From nnorwitz at gmail.com Sun May 1 01:17:19 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Sat, 30 Apr 2011 19:17:19 -0400 Subject: [Python-checkins] Python Regression Test Failures all (1) Message-ID: <20110430231719.GA19748@kbk-i386-bb.dyndns.org> 352 tests OK. 1 test failed: test_bsddb3 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:88828M, Apr 30 2011, 16:01:38) [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_12464 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-12464 test test_bsddb3 failed -- multiple errors occurred; run in verbose mode for details Sleepycat Software: Berkeley DB 4.1.25: (December 19, 2002) Test path prefix: /tmp/z-test_bsddb3-12464 Re-running test 'test_bsddb3' in verbose mode test00_associateDBError (bsddb.test.test_associate.AssociateErrorTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.AssociateHashTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.AssociateHashTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.AssociateBTreeTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.AssociateBTreeTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.AssociateRecnoTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.AssociateRecnoTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.AssociateBTreeTxnTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.AssociateBTreeTxnTestCase) ... ERROR test13_associate_in_transaction (bsddb.test.test_associate.AssociateBTreeTxnTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.ShelveAssociateHashTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.ShelveAssociateHashTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.ShelveAssociateBTreeTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.ShelveAssociateBTreeTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.ShelveAssociateRecnoTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.ShelveAssociateRecnoTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.ThreadedAssociateHashTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.ThreadedAssociateHashTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.ThreadedAssociateBTreeTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.ThreadedAssociateBTreeTestCase) ... ERROR test01_associateWithDB (bsddb.test.test_associate.ThreadedAssociateRecnoTestCase) ... ERROR test02_associateAfterDB (bsddb.test.test_associate.ThreadedAssociateRecnoTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test00_version (bsddb.test.test_basics.VersionTestCase) ... ok test01_GetsAndPuts (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BasicBTreeTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BasicHashTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test09_EnvRemoveAndRename (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test09_EnvRemoveAndRename (bsddb.test.test_basics.BasicHashWithEnvTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test06_Transactions (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test09_TxnTruncate (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test10_TxnLateUse (bsddb.test.test_basics.BTreeTransactionTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test06_Transactions (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test07_verify (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test09_TxnTruncate (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test10_TxnLateUse (bsddb.test.test_basics.HashTransactionTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test09_RecnoInBTree (bsddb.test.test_basics.BTreeRecnoTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test09_RecnoInBTree (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test10_DuplicateKeys (bsddb.test.test_basics.BTreeDUPTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test07_verify (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test10_DuplicateKeys (bsddb.test.test_basics.HashDUPTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test10_DuplicateKeys (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test07_verify (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test10_DuplicateKeys (bsddb.test.test_basics.HashDUPWithThreadTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test07_verify (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test11_MultiDB (bsddb.test.test_basics.BTreeMultiDBTestCase) ... ERROR test01_GetsAndPuts (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test02_DictionaryMethods (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test02b_SequenceMethods (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test03_SimpleCursorStuff (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test04_PartialGetAndPut (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test05_GetSize (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test06_Truncate (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test07_verify (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test11_MultiDB (bsddb.test.test_basics.HashMultiDBTestCase) ... ERROR test01_DefaultIsNone (bsddb.test.test_basics.DBEnvPrivateObject) ... ok test02_assignment (bsddb.test.test_basics.DBEnvPrivateObject) ... ok test03_leak_assignment (bsddb.test.test_basics.DBEnvPrivateObject) ... ok test04_leak_GC (bsddb.test.test_basics.DBEnvPrivateObject) ... ok test01_DefaultIsNone (bsddb.test.test_basics.DBPrivateObject) ... ok test02_assignment (bsddb.test.test_basics.DBPrivateObject) ... ok test03_leak_assignment (bsddb.test.test_basics.DBPrivateObject) ... ok test04_leak_GC (bsddb.test.test_basics.DBPrivateObject) ... ok test02_DBEnv_dealloc (bsddb.test.test_basics.CrashAndBurn) ... ok testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test_memp_1_trickle (bsddb.test.test_dbenv.DBEnv_memp) ... ERROR test_memp_2_sync (bsddb.test.test_dbenv.DBEnv_memp) ... ERROR test_memp_stat_1 (bsddb.test.test_dbenv.DBEnv_memp) ... ERROR test_memp_stat_2 (bsddb.test.test_dbenv.DBEnv_memp) ... ERROR test_1_first (bsddb.test.test_dbenv.DBEnv_logcursor) ... ERROR test_2_last (bsddb.test.test_dbenv.DBEnv_logcursor) ... ERROR test_3_next (bsddb.test.test_dbenv.DBEnv_logcursor) ... ERROR test_4_prev (bsddb.test.test_dbenv.DBEnv_logcursor) ... ERROR test_5_current (bsddb.test.test_dbenv.DBEnv_logcursor) ... ERROR test_6_set (bsddb.test.test_dbenv.DBEnv_logcursor) ... ERROR test_explicit_close (bsddb.test.test_dbenv.DBEnv_logcursor) ... ERROR test_implicit_close (bsddb.test.test_dbenv.DBEnv_logcursor) ... ERROR test_log_file (bsddb.test.test_dbenv.DBEnv_log) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test_lexical_comparator (bsddb.test.test_compare.ComparatorTests) ... ok test_lowercase_comparator (bsddb.test.test_compare.ComparatorTests) ... ok test_reverse_lexical_comparator (bsddb.test.test_compare.ComparatorTests) ... ok test_cannot_assign_twice (bsddb.test.test_compare.BtreeExceptionsTestCase) ... ERROR test_compare_function_bad_return (bsddb.test.test_compare.BtreeExceptionsTestCase) ... ERROR test_compare_function_exception (bsddb.test.test_compare.BtreeExceptionsTestCase) ... ERROR test_compare_function_incorrect (bsddb.test.test_compare.BtreeExceptionsTestCase) ... ERROR test_raises_non_callable (bsddb.test.test_compare.BtreeExceptionsTestCase) ... ERROR test_set_bt_compare_with_function (bsddb.test.test_compare.BtreeExceptionsTestCase) ... ERROR test_compare_function_useless (bsddb.test.test_compare.BtreeKeyCompareTestCase) ... ERROR test_lexical_ordering (bsddb.test.test_compare.BtreeKeyCompareTestCase) ... ERROR test_reverse_lexical_ordering (bsddb.test.test_compare.BtreeKeyCompareTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_btopen (bsddb.test.test_compat.CompatibilityTestCase) ... ERROR test02_hashopen (bsddb.test.test_compat.CompatibilityTestCase) ... ERROR test03_rnopen (bsddb.test.test_compat.CompatibilityTestCase) ... ERROR test04_n_flag (bsddb.test.test_compat.CompatibilityTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test_pget (bsddb.test.test_cursor_pget_bug.pget_bugTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_both (bsddb.test.test_dbobj.dbobjTestCase) ... ERROR test02_dbobj_dict_interface (bsddb.test.test_dbobj.dbobjTestCase) ... ERROR test03_dbobj_type_before_open (bsddb.test.test_dbobj.dbobjTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_basics (bsddb.test.test_dbshelve.DBShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.DBShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.DBShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.DBShelveTestCase) ... ERROR test01_basics (bsddb.test.test_dbshelve.BTreeShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.BTreeShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.BTreeShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.BTreeShelveTestCase) ... ERROR test01_basics (bsddb.test.test_dbshelve.HashShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.HashShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.HashShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.HashShelveTestCase) ... ERROR test01_basics (bsddb.test.test_dbshelve.ThreadBTreeShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.ThreadBTreeShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.ThreadBTreeShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.ThreadBTreeShelveTestCase) ... ERROR test01_basics (bsddb.test.test_dbshelve.ThreadHashShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.ThreadHashShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.ThreadHashShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.ThreadHashShelveTestCase) ... ERROR test01_basics (bsddb.test.test_dbshelve.EnvBTreeShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.EnvBTreeShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.EnvBTreeShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.EnvBTreeShelveTestCase) ... ERROR test01_basics (bsddb.test.test_dbshelve.EnvHashShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.EnvHashShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.EnvHashShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.EnvHashShelveTestCase) ... ERROR test01_basics (bsddb.test.test_dbshelve.EnvThreadBTreeShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.EnvThreadBTreeShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.EnvThreadBTreeShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.EnvThreadBTreeShelveTestCase) ... ERROR test01_basics (bsddb.test.test_dbshelve.EnvThreadHashShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.EnvThreadHashShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.EnvThreadHashShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.EnvThreadHashShelveTestCase) ... ERROR test01_basics (bsddb.test.test_dbshelve.RecNoShelveTestCase) ... ERROR test02_cursors (bsddb.test.test_dbshelve.RecNoShelveTestCase) ... ERROR test03_append (bsddb.test.test_dbshelve.RecNoShelveTestCase) ... ERROR test04_iterable (bsddb.test.test_dbshelve.RecNoShelveTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01 (bsddb.test.test_dbtables.TableDBTestCase) ... ERROR test02 (bsddb.test.test_dbtables.TableDBTestCase) ... ERROR test03 (bsddb.test.test_dbtables.TableDBTestCase) ... ERROR test04_MultiCondSelect (bsddb.test.test_dbtables.TableDBTestCase) ... ERROR test_CondObjs (bsddb.test.test_dbtables.TableDBTestCase) ... ERROR test_CreateOrExtend (bsddb.test.test_dbtables.TableDBTestCase) ... ERROR test_Delete (bsddb.test.test_dbtables.TableDBTestCase) ... ERROR test_Modify (bsddb.test.test_dbtables.TableDBTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_close_dbenv_before_db (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ... ERROR test02_close_dbenv_before_dbcursor (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ... ERROR test03_close_db_before_dbcursor_without_env (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ... ERROR test04_close_massive (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ... ERROR test05_close_dbenv_delete_db_success (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ... ERROR test06_close_txn_before_dup_cursor (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_get_returns_none (bsddb.test.test_get_none.GetReturnsNoneTestCase) ... ERROR test02_get_raises_exception (bsddb.test.test_get_none.GetReturnsNoneTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_join (bsddb.test.test_join.JoinTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_simple (bsddb.test.test_lock.LockingTestCase) ... ERROR test02_threaded (bsddb.test.test_lock.LockingTestCase) ... ERROR test04_lock_timeout2 (bsddb.test.test_lock.LockingTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_badpointer (bsddb.test.test_misc.MiscTestCase) ... ERROR test02_db_home (bsddb.test.test_misc.MiscTestCase) ... ERROR test03_repr_closed_db (bsddb.test.test_misc.MiscTestCase) ... ERROR test04_repr_db (bsddb.test.test_misc.MiscTestCase) ... ERROR test05_double_free_make_key_dbt (bsddb.test.test_misc.MiscTestCase) ... ERROR test06_key_with_null_bytes (bsddb.test.test_misc.MiscTestCase) ... ERROR test07_DB_set_flags_persists (bsddb.test.test_misc.MiscTestCase) ... ERROR test08_ExceptionTypes (bsddb.test.test_misc.MiscTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_pickle_DBError (bsddb.test.test_pickle.pickleTestCase) ... ERROR test02_cPickle_DBError (bsddb.test.test_pickle.pickleTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_basic (bsddb.test.test_queue.SimpleQueueTestCase) ... ERROR test02_basicPost32 (bsddb.test.test_queue.SimpleQueueTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_basic (bsddb.test.test_recno.SimpleRecnoTestCase) ... ERROR test02_WithSource (bsddb.test.test_recno.SimpleRecnoTestCase) ... ERROR test03_FixedLength (bsddb.test.test_recno.SimpleRecnoTestCase) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok test01_1WriterMultiReaders (bsddb.test.test_thread.BTreeConcurrentDataStore) ... ERROR test01_1WriterMultiReaders (bsddb.test.test_thread.HashConcurrentDataStore) ... ERROR test02_SimpleLocks (bsddb.test.test_thread.BTreeSimpleThreaded) ... ERROR test02_SimpleLocks (bsddb.test.test_thread.HashSimpleThreaded) ... ERROR test03_ThreadedTransactions (bsddb.test.test_thread.BTreeThreadedTransactions) ... ERROR test03_ThreadedTransactions (bsddb.test.test_thread.HashThreadedTransactions) ... ERROR test03_ThreadedTransactions (bsddb.test.test_thread.BTreeThreadedNoWaitTransactions) ... ERROR test03_ThreadedTransactions (bsddb.test.test_thread.HashThreadedNoWaitTransactions) ... ERROR testCheckElapsedTime (test.test_bsddb3.TimingCheck) ... ok ====================================================================== ERROR: test00_associateDBError (bsddb.test.test_associate.AssociateErrorTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 81, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_336' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.AssociateHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_337' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.AssociateHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_338' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.AssociateBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_339' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.AssociateBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_340' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.AssociateRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_341' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.AssociateRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_342' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.AssociateBTreeTxnTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_343' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.AssociateBTreeTxnTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_344' ====================================================================== ERROR: test13_associate_in_transaction (bsddb.test.test_associate.AssociateBTreeTxnTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_345' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.ShelveAssociateHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_346' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.ShelveAssociateHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_347' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.ShelveAssociateBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_348' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.ShelveAssociateBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_349' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.ShelveAssociateRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_350' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.ShelveAssociateRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_351' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.ThreadedAssociateHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_352' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.ThreadedAssociateHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_353' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.ThreadedAssociateBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_354' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.ThreadedAssociateBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_355' ====================================================================== ERROR: test01_associateWithDB (bsddb.test.test_associate.ThreadedAssociateRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_356' ====================================================================== ERROR: test02_associateAfterDB (bsddb.test.test_associate.ThreadedAssociateRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_associate.py", line 129, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_357' ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BasicBTreeTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BasicHashTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BasicBTreeWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BasicHashWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_402' ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_403' ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_404' ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_405' ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_406' ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_407' ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_408' ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_409' ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_410' ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_411' ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_412' ====================================================================== ERROR: test09_EnvRemoveAndRename (bsddb.test.test_basics.BasicBTreeWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_413' ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_414' ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_415' ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_416' ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_417' ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_418' ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_419' ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_420' ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_421' ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_422' ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_423' ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_424' ====================================================================== ERROR: test09_EnvRemoveAndRename (bsddb.test.test_basics.BasicHashWithEnvTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_425' ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_426' ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_427' ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_428' ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_429' ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_430' ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_431' ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_432' ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_433' ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_434' ====================================================================== ERROR: test06_Transactions (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_435' ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_436' ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_437' ====================================================================== ERROR: test09_TxnTruncate (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_438' ====================================================================== ERROR: test10_TxnLateUse (bsddb.test.test_basics.BTreeTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_439' ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_440' ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_441' ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_442' ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_443' ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_444' ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_445' ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_446' ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_447' ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_448' ====================================================================== ERROR: test06_Transactions (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_449' ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_450' ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_451' ====================================================================== ERROR: test09_TxnTruncate (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_452' ====================================================================== ERROR: test10_TxnLateUse (bsddb.test.test_basics.HashTransactionTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_453' ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test09_RecnoInBTree (bsddb.test.test_basics.BTreeRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test09_RecnoInBTree (bsddb.test.test_basics.BTreeRecnoWithThreadFlagTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test10_DuplicateKeys (bsddb.test.test_basics.BTreeDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test10_DuplicateKeys (bsddb.test.test_basics.HashDUPTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test10_DuplicateKeys (bsddb.test.test_basics.BTreeDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test10_DuplicateKeys (bsddb.test.test_basics.HashDUPWithThreadTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 93, in setUp flags = self.dbopenflags|db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_526' ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_527' ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_528' ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_529' ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_530' ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_531' ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_532' ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_533' ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_534' ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_535' ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_536' ====================================================================== ERROR: test11_MultiDB (bsddb.test.test_basics.BTreeMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_537' ====================================================================== ERROR: test01_GetsAndPuts (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_538' ====================================================================== ERROR: test02_DictionaryMethods (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_539' ====================================================================== ERROR: test02b_SequenceMethods (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_540' ====================================================================== ERROR: test03_SimpleCursorStuff (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_541' ====================================================================== ERROR: test03b_SimpleCursorWithGetReturnsNone1 (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_542' ====================================================================== ERROR: test03b_SimpleCursorWithoutGetReturnsNone0 (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_543' ====================================================================== ERROR: test03c_SimpleCursorGetReturnsNone2 (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_544' ====================================================================== ERROR: test04_PartialGetAndPut (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_545' ====================================================================== ERROR: test05_GetSize (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_546' ====================================================================== ERROR: test06_Truncate (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_547' ====================================================================== ERROR: test07_verify (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_548' ====================================================================== ERROR: test11_MultiDB (bsddb.test.test_basics.HashMultiDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_basics.py", line 56, in setUp self.homeDir=get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_549' ====================================================================== ERROR: test_memp_1_trickle (bsddb.test.test_dbenv.DBEnv_memp) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 351, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_550' ====================================================================== ERROR: test_memp_2_sync (bsddb.test.test_dbenv.DBEnv_memp) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 351, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_551' ====================================================================== ERROR: test_memp_stat_1 (bsddb.test.test_dbenv.DBEnv_memp) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 351, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_552' ====================================================================== ERROR: test_memp_stat_2 (bsddb.test.test_dbenv.DBEnv_memp) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 351, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_553' ====================================================================== ERROR: test_1_first (bsddb.test.test_dbenv.DBEnv_logcursor) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 399, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_554' ====================================================================== ERROR: test_2_last (bsddb.test.test_dbenv.DBEnv_logcursor) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 399, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_555' ====================================================================== ERROR: test_3_next (bsddb.test.test_dbenv.DBEnv_logcursor) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 399, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_556' ====================================================================== ERROR: test_4_prev (bsddb.test.test_dbenv.DBEnv_logcursor) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 399, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_557' ====================================================================== ERROR: test_5_current (bsddb.test.test_dbenv.DBEnv_logcursor) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 399, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_558' ====================================================================== ERROR: test_6_set (bsddb.test.test_dbenv.DBEnv_logcursor) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 399, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_559' ====================================================================== ERROR: test_explicit_close (bsddb.test.test_dbenv.DBEnv_logcursor) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 399, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_560' ====================================================================== ERROR: test_implicit_close (bsddb.test.test_dbenv.DBEnv_logcursor) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 399, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_561' ====================================================================== ERROR: test_log_file (bsddb.test.test_dbenv.DBEnv_log) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 277, in setUp DBEnv.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbenv.py", line 19, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_562' ====================================================================== ERROR: test_cannot_assign_twice (bsddb.test.test_compare.BtreeExceptionsTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compare.py", line 89, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_563' ====================================================================== ERROR: test_compare_function_bad_return (bsddb.test.test_compare.BtreeExceptionsTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compare.py", line 89, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_564' ====================================================================== ERROR: test_compare_function_exception (bsddb.test.test_compare.BtreeExceptionsTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compare.py", line 89, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_565' ====================================================================== ERROR: test_compare_function_incorrect (bsddb.test.test_compare.BtreeExceptionsTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compare.py", line 89, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_566' ====================================================================== ERROR: test_raises_non_callable (bsddb.test.test_compare.BtreeExceptionsTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compare.py", line 89, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_567' ====================================================================== ERROR: test_set_bt_compare_with_function (bsddb.test.test_compare.BtreeExceptionsTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compare.py", line 89, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_568' ====================================================================== ERROR: test_compare_function_useless (bsddb.test.test_compare.BtreeKeyCompareTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compare.py", line 89, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_569' ====================================================================== ERROR: test_lexical_ordering (bsddb.test.test_compare.BtreeKeyCompareTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compare.py", line 89, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_570' ====================================================================== ERROR: test_reverse_lexical_ordering (bsddb.test.test_compare.BtreeKeyCompareTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compare.py", line 89, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_571' ====================================================================== ERROR: test01_btopen (bsddb.test.test_compat.CompatibilityTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compat.py", line 25, in test01_btopen self.do_bthash_test(btopen, 'btopen') File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compat.py", line 87, in do_bthash_test f = factory(self.filename, 'c') File "/tmp/python-test/local/lib/python2.7/bsddb/__init__.py", line 381, in btopen d.open(file, db.DB_BTREE, flags, mode) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_hashopen (bsddb.test.test_compat.CompatibilityTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compat.py", line 28, in test02_hashopen self.do_bthash_test(hashopen, 'hashopen') File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compat.py", line 87, in do_bthash_test f = factory(self.filename, 'c') File "/tmp/python-test/local/lib/python2.7/bsddb/__init__.py", line 364, in hashopen d.open(file, db.DB_HASH, flags, mode) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_rnopen (bsddb.test.test_compat.CompatibilityTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compat.py", line 35, in test03_rnopen f = rnopen(self.filename, 'c') File "/tmp/python-test/local/lib/python2.7/bsddb/__init__.py", line 401, in rnopen d.open(file, db.DB_RECNO, flags, mode) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_n_flag (bsddb.test.test_compat.CompatibilityTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_compat.py", line 79, in test04_n_flag f = hashopen(self.filename, 'n') File "/tmp/python-test/local/lib/python2.7/bsddb/__init__.py", line 364, in hashopen d.open(file, db.DB_HASH, flags, mode) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test_pget (bsddb.test.test_cursor_pget_bug.pget_bugTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_cursor_pget_bug.py", line 14, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_576' ====================================================================== ERROR: test01_both (bsddb.test.test_dbobj.dbobjTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbobj.py", line 15, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_577' ====================================================================== ERROR: test02_dbobj_dict_interface (bsddb.test.test_dbobj.dbobjTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbobj.py", line 15, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_578' ====================================================================== ERROR: test03_dbobj_type_before_open (bsddb.test.test_dbobj.dbobjTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbobj.py", line 15, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_579' ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.DBShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 83, in do_open self.d = dbshelve.open(self.filename) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 131, in open d.open(filename, dbname, filetype, flags, mode) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.DBShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 83, in do_open self.d = dbshelve.open(self.filename) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 131, in open d.open(filename, dbname, filetype, flags, mode) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.DBShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 83, in do_open self.d = dbshelve.open(self.filename) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 131, in open d.open(filename, dbname, filetype, flags, mode) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.DBShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 83, in do_open self.d = dbshelve.open(self.filename) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 131, in open d.open(filename, dbname, filetype, flags, mode) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.BTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.BTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.BTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.BTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.HashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.HashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.HashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.HashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.ThreadBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.ThreadBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.ThreadBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.ThreadBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.ThreadHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.ThreadHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.ThreadHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.ThreadHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.EnvBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_600' ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.EnvBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_601' ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.EnvBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_602' ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.EnvBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_603' ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.EnvHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_604' ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.EnvHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_605' ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.EnvHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_606' ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.EnvHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_607' ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.EnvThreadBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_608' ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.EnvThreadBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_609' ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.EnvThreadBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_610' ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.EnvThreadBTreeShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_611' ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.EnvThreadHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_612' ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.EnvThreadHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_613' ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.EnvThreadHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_614' ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.EnvThreadHashShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 310, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_615' ====================================================================== ERROR: test01_basics (bsddb.test.test_dbshelve.RecNoShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 353, in setUp BasicShelveTestCase.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_cursors (bsddb.test.test_dbshelve.RecNoShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 353, in setUp BasicShelveTestCase.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test03_append (bsddb.test.test_dbshelve.RecNoShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 353, in setUp BasicShelveTestCase.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test04_iterable (bsddb.test.test_dbshelve.RecNoShelveTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 353, in setUp BasicShelveTestCase.setUp(self) File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 51, in setUp self.do_open() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbshelve.py", line 265, in do_open self.d.open(self.filename, self.dbtype, self.dbflags) File "/tmp/python-test/local/lib/python2.7/bsddb/dbshelve.py", line 203, in open self.db.open(*args, **kwargs) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01 (bsddb.test.test_dbtables.TableDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbtables.py", line 49, in setUp self.testHomeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_620' ====================================================================== ERROR: test02 (bsddb.test.test_dbtables.TableDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbtables.py", line 49, in setUp self.testHomeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_621' ====================================================================== ERROR: test03 (bsddb.test.test_dbtables.TableDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbtables.py", line 49, in setUp self.testHomeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_622' ====================================================================== ERROR: test04_MultiCondSelect (bsddb.test.test_dbtables.TableDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbtables.py", line 49, in setUp self.testHomeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_623' ====================================================================== ERROR: test_CondObjs (bsddb.test.test_dbtables.TableDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbtables.py", line 49, in setUp self.testHomeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_624' ====================================================================== ERROR: test_CreateOrExtend (bsddb.test.test_dbtables.TableDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbtables.py", line 49, in setUp self.testHomeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_625' ====================================================================== ERROR: test_Delete (bsddb.test.test_dbtables.TableDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbtables.py", line 49, in setUp self.testHomeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_626' ====================================================================== ERROR: test_Modify (bsddb.test.test_dbtables.TableDBTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_dbtables.py", line 49, in setUp self.testHomeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_627' ====================================================================== ERROR: test01_close_dbenv_before_db (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_early_close.py", line 26, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_628' ====================================================================== ERROR: test02_close_dbenv_before_dbcursor (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_early_close.py", line 26, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_629' ====================================================================== ERROR: test03_close_db_before_dbcursor_without_env (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_early_close.py", line 26, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_630' ====================================================================== ERROR: test04_close_massive (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_early_close.py", line 26, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_631' ====================================================================== ERROR: test05_close_dbenv_delete_db_success (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_early_close.py", line 26, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_632' ====================================================================== ERROR: test06_close_txn_before_dup_cursor (bsddb.test.test_early_close.DBEnvClosedEarlyCrash) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_early_close.py", line 26, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_633' ====================================================================== ERROR: test01_get_returns_none (bsddb.test.test_get_none.GetReturnsNoneTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_get_none.py", line 26, in test01_get_returns_none d.open(self.filename, db.DB_BTREE, db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_get_raises_exception (bsddb.test.test_get_none.GetReturnsNoneTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_get_none.py", line 54, in test02_get_raises_exception d.open(self.filename, db.DB_BTREE, db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_join (bsddb.test.test_join.JoinTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_join.py", line 37, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_636' ====================================================================== ERROR: test01_simple (bsddb.test.test_lock.LockingTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_lock.py", line 29, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_637' ====================================================================== ERROR: test02_threaded (bsddb.test.test_lock.LockingTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_lock.py", line 29, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_638' ====================================================================== ERROR: test04_lock_timeout2 (bsddb.test.test_lock.LockingTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_lock.py", line 29, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_639' ====================================================================== ERROR: test01_badpointer (bsddb.test.test_misc.MiscTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_misc.py", line 21, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_641' ====================================================================== ERROR: test02_db_home (bsddb.test.test_misc.MiscTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_misc.py", line 21, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_643' ====================================================================== ERROR: test03_repr_closed_db (bsddb.test.test_misc.MiscTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_misc.py", line 21, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_645' ====================================================================== ERROR: test04_repr_db (bsddb.test.test_misc.MiscTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_misc.py", line 21, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_647' ====================================================================== ERROR: test05_double_free_make_key_dbt (bsddb.test.test_misc.MiscTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_misc.py", line 21, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_649' ====================================================================== ERROR: test06_key_with_null_bytes (bsddb.test.test_misc.MiscTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_misc.py", line 21, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_651' ====================================================================== ERROR: test07_DB_set_flags_persists (bsddb.test.test_misc.MiscTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_misc.py", line 21, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_653' ====================================================================== ERROR: test08_ExceptionTypes (bsddb.test.test_misc.MiscTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_misc.py", line 21, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_655' ====================================================================== ERROR: test01_pickle_DBError (bsddb.test.test_pickle.pickleTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_pickle.py", line 25, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_656' ====================================================================== ERROR: test02_cPickle_DBError (bsddb.test.test_pickle.pickleTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_pickle.py", line 25, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_657' ====================================================================== ERROR: test01_basic (bsddb.test.test_queue.SimpleQueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_queue.py", line 33, in test01_basic d.open(self.filename, db.DB_QUEUE, db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_basicPost32 (bsddb.test.test_queue.SimpleQueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_queue.py", line 109, in test02_basicPost32 d.open(self.filename, db.DB_QUEUE, db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_basic (bsddb.test.test_recno.SimpleRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_recno.py", line 46, in test01_basic d.open(self.filename, db.DB_RECNO, db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test02_WithSource (bsddb.test.test_recno.SimpleRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_recno.py", line 217, in test02_WithSource homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_662' ====================================================================== ERROR: test03_FixedLength (bsddb.test.test_recno.SimpleRecnoTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_recno.py", line 273, in test03_FixedLength d.open(self.filename, db.DB_RECNO, db.DB_CREATE) DBAccessError: (13, 'Permission denied') ====================================================================== ERROR: test01_1WriterMultiReaders (bsddb.test.test_thread.BTreeConcurrentDataStore) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_thread.py", line 46, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_664' ====================================================================== ERROR: test01_1WriterMultiReaders (bsddb.test.test_thread.HashConcurrentDataStore) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_thread.py", line 46, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_665' ====================================================================== ERROR: test02_SimpleLocks (bsddb.test.test_thread.BTreeSimpleThreaded) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_thread.py", line 46, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_666' ====================================================================== ERROR: test02_SimpleLocks (bsddb.test.test_thread.HashSimpleThreaded) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_thread.py", line 46, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_667' ====================================================================== ERROR: test03_ThreadedTransactions (bsddb.test.test_thread.BTreeThreadedTransactions) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_thread.py", line 46, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_668' ====================================================================== ERROR: test03_ThreadedTransactions (bsddb.test.test_thread.HashThreadedTransactions) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_thread.py", line 46, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_669' ====================================================================== ERROR: test03_ThreadedTransactions (bsddb.test.test_thread.BTreeThreadedNoWaitTransactions) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_thread.py", line 46, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_670' ====================================================================== ERROR: test03_ThreadedTransactions (bsddb.test.test_thread.HashThreadedNoWaitTransactions) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_thread.py", line 46, in setUp self.homeDir = get_new_environment_path() File "/tmp/python-test/local/lib/python2.7/bsddb/test/test_all.py", line 517, in get_new_environment_path test_support.rmtree(path) File "/tmp/python-test/local/lib/python2.7/test/test_support.py", line 189, in rmtree shutil.rmtree(path) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 236, in rmtree onerror(os.listdir, path, sys.exc_info()) File "/tmp/python-test/local/lib/python2.7/shutil.py", line 234, in rmtree names = os.listdir(path) OSError: [Errno 13] Permission denied: '/tmp/z-test_bsddb3-12464/environment_12464_671' ---------------------------------------------------------------------- Ran 363 tests in 0.303s FAILED (errors=327) test test_bsddb3 failed -- multiple errors occurred 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_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_bsddb3 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 [985034 refs] From python-checkins at python.org Sun May 1 01:23:06 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 01 May 2011 01:23:06 +0200 Subject: [Python-checkins] cpython: Close #11958: Fix FTP tests for IPv6, bind to "::1" instead of "localhost". Message-ID: http://hg.python.org/cpython/rev/e680564efa8c changeset: 69731:e680564efa8c user: Victor Stinner date: Sun May 01 01:23:03 2011 +0200 summary: Close #11958: Fix FTP tests for IPv6, bind to "::1" instead of "localhost". Patch written by Charles-Francois Natali. files: Lib/test/test_ftplib.py | 9 ++------- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -648,7 +648,7 @@ class TestIPv6Environment(TestCase): def setUp(self): - self.server = DummyFTPServer((HOST, 0), af=socket.AF_INET6) + self.server = DummyFTPServer(('::1', 0), af=socket.AF_INET6) self.server.start() self.client = ftplib.FTP() self.client.connect(self.server.host, self.server.port) @@ -874,12 +874,7 @@ def test_main(): tests = [TestFTPClass, TestTimeouts] if support.IPV6_ENABLED: - try: - DummyFTPServer((HOST, 0), af=socket.AF_INET6) - except socket.error: - pass - else: - tests.append(TestIPv6Environment) + tests.append(TestIPv6Environment) if ssl is not None: tests.extend([TestTLS_FTPClassMixin, TestTLS_FTPClass]) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -534,6 +534,9 @@ Tests ----- +- Issue #11958: Fix FTP tests for IPv6, bind to "::1" instead of "localhost". + Patch written by Charles-Francois Natali. + - Issue #8407, #11859: Fix tests of test_io using threads and an alarm: use pthread_sigmask() to ensure that the SIGALRM signal is received by the main thread. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun May 1 04:59:02 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 01 May 2011 04:59:02 +0200 Subject: [Python-checkins] Daily reference leaks (e680564efa8c): sum=0 Message-ID: results for e680564efa8c on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogFLeozJ', '-x'] From nnorwitz at gmail.com Sun May 1 10:00:12 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Sun, 1 May 2011 04:00:12 -0400 Subject: [Python-checkins] Python Regression Test Failures doc (1) Message-ID: <20110501080012.GA21459@kbk-i386-bb.dyndns.org> rm -rf build/* rm -rf tools/sphinx rm -rf tools/pygments rm -rf tools/jinja2 rm -rf tools/docutils Checking out Sphinx... svn: PROPFIND request failed on '/projects/external/Sphinx-0.6.5/sphinx' svn: PROPFIND of '/projects/external/Sphinx-0.6.5/sphinx': could not connect to server (http://svn.python.org) make: *** [checkout] Error 1 From python-checkins at python.org Sun May 1 16:52:03 2011 From: python-checkins at python.org (alexis.metaireau) Date: Sun, 01 May 2011 16:52:03 +0200 Subject: [Python-checkins] peps: PEP 345: platform.python_implementation is now an authorised environment marker. Message-ID: http://hg.python.org/peps/rev/a09a267ab612 changeset: 3871:a09a267ab612 user: Alexis Metaireau date: Sun May 01 15:51:51 2011 +0100 summary: PEP 345: platform.python_implementation is now an authorised environment marker. This allows to target some specific python implementations (such as cpython/pypy/jython) when describing PEP 345 fields files: pep-0345.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/pep-0345.txt b/pep-0345.txt --- a/pep-0345.txt +++ b/pep-0345.txt @@ -483,6 +483,7 @@ - sys.platform = sys.platform - platform.version = platform.version() - platform.machine = platform.machine() +- platform.python_implementation = platform.python_implementation() - a free string, like ``'2.4'``, or ``'win32'`` Notice that ``in`` is restricted to strings, meaning that it is not possible -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun May 1 17:15:24 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 01 May 2011 17:15:24 +0200 Subject: [Python-checkins] cpython (2.7): #11971: fix man page; it's -OO not -O0 Message-ID: http://hg.python.org/cpython/rev/d70b0137902b changeset: 69732:d70b0137902b branch: 2.7 parent: 69727:a9cb47d0241e user: R David Murray date: Sun May 01 11:12:35 2011 -0400 summary: #11971: fix man page; it's -OO not -O0 Patch by Lars Michelsen. files: Misc/python.man | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/python.man b/Misc/python.man --- a/Misc/python.man +++ b/Misc/python.man @@ -31,7 +31,7 @@ .B \-O ] [ -.B \-O0 +.B \-OO ] [ .B -Q @@ -148,7 +148,7 @@ .I .pyc to \fI.pyo\fP. Given twice, causes docstrings to be discarded. .TP -.B \-O0 +.B \-OO Discard docstrings in addition to the \fB-O\fP optimizations. .TP .BI "\-Q " argument -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 17:15:27 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 01 May 2011 17:15:27 +0200 Subject: [Python-checkins] cpython (3.1): #11971: fix man page; it's -OO not -O0 Message-ID: http://hg.python.org/cpython/rev/c57fdce01eb8 changeset: 69733:c57fdce01eb8 branch: 3.1 parent: 69728:00ff8825f551 user: R David Murray date: Sun May 01 11:13:56 2011 -0400 summary: #11971: fix man page; it's -OO not -O0 Patch by Lars Michelsen. files: Misc/python.man | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/python.man b/Misc/python.man --- a/Misc/python.man +++ b/Misc/python.man @@ -31,7 +31,7 @@ .B \-O ] [ -.B \-O0 +.B \-OO ] [ .B -Q @@ -142,7 +142,7 @@ .I .pyc to \fI.pyo\fP. Given twice, causes docstrings to be discarded. .TP -.B \-O0 +.B \-OO Discard docstrings in addition to the \fB-O\fP optimizations. .TP .BI "\-Q " argument -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 17:15:28 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 01 May 2011 17:15:28 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge #11971: fix man page; it's -OO not -O0 Message-ID: http://hg.python.org/cpython/rev/bbc6129f7861 changeset: 69734:bbc6129f7861 branch: 3.2 parent: 69729:0f14dd4e644e parent: 69733:c57fdce01eb8 user: R David Murray date: Sun May 01 11:14:31 2011 -0400 summary: Merge #11971: fix man page; it's -OO not -O0 Patch by Lars Michelsen. files: Misc/python.man | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/python.man b/Misc/python.man --- a/Misc/python.man +++ b/Misc/python.man @@ -34,7 +34,7 @@ .B \-O ] [ -.B \-O0 +.B \-OO ] [ .B -Q @@ -145,7 +145,7 @@ .I .pyc to \fI.pyo\fP. Given twice, causes docstrings to be discarded. .TP -.B \-O0 +.B \-OO Discard docstrings in addition to the \fB-O\fP optimizations. .TP .B \-q -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 17:15:35 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 01 May 2011 17:15:35 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #11971: fix man page; it's -OO not -O0 Message-ID: http://hg.python.org/cpython/rev/e2f71bc9b0db changeset: 69735:e2f71bc9b0db parent: 69731:e680564efa8c parent: 69734:bbc6129f7861 user: R David Murray date: Sun May 01 11:15:01 2011 -0400 summary: Merge #11971: fix man page; it's -OO not -O0 Patch by Lars Michelsen. files: Misc/python.man | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/python.man b/Misc/python.man --- a/Misc/python.man +++ b/Misc/python.man @@ -34,7 +34,7 @@ .B \-O ] [ -.B \-O0 +.B \-OO ] [ .B \-s @@ -141,7 +141,7 @@ .I .pyc to \fI.pyo\fP. Given twice, causes docstrings to be discarded. .TP -.B \-O0 +.B \-OO Discard docstrings in addition to the \fB-O\fP optimizations. .TP .B \-q -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 22:37:59 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 May 2011 22:37:59 +0200 Subject: [Python-checkins] cpython: Split combined code/doctest code blocks in two blocks, to enable proper Message-ID: http://hg.python.org/cpython/rev/b9e04043568e changeset: 69736:b9e04043568e user: Georg Brandl date: Sun May 01 22:34:31 2011 +0200 summary: Split combined code/doctest code blocks in two blocks, to enable proper highlighting. files: Doc/tutorial/classes.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -754,6 +754,8 @@ self.index = self.index - 1 return self.data[self.index] +:: + >>> rev = Reverse('spam') >>> iter(rev) <__main__.Reverse object at 0x00A1DB50> @@ -782,6 +784,8 @@ for index in range(len(data)-1, -1, -1): yield data[index] +:: + >>> for char in reverse('golf'): ... print(char) ... -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 22:37:59 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 May 2011 22:37:59 +0200 Subject: [Python-checkins] cpython (2.7): Split combined code/doctest code blocks in two blocks, to enable proper Message-ID: http://hg.python.org/cpython/rev/3d0a41407abf changeset: 69737:3d0a41407abf branch: 2.7 parent: 69732:d70b0137902b user: Georg Brandl date: Sun May 01 22:36:31 2011 +0200 summary: Split combined code/doctest code blocks in two blocks, to enable proper highlighting. files: Doc/tutorial/classes.rst | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -687,7 +687,6 @@ >>> it.next() 'c' >>> it.next() - Traceback (most recent call last): File "", line 1, in ? it.next() @@ -699,7 +698,7 @@ :meth:`next`, then :meth:`__iter__` can just return ``self``:: class Reverse: - "Iterator for looping over a sequence backwards" + """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data = data self.index = len(data) @@ -711,6 +710,8 @@ self.index = self.index - 1 return self.data[self.index] +:: + >>> rev = Reverse('spam') >>> iter(rev) <__main__.Reverse object at 0x00A1DB50> @@ -739,6 +740,8 @@ for index in range(len(data)-1, -1, -1): yield data[index] +:: + >>> for char in reverse('golf'): ... print char ... -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 22:38:00 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 May 2011 22:38:00 +0200 Subject: [Python-checkins] cpython (3.2): Split combined code/doctest code blocks in two blocks, to enable proper Message-ID: http://hg.python.org/cpython/rev/13878873ccc7 changeset: 69738:13878873ccc7 branch: 3.2 parent: 69734:bbc6129f7861 user: Georg Brandl date: Sun May 01 22:37:23 2011 +0200 summary: Split combined code/doctest code blocks in two blocks, to enable proper highlighting. files: Doc/tutorial/classes.rst | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -730,7 +730,6 @@ >>> next(it) 'c' >>> next(it) - Traceback (most recent call last): File "", line 1, in ? next(it) @@ -742,7 +741,7 @@ :meth:`__next__`, then :meth:`__iter__` can just return ``self``:: class Reverse: - "Iterator for looping over a sequence backwards" + """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data = data self.index = len(data) @@ -754,6 +753,8 @@ self.index = self.index - 1 return self.data[self.index] +:: + >>> rev = Reverse('spam') >>> iter(rev) <__main__.Reverse object at 0x00A1DB50> @@ -782,6 +783,8 @@ for index in range(len(data)-1, -1, -1): yield data[index] +:: + >>> for char in reverse('golf'): ... print(char) ... -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 22:38:02 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 May 2011 22:38:02 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge with 3.2 Message-ID: http://hg.python.org/cpython/rev/659424ca36ac changeset: 69739:659424ca36ac parent: 69736:b9e04043568e parent: 69738:13878873ccc7 user: Georg Brandl date: Sun May 01 22:37:46 2011 +0200 summary: merge with 3.2 files: Doc/tutorial/classes.rst | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -730,7 +730,6 @@ >>> next(it) 'c' >>> next(it) - Traceback (most recent call last): File "", line 1, in ? next(it) @@ -742,7 +741,7 @@ :meth:`__next__`, then :meth:`__iter__` can just return ``self``:: class Reverse: - "Iterator for looping over a sequence backwards" + """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data = data self.index = len(data) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 23:33:16 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 01 May 2011 23:33:16 +0200 Subject: [Python-checkins] cpython: regrtest: add the name of the failing test on a child error (-j option) Message-ID: http://hg.python.org/cpython/rev/9a0f1d7671be changeset: 69740:9a0f1d7671be user: Victor Stinner date: Sun May 01 22:57:43 2011 +0200 summary: regrtest: add the name of the failing test on a child error (-j option) files: Lib/test/regrtest.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -637,7 +637,7 @@ assert result[1] == 'KeyboardInterrupt' raise KeyboardInterrupt # What else? if result[0] == CHILD_ERROR: - raise Exception("Child error: {}".format(result[1])) + raise Exception("Child error on {}: {}".format(test, result[1])) accumulate_result(test, result) test_index += 1 except KeyboardInterrupt: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 23:33:17 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 01 May 2011 23:33:17 +0200 Subject: [Python-checkins] cpython (3.1): Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the Message-ID: http://hg.python.org/cpython/rev/c5e6f997730e changeset: 69741:c5e6f997730e branch: 3.1 parent: 69733:c57fdce01eb8 user: Victor Stinner date: Sun May 01 23:19:15 2011 +0200 summary: Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. Fix a crash if a class override its __class__ attribute (e.g. a proxy of the str type). files: Lib/test/test_descr.py | 16 ++++++++++++++++ Misc/NEWS | 5 +++++ Objects/descrobject.c | 9 ++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4235,6 +4235,22 @@ with self.assertRaises(AttributeError): del X.__abstractmethods__ + def test_proxy_call(self): + class FakeStr: + __class__ = str + + fake_str = FakeStr() + # isinstance() reads __class__ + self.assertTrue(isinstance(fake_str, str)) + + # call a method descriptor + with self.assertRaises(TypeError): + str.split(fake_str) + + # call a slot wrapper descriptor + with self.assertRaises(TypeError): + str.__add__(fake_str, "abc") + class DictProxyTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #9756: When calling a method descriptor or a slot wrapper descriptor, + the check of the object type doesn't read the __class__ attribute anymore. + Fix a crash if a class override its __class__ attribute (e.g. a proxy of the + str type). + - Issue #6780: fix starts/endswith error message to mention that tuples are accepted too. diff --git a/Objects/descrobject.c b/Objects/descrobject.c --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -226,7 +226,8 @@ return NULL; } self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)(descr->d_type))) { PyErr_Format(PyExc_TypeError, "descriptor '%V' " "requires a '%.100s' object " @@ -284,7 +285,8 @@ return NULL; } self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)(descr->d_type))) { PyErr_Format(PyExc_TypeError, "descriptor '%V' " "requires a '%.100s' object " @@ -1065,7 +1067,8 @@ assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); descr = (PyWrapperDescrObject *)d; - assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type))); + assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)(descr->d_type))); wp = PyObject_GC_New(wrapperobject, &wrappertype); if (wp != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 23:33:20 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 01 May 2011 23:33:20 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (Merge 3.1) Issue #9756: When calling a method descriptor or a slot wrapper Message-ID: http://hg.python.org/cpython/rev/4fc04f6a0731 changeset: 69742:4fc04f6a0731 branch: 3.2 parent: 69738:13878873ccc7 parent: 69741:c5e6f997730e user: Victor Stinner date: Sun May 01 23:31:36 2011 +0200 summary: (Merge 3.1) Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. Fix a crash if a class override its __class__ attribute (e.g. a proxy of the str type). files: Lib/test/test_descr.py | 16 ++++++++++++++++ Misc/NEWS | 5 +++++ Objects/descrobject.c | 9 ++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4235,6 +4235,22 @@ with self.assertRaises(AttributeError): del X.__abstractmethods__ + def test_proxy_call(self): + class FakeStr: + __class__ = str + + fake_str = FakeStr() + # isinstance() reads __class__ + self.assertTrue(isinstance(fake_str, str)) + + # call a method descriptor + with self.assertRaises(TypeError): + str.split(fake_str) + + # call a slot wrapper descriptor + with self.assertRaises(TypeError): + str.__add__(fake_str, "abc") + class DictProxyTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #9756: When calling a method descriptor or a slot wrapper descriptor, + the check of the object type doesn't read the __class__ attribute anymore. + Fix a crash if a class override its __class__ attribute (e.g. a proxy of the + str type). + - Issue #10914: Initialize correctly the filesystem codec when creating a new subinterpreter to fix a bootstrap issue with codecs implemented in Python, as the ISO-8859-15 codec. diff --git a/Objects/descrobject.c b/Objects/descrobject.c --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -226,7 +226,8 @@ return NULL; } self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)PyDescr_TYPE(descr))) { + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)PyDescr_TYPE(descr))) { PyErr_Format(PyExc_TypeError, "descriptor '%V' " "requires a '%.100s' object " @@ -284,7 +285,8 @@ return NULL; } self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)PyDescr_TYPE(descr))) { + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)PyDescr_TYPE(descr))) { PyErr_Format(PyExc_TypeError, "descriptor '%V' " "requires a '%.100s' object " @@ -1065,7 +1067,8 @@ assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); descr = (PyWrapperDescrObject *)d; - assert(PyObject_IsInstance(self, (PyObject *)PyDescr_TYPE(descr))); + assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)PyDescr_TYPE(descr))); wp = PyObject_GC_New(wrapperobject, &wrappertype); if (wp != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 23:33:25 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 01 May 2011 23:33:25 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #9756: When calling a method descriptor or a slot wrapper Message-ID: http://hg.python.org/cpython/rev/8544561b7f04 changeset: 69743:8544561b7f04 parent: 69740:9a0f1d7671be parent: 69742:4fc04f6a0731 user: Victor Stinner date: Sun May 01 23:33:06 2011 +0200 summary: (Merge 3.2) Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. Fix a crash if a class override its __class__ attribute (e.g. a proxy of the str type). files: Lib/test/test_descr.py | 16 ++++++++++++++++ Misc/NEWS | 5 +++++ Objects/descrobject.c | 9 ++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4235,6 +4235,22 @@ with self.assertRaises(AttributeError): del X.__abstractmethods__ + def test_proxy_call(self): + class FakeStr: + __class__ = str + + fake_str = FakeStr() + # isinstance() reads __class__ + self.assertTrue(isinstance(fake_str, str)) + + # call a method descriptor + with self.assertRaises(TypeError): + str.split(fake_str) + + # call a slot wrapper descriptor + with self.assertRaises(TypeError): + str.__add__(fake_str, "abc") + class DictProxyTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #9756: When calling a method descriptor or a slot wrapper descriptor, + the check of the object type doesn't read the __class__ attribute anymore. + Fix a crash if a class override its __class__ attribute (e.g. a proxy of the + str type). + - Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch by Charles-Fran?ois Natali. diff --git a/Objects/descrobject.c b/Objects/descrobject.c --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -226,7 +226,8 @@ return NULL; } self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)PyDescr_TYPE(descr))) { + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)PyDescr_TYPE(descr))) { PyErr_Format(PyExc_TypeError, "descriptor '%V' " "requires a '%.100s' object " @@ -284,7 +285,8 @@ return NULL; } self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)PyDescr_TYPE(descr))) { + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)PyDescr_TYPE(descr))) { PyErr_Format(PyExc_TypeError, "descriptor '%V' " "requires a '%.100s' object " @@ -1065,7 +1067,8 @@ assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); descr = (PyWrapperDescrObject *)d; - assert(PyObject_IsInstance(self, (PyObject *)PyDescr_TYPE(descr))); + assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)PyDescr_TYPE(descr))); wp = PyObject_GC_New(wrapperobject, &wrappertype); if (wp != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 1 23:44:31 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 01 May 2011 23:44:31 +0200 Subject: [Python-checkins] cpython (2.7): (Merge 3.1) Issue #9756: When calling a method descriptor or a slot wrapper Message-ID: http://hg.python.org/cpython/rev/109687cc2c1e changeset: 69744:109687cc2c1e branch: 2.7 parent: 69737:3d0a41407abf user: Victor Stinner date: Sun May 01 23:43:37 2011 +0200 summary: (Merge 3.1) Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. Fix a crash if a class override its __class__ attribute (e.g. a proxy of the str type). files: Lib/test/test_descr.py | 16 ++++++++++++++++ Misc/NEWS | 5 +++++ Objects/descrobject.c | 9 ++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4564,6 +4564,22 @@ with self.assertRaises(AttributeError): del X.__abstractmethods__ + def test_proxy_call(self): + class FakeStr(object): + __class__ = str + + fake_str = FakeStr() + # isinstance() reads __class__ on new style classes + self.assertTrue(isinstance(fake_str, str)) + + # call a method descriptor + with self.assertRaises(TypeError): + str.split(fake_str) + + # call a slot wrapper descriptor + with self.assertRaises(TypeError): + str.__add__(fake_str, "abc") + class DictProxyTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,11 @@ Core and Builtins ----------------- +- Issue #9756: When calling a method descriptor or a slot wrapper descriptor, + the check of the object type doesn't read the __class__ attribute anymore. + Fix a crash if a class override its __class__ attribute (e.g. a proxy of the + str type). + - Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch by Charles-Fran?ois Natali. diff --git a/Objects/descrobject.c b/Objects/descrobject.c --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -224,7 +224,8 @@ return NULL; } self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)(descr->d_type))) { PyErr_Format(PyExc_TypeError, "descriptor '%.200s' " "requires a '%.100s' object " @@ -282,7 +283,8 @@ return NULL; } self = PyTuple_GET_ITEM(args, 0); - if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)(descr->d_type))) { PyErr_Format(PyExc_TypeError, "descriptor '%.200s' " "requires a '%.100s' object " @@ -1046,7 +1048,8 @@ assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); descr = (PyWrapperDescrObject *)d; - assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type))); + assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)(descr->d_type))); wp = PyObject_GC_New(wrapperobject, &wrappertype); if (wp != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 00:37:45 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 May 2011 00:37:45 +0200 Subject: [Python-checkins] cpython (3.1): note abcs of int and float (closes #11977) Message-ID: http://hg.python.org/cpython/rev/dc65d1b99dff changeset: 69749:dc65d1b99dff branch: 3.1 parent: 69745:0db11682ea45 user: Benjamin Peterson date: Sun May 01 17:38:17 2011 -0500 summary: note abcs of int and float (closes #11977) files: Doc/library/stdtypes.rst | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -353,8 +353,8 @@ for a complete list of code points with the ``Nd`` property. -All :class:`numbers.Real` types (:class:`int` and -:class:`float`) also include the following operations: +All :class:`numbers.Real` types (:class:`int` and :class:`float`) also include +the following operations: +--------------------+------------------------------------+--------+ | Operation | Result | Notes | @@ -438,6 +438,9 @@ Additional Methods on Integer Types ----------------------------------- +The int type implements the :class:`numbers.Integral` :term:`abstact base +class`. In addition, it provides one more method + .. method:: int.bit_length() Return the number of bits necessary to represent an integer in binary, @@ -468,7 +471,8 @@ Additional Methods on Float --------------------------- -The float type has some additional methods. +The float type implements the :class:`numbers.Real` :term:`abstract base +class`. float also has the following additional methods. .. method:: float.as_integer_ratio() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 00:37:46 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 May 2011 00:37:46 +0200 Subject: [Python-checkins] cpython (2.7): note abcs of int and float (closes #11977) Message-ID: http://hg.python.org/cpython/rev/5b315145e525 changeset: 69750:5b315145e525 branch: 2.7 parent: 69748:bc5cd43c8d0c user: Benjamin Peterson date: Sun May 01 17:38:17 2011 -0500 summary: note abcs of int and float (closes #11977) files: Doc/library/stdtypes.rst | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -460,6 +460,9 @@ Additional Methods on Integer Types ----------------------------------- +The int type implements the :class:`numbers.Integral` :term:`abstact base +class`. In addition, it provides one more method + .. method:: int.bit_length() .. method:: long.bit_length() @@ -491,7 +494,8 @@ Additional Methods on Float --------------------------- -The float type has some additional methods. +The float type implements the :class:`numbers.Real` :term:`abstract base +class`. float also has the following additional methods. .. method:: float.as_integer_ratio() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 00:37:47 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 May 2011 00:37:47 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge 3.1 Message-ID: http://hg.python.org/cpython/rev/e35e51d4e28c changeset: 69751:e35e51d4e28c branch: 3.2 parent: 69746:a17f5c787cc0 parent: 69749:dc65d1b99dff user: Benjamin Peterson date: Sun May 01 17:39:40 2011 -0500 summary: merge 3.1 files: Doc/library/stdtypes.rst | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -354,8 +354,8 @@ for a complete list of code points with the ``Nd`` property. -All :class:`numbers.Real` types (:class:`int` and -:class:`float`) also include the following operations: +All :class:`numbers.Real` types (:class:`int` and :class:`float`) also include +the following operations: +--------------------+------------------------------------+--------+ | Operation | Result | Notes | @@ -439,6 +439,9 @@ Additional Methods on Integer Types ----------------------------------- +The int type implements the :class:`numbers.Integral` :term:`abstact base +class`. In addition, it provides one more method + .. method:: int.bit_length() Return the number of bits necessary to represent an integer in binary, @@ -532,7 +535,8 @@ Additional Methods on Float --------------------------- -The float type has some additional methods. +The float type implements the :class:`numbers.Real` :term:`abstract base +class`. float also has the following additional methods. .. method:: float.as_integer_ratio() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 00:37:52 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 May 2011 00:37:52 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge 3.2 Message-ID: http://hg.python.org/cpython/rev/53a55599bc6b changeset: 69752:53a55599bc6b parent: 69747:ba8a8c47de7b parent: 69751:e35e51d4e28c user: Benjamin Peterson date: Sun May 01 17:39:52 2011 -0500 summary: merge 3.2 files: Doc/library/stdtypes.rst | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -354,8 +354,8 @@ for a complete list of code points with the ``Nd`` property. -All :class:`numbers.Real` types (:class:`int` and -:class:`float`) also include the following operations: +All :class:`numbers.Real` types (:class:`int` and :class:`float`) also include +the following operations: +--------------------+------------------------------------+--------+ | Operation | Result | Notes | @@ -439,6 +439,9 @@ Additional Methods on Integer Types ----------------------------------- +The int type implements the :class:`numbers.Integral` :term:`abstact base +class`. In addition, it provides one more method + .. method:: int.bit_length() Return the number of bits necessary to represent an integer in binary, @@ -532,7 +535,8 @@ Additional Methods on Float --------------------------- -The float type has some additional methods. +The float type implements the :class:`numbers.Real` :term:`abstract base +class`. float also has the following additional methods. .. method:: float.as_integer_ratio() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 01:15:30 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 02 May 2011 01:15:30 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11277: mmap calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a Message-ID: http://hg.python.org/cpython/rev/cb464f8fb3a1 changeset: 69753:cb464f8fb3a1 branch: 3.1 parent: 69749:dc65d1b99dff user: Victor Stinner date: Mon May 02 01:05:37 2011 +0200 summary: Issue #11277: mmap calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. files: Doc/library/mmap.rst | 4 ++++ Lib/test/test_zlib.py | 2 +- Misc/NEWS | 3 +++ Modules/mmapmodule.c | 9 +++++++++ 4 files changed, 17 insertions(+), 1 deletions(-) diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -86,6 +86,10 @@ defaults to 0. *offset* must be a multiple of the PAGESIZE or ALLOCATIONGRANULARITY. + To ensure validity of the created memory mapping the file specified + by the descriptor *fileno* is internally automatically synchronized + with physical backing store on Mac OS X and OpenVMS. + This example shows a simple way of using :class:`mmap`:: import mmap diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -74,7 +74,7 @@ with open(support.TESTFN, "wb+") as f: f.seek(_4G) f.write(b"asdf") - with open(support.TESTFN, "rb") as f: + f.flush() self.mapping = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) def tearDown(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,9 @@ Library ------- +- Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get + around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. + - Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the strings are too long. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -23,6 +23,9 @@ #ifndef MS_WINDOWS #define UNIX +# ifdef __APPLE__ +# include +# endif #endif #ifdef MS_WINDOWS @@ -1091,6 +1094,12 @@ "mmap invalid access parameter."); } +#ifdef __APPLE__ + /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific + fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */ + if (fd != -1) + (void)fcntl(fd, F_FULLFSYNC); +#endif #ifdef HAVE_FSTAT # ifdef __VMS /* on OpenVMS we must ensure that all bytes are written to the file */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 01:15:32 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 02 May 2011 01:15:32 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (Merge 3.1) Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X Message-ID: http://hg.python.org/cpython/rev/e9d298376dde changeset: 69754:e9d298376dde branch: 3.2 parent: 69751:e35e51d4e28c parent: 69753:cb464f8fb3a1 user: Victor Stinner date: Mon May 02 01:11:33 2011 +0200 summary: (Merge 3.1) Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. files: Doc/library/mmap.rst | 4 ++++ Lib/test/test_zlib.py | 2 +- Misc/NEWS | 3 +++ Modules/mmapmodule.c | 9 +++++++++ 4 files changed, 17 insertions(+), 1 deletions(-) diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -86,6 +86,10 @@ defaults to 0. *offset* must be a multiple of the PAGESIZE or ALLOCATIONGRANULARITY. + To ensure validity of the created memory mapping the file specified + by the descriptor *fileno* is internally automatically synchronized + with physical backing store on Mac OS X and OpenVMS. + This example shows a simple way of using :class:`mmap`:: import mmap diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -70,7 +70,7 @@ with open(support.TESTFN, "wb+") as f: f.seek(_4G) f.write(b"asdf") - with open(support.TESTFN, "rb") as f: + f.flush() self.mapping = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) def tearDown(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -79,6 +79,9 @@ Library ------- +- Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get + around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. + - Issue #11858: configparser.ExtendedInterpolation expected lower-case section names. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -23,6 +23,9 @@ #ifndef MS_WINDOWS #define UNIX +# ifdef __APPLE__ +# include +# endif #endif #ifdef MS_WINDOWS @@ -1122,6 +1125,12 @@ "mmap invalid access parameter."); } +#ifdef __APPLE__ + /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific + fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */ + if (fd != -1) + (void)fcntl(fd, F_FULLFSYNC); +#endif #ifdef HAVE_FSTAT # ifdef __VMS /* on OpenVMS we must ensure that all bytes are written to the file */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 01:15:37 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 02 May 2011 01:15:37 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X Message-ID: http://hg.python.org/cpython/rev/d578fdc9b157 changeset: 69755:d578fdc9b157 parent: 69752:53a55599bc6b parent: 69754:e9d298376dde user: Victor Stinner date: Mon May 02 01:14:55 2011 +0200 summary: (Merge 3.2) Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. files: Doc/library/mmap.rst | 4 ++++ Lib/test/test_zlib.py | 2 +- Misc/NEWS | 3 +++ Modules/mmapmodule.c | 9 +++++++++ 4 files changed, 17 insertions(+), 1 deletions(-) diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -86,6 +86,10 @@ defaults to 0. *offset* must be a multiple of the PAGESIZE or ALLOCATIONGRANULARITY. + To ensure validity of the created memory mapping the file specified + by the descriptor *fileno* is internally automatically synchronized + with physical backing store on Mac OS X and OpenVMS. + This example shows a simple way of using :class:`mmap`:: import mmap diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -70,7 +70,7 @@ with open(support.TESTFN, "wb+") as f: f.seek(_4G) f.write(b"asdf") - with open(support.TESTFN, "rb") as f: + f.flush() self.mapping = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) def tearDown(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -132,6 +132,9 @@ Library ------- +- Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get + around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. + - Issue #8407: Add signal.pthread_sigmask() function to fetch and/or change the signal mask of the calling thread. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -23,6 +23,9 @@ #ifndef MS_WINDOWS #define UNIX +# ifdef __APPLE__ +# include +# endif #endif #ifdef MS_WINDOWS @@ -1122,6 +1125,12 @@ "mmap invalid access parameter."); } +#ifdef __APPLE__ + /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific + fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */ + if (fd != -1) + (void)fcntl(fd, F_FULLFSYNC); +#endif #ifdef HAVE_FSTAT # ifdef __VMS /* on OpenVMS we must ensure that all bytes are written to the file */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 03:14:57 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 02 May 2011 03:14:57 +0200 Subject: [Python-checkins] cpython (2.7): Fix spelling. Message-ID: http://hg.python.org/cpython/rev/7eba783fff91 changeset: 69756:7eba783fff91 branch: 2.7 parent: 69750:5b315145e525 user: Raymond Hettinger date: Sun May 01 18:14:49 2011 -0700 summary: Fix spelling. files: Doc/library/stdtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -460,7 +460,7 @@ Additional Methods on Integer Types ----------------------------------- -The int type implements the :class:`numbers.Integral` :term:`abstact base +The int type implements the :class:`numbers.Integral` :term:`abstract base class`. In addition, it provides one more method .. method:: int.bit_length() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 03:22:47 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 May 2011 03:22:47 +0200 Subject: [Python-checkins] cpython (3.1): Fix spelling. Message-ID: http://hg.python.org/cpython/rev/22fb7ff4e6d9 changeset: 69757:22fb7ff4e6d9 branch: 3.1 parent: 69753:cb464f8fb3a1 user: Raymond Hettinger date: Sun May 01 18:14:49 2011 -0700 summary: Fix spelling. files: Doc/library/stdtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -438,7 +438,7 @@ Additional Methods on Integer Types ----------------------------------- -The int type implements the :class:`numbers.Integral` :term:`abstact base +The int type implements the :class:`numbers.Integral` :term:`abstract base class`. In addition, it provides one more method .. method:: int.bit_length() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 03:22:50 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 May 2011 03:22:50 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge 3.1 Message-ID: http://hg.python.org/cpython/rev/db31b4297ddc changeset: 69758:db31b4297ddc branch: 3.2 parent: 69754:e9d298376dde parent: 69757:22fb7ff4e6d9 user: Benjamin Peterson date: Sun May 01 20:24:40 2011 -0500 summary: merge 3.1 files: Doc/library/stdtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -439,7 +439,7 @@ Additional Methods on Integer Types ----------------------------------- -The int type implements the :class:`numbers.Integral` :term:`abstact base +The int type implements the :class:`numbers.Integral` :term:`abstract base class`. In addition, it provides one more method .. method:: int.bit_length() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 03:22:52 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 May 2011 03:22:52 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge 3.2 Message-ID: http://hg.python.org/cpython/rev/513f6dfd3173 changeset: 69759:513f6dfd3173 parent: 69755:d578fdc9b157 parent: 69758:db31b4297ddc user: Benjamin Peterson date: Sun May 01 20:24:59 2011 -0500 summary: merge 3.2 files: Doc/library/stdtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -439,7 +439,7 @@ Additional Methods on Integer Types ----------------------------------- -The int type implements the :class:`numbers.Integral` :term:`abstact base +The int type implements the :class:`numbers.Integral` :term:`abstract base class`. In addition, it provides one more method .. method:: int.bit_length() -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon May 2 04:58:14 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 02 May 2011 04:58:14 +0200 Subject: [Python-checkins] Daily reference leaks (513f6dfd3173): sum=0 Message-ID: results for 513f6dfd3173 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogZssNQN', '-x'] From nnorwitz at gmail.com Mon May 2 10:00:11 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Mon, 2 May 2011 04:00:11 -0400 Subject: [Python-checkins] Python Regression Test Failures doc (1) Message-ID: <20110502080011.GA18103@kbk-i386-bb.dyndns.org> rm -rf build/* rm -rf tools/sphinx rm -rf tools/pygments rm -rf tools/jinja2 rm -rf tools/docutils Checking out Sphinx... svn: PROPFIND request failed on '/projects/external/Sphinx-0.6.5/sphinx' svn: PROPFIND of '/projects/external/Sphinx-0.6.5/sphinx': could not connect to server (http://svn.python.org) make: *** [checkout] Error 1 From python-checkins at python.org Mon May 2 13:34:22 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:34:22 +0200 Subject: [Python-checkins] cpython (3.1): Fix wording Message-ID: http://hg.python.org/cpython/rev/961c4b893e63 changeset: 69760:961c4b893e63 branch: 3.1 parent: 69699:cd68b3031f00 user: ?ric Araujo date: Sun May 01 02:14:48 2011 +0200 summary: Fix wording files: Doc/documenting/markup.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -208,8 +208,8 @@ Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. This method should be nested in a class - method, like in the example above. + described for ``function``. This directive should be nested in a class + directive, like in the example above. .. describe:: opcode -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:34:22 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:34:22 +0200 Subject: [Python-checkins] cpython (3.1): Add missing colon Message-ID: http://hg.python.org/cpython/rev/4dabb605c50c changeset: 69761:4dabb605c50c branch: 3.1 parent: 69757:22fb7ff4e6d9 user: ?ric Araujo date: Mon May 02 13:10:18 2011 +0200 summary: Add missing colon files: Doc/library/stdtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -439,7 +439,7 @@ ----------------------------------- The int type implements the :class:`numbers.Integral` :term:`abstract base -class`. In addition, it provides one more method +class`. In addition, it provides one more method: .. method:: int.bit_length() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:34:23 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:34:23 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): Branch merge Message-ID: http://hg.python.org/cpython/rev/ecf41fca3273 changeset: 69762:ecf41fca3273 branch: 3.1 parent: 69761:4dabb605c50c parent: 69760:961c4b893e63 user: ?ric Araujo date: Mon May 02 13:10:36 2011 +0200 summary: Branch merge files: Doc/documenting/markup.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -208,8 +208,8 @@ Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. This method should be nested in a class - method, like in the example above. + described for ``function``. This directive should be nested in a class + directive, like in the example above. .. describe:: opcode -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:34:29 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:34:29 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge 3.1 Message-ID: http://hg.python.org/cpython/rev/b1f28a2d6d33 changeset: 69763:b1f28a2d6d33 branch: 3.2 parent: 69758:db31b4297ddc parent: 69762:ecf41fca3273 user: ?ric Araujo date: Mon May 02 13:12:23 2011 +0200 summary: Merge 3.1 files: Doc/documenting/markup.rst | 4 ++-- Doc/library/stdtypes.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -239,8 +239,8 @@ Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. This method should be nested in a class - method, like in the example above. + described for ``function``. This directive should be nested in a class + directive, like in the example above. .. describe:: decoratormethod diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -440,7 +440,7 @@ ----------------------------------- The int type implements the :class:`numbers.Integral` :term:`abstract base -class`. In addition, it provides one more method +class`. In addition, it provides one more method: .. method:: int.bit_length() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:34:33 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:34:33 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2 Message-ID: http://hg.python.org/cpython/rev/92f563a14076 changeset: 69764:92f563a14076 parent: 69759:513f6dfd3173 parent: 69763:b1f28a2d6d33 user: ?ric Araujo date: Mon May 02 13:33:14 2011 +0200 summary: Merge 3.2 files: Doc/documenting/markup.rst | 4 ++-- Doc/library/stdtypes.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -239,8 +239,8 @@ Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. This method should be nested in a class - method, like in the example above. + described for ``function``. This directive should be nested in a class + directive, like in the example above. .. describe:: decoratormethod diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -440,7 +440,7 @@ ----------------------------------- The int type implements the :class:`numbers.Integral` :term:`abstract base -class`. In addition, it provides one more method +class`. In addition, it provides one more method: .. method:: int.bit_length() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:06 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:06 +0200 Subject: [Python-checkins] cpython (2.7): Fix improper tests in RegisterTestCase Message-ID: http://hg.python.org/cpython/rev/8d538e088d95 changeset: 69765:8d538e088d95 branch: 2.7 parent: 69373:9e49f4d81f54 user: ?ric Araujo date: Thu Apr 14 03:49:19 2011 +0200 summary: Fix improper tests in RegisterTestCase files: Lib/distutils/tests/test_register.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -138,7 +138,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) self.assertEqual(req2['Content-length'], req1['Content-length']) @@ -168,7 +168,7 @@ del register_module.raw_input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -186,7 +186,7 @@ del register_module.raw_input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:08 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:08 +0200 Subject: [Python-checkins] cpython (2.7): Minor tweaks to a few comments in heapq Message-ID: http://hg.python.org/cpython/rev/6e4f446835da changeset: 69766:6e4f446835da branch: 2.7 user: ?ric Araujo date: Fri Apr 15 23:34:31 2011 +0200 summary: Minor tweaks to a few comments in heapq files: Lib/heapq.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -178,7 +178,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -368,7 +368,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -406,7 +406,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:09 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:09 +0200 Subject: [Python-checkins] cpython (2.7): Fix double use of f.close(). Message-ID: http://hg.python.org/cpython/rev/c02c78d93a2e changeset: 69767:c02c78d93a2e branch: 2.7 user: ?ric Araujo date: Sat Apr 16 00:13:39 2011 +0200 summary: Fix double use of f.close(). The other one is in a finally block not seen in the diff, which I added in 3bf86785cd9c (for #10252). files: Lib/sysconfig.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -639,7 +639,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:10 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:10 +0200 Subject: [Python-checkins] cpython (2.7): Advertise nesting directives for class/method and class/data combos. Message-ID: http://hg.python.org/cpython/rev/c882b5ff92d9 changeset: 69768:c882b5ff92d9 branch: 2.7 parent: 69704:1a45c92f9716 user: ?ric Araujo date: Sat Apr 16 23:47:53 2011 +0200 summary: Advertise nesting directives for class/method and class/data combos. Also fix a typo and a misleading example (method used to describe function). files: Doc/documenting/markup.rst | 25 +++++++++++++++++++++---- 1 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -186,13 +186,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This method should be nested in a class + method, like in the example above. .. describe:: opcode -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:18 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:18 +0200 Subject: [Python-checkins] cpython (2.7): Fix file handle leak Message-ID: http://hg.python.org/cpython/rev/648d9ce2e426 changeset: 69769:648d9ce2e426 branch: 2.7 user: ?ric Araujo date: Sun May 01 02:05:58 2011 +0200 summary: Fix file handle leak files: Lib/distutils/command/sdist.py | 23 ++++++++++++--------- 1 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -306,17 +306,20 @@ rstrip_ws=1, collapse_join=1) - while 1: - line = template.readline() - if line is None: # end of file - break + try: + while 1: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError, msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError, msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:22 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:22 +0200 Subject: [Python-checkins] cpython (2.7): Add docstring to anydbm.open Message-ID: http://hg.python.org/cpython/rev/5c3f3d352e0a changeset: 69770:5c3f3d352e0a branch: 2.7 user: ?ric Araujo date: Sun May 01 02:02:30 2011 +0200 summary: Add docstring to anydbm.open files: Lib/anydbm.py | 24 +++++++++++++----------- 1 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Lib/anydbm.py b/Lib/anydbm.py --- a/Lib/anydbm.py +++ b/Lib/anydbm.py @@ -29,17 +29,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. - """ class error(Exception): @@ -63,7 +54,18 @@ error = tuple(_errors) -def open(file, flag = 'r', mode = 0666): +def open(file, flag='r', mode=0666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ + # guess the type of an existing database from whichdb import whichdb result=whichdb(file) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:23 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:23 +0200 Subject: [Python-checkins] cpython (merge 2.7 -> 2.7): Branch merge Message-ID: http://hg.python.org/cpython/rev/da2c8cb59559 changeset: 69771:da2c8cb59559 branch: 2.7 parent: 69770:5c3f3d352e0a parent: 69767:c02c78d93a2e user: ?ric Araujo date: Sun May 01 02:09:37 2011 +0200 summary: Branch merge files: Lib/distutils/tests/test_register.py | 6 +++--- Lib/heapq.py | 6 +++--- Lib/sysconfig.py | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -138,7 +138,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) self.assertEqual(req2['Content-length'], req1['Content-length']) @@ -168,7 +168,7 @@ del register_module.raw_input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -186,7 +186,7 @@ del register_module.raw_input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -178,7 +178,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -368,7 +368,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -406,7 +406,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -639,7 +639,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:25 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:25 +0200 Subject: [Python-checkins] cpython (2.7): Fix wording Message-ID: http://hg.python.org/cpython/rev/b6af2c367549 changeset: 69772:b6af2c367549 branch: 2.7 user: ?ric Araujo date: Sun May 01 02:15:03 2011 +0200 summary: Fix wording files: Doc/documenting/markup.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -208,8 +208,8 @@ Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. This method should be nested in a class - method, like in the example above. + described for ``function``. This directive should be nested in a class + directive, like in the example above. .. describe:: opcode -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:30 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:30 +0200 Subject: [Python-checkins] cpython (2.7): Fix grammar to include both integer types in 2.x Message-ID: http://hg.python.org/cpython/rev/d7cd797842c0 changeset: 69773:d7cd797842c0 branch: 2.7 parent: 69756:7eba783fff91 user: ?ric Araujo date: Mon May 02 13:09:36 2011 +0200 summary: Fix grammar to include both integer types in 2.x files: Doc/library/stdtypes.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -460,8 +460,8 @@ Additional Methods on Integer Types ----------------------------------- -The int type implements the :class:`numbers.Integral` :term:`abstract base -class`. In addition, it provides one more method +The integer types implement the :class:`numbers.Integral` :term:`abstract base +class`. In addition, they provide one more method: .. method:: int.bit_length() .. method:: long.bit_length() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 13:39:31 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 02 May 2011 13:39:31 +0200 Subject: [Python-checkins] cpython (merge 2.7 -> 2.7): Branch merge Message-ID: http://hg.python.org/cpython/rev/a13310c045b0 changeset: 69774:a13310c045b0 branch: 2.7 parent: 69773:d7cd797842c0 parent: 69772:b6af2c367549 user: ?ric Araujo date: Mon May 02 13:36:18 2011 +0200 summary: Branch merge files: Doc/documenting/markup.rst | 25 +++++++++++++-- Lib/anydbm.py | 24 ++++++++------- Lib/distutils/command/sdist.py | 23 ++++++++------ Lib/distutils/tests/test_register.py | 6 +- Lib/heapq.py | 6 +- Lib/sysconfig.py | 1 - 6 files changed, 53 insertions(+), 32 deletions(-) diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -152,7 +152,7 @@ Describes global data in a module, including both variables and values used as "defined constants." Class and object attributes are not documented - using this environment. + using this directive. .. describe:: exception @@ -165,7 +165,7 @@ parameters, enclosing optional parameters in brackets. Default values can be given if it enhances clarity. For example:: - .. function:: Timer.repeat([repeat=3[, number=1000000]]) + .. function:: repeat([repeat=3[, number=1000000]]) Object methods are not documented using this directive. Bound object methods placed in the module namespace as part of the public interface of the module @@ -186,13 +186,30 @@ Describes an object data attribute. The description should include information about the type of the data to be expected and whether it may be - changed directly. + changed directly. This directive should be nested in a class directive, + like in this example:: + + .. class:: Spam + + Description of the class. + + .. data:: ham + + Description of the attribute. + + If is also possible to document an attribute outside of a class directive, + for example if the documentation for different attributes and methods is + split in multiple sections. The class name should then be included + explicitly:: + + .. data:: Spam.eggs .. describe:: method Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. + described for ``function``. This directive should be nested in a class + directive, like in the example above. .. describe:: opcode diff --git a/Lib/anydbm.py b/Lib/anydbm.py --- a/Lib/anydbm.py +++ b/Lib/anydbm.py @@ -29,17 +29,8 @@ list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. - """ class error(Exception): @@ -63,7 +54,18 @@ error = tuple(_errors) -def open(file, flag = 'r', mode = 0666): +def open(file, flag='r', mode=0666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ + # guess the type of an existing database from whichdb import whichdb result=whichdb(file) diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -306,17 +306,20 @@ rstrip_ws=1, collapse_join=1) - while 1: - line = template.readline() - if line is None: # end of file - break + try: + while 1: + line = template.readline() + if line is None: # end of file + break - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError, msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError, msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -138,7 +138,7 @@ # let's see what the server received : we should # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) + self.assertEqual(len(self.conn.reqs), 2) req1 = dict(self.conn.reqs[0].headers) req2 = dict(self.conn.reqs[1].headers) self.assertEqual(req2['Content-length'], req1['Content-length']) @@ -168,7 +168,7 @@ del register_module.raw_input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '608') @@ -186,7 +186,7 @@ del register_module.raw_input # we should have send a request - self.assertTrue(self.conn.reqs, 1) + self.assertEqual(len(self.conn.reqs), 1) req = self.conn.reqs[0] headers = dict(req.headers) self.assertEqual(headers['Content-length'], '290') diff --git a/Lib/heapq.py b/Lib/heapq.py --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -178,7 +178,7 @@ return item def heapify(x): - """Transform list into a heap, in-place, in O(len(heap)) time.""" + """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at # is the largest with a child index in-range, so must have 2*i + 1 < n, @@ -368,7 +368,7 @@ return [min(chain(head, it))] return [min(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): @@ -406,7 +406,7 @@ return [max(chain(head, it))] return [max(chain(head, it), key=key)] - # When n>=size, it's faster to use sort() + # When n>=size, it's faster to use sorted() try: size = len(iterable) except (TypeError, AttributeError): diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -639,7 +639,6 @@ m = re.search( r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) - f.close() if m is not None: macrelease = '.'.join(m.group(1).split('.')[:2]) # else: fall back to the default behaviour -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 14:18:27 2011 From: python-checkins at python.org (vinay.sajip) Date: Mon, 02 May 2011 14:18:27 +0200 Subject: [Python-checkins] cpython: Added tests to improve coverage. Message-ID: http://hg.python.org/cpython/rev/347fa1c0b953 changeset: 69775:347fa1c0b953 parent: 69759:513f6dfd3173 user: Vinay Sajip date: Mon May 02 13:17:27 2011 +0100 summary: Added tests to improve coverage. files: Lib/test/test_logging.py | 447 ++++++++++++++++++++------ 1 files changed, 339 insertions(+), 108 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -33,6 +33,7 @@ import pickle import io import gc +from http.server import HTTPServer, BaseHTTPRequestHandler import json import os import queue @@ -40,7 +41,8 @@ import select import smtpd import socket -from socketserver import ThreadingTCPServer, StreamRequestHandler +from socketserver import (ThreadingUDPServer, DatagramRequestHandler, + ThreadingTCPServer, StreamRequestHandler) import struct import sys import tempfile @@ -49,6 +51,7 @@ import textwrap import time import unittest +from urllib.parse import urlparse, parse_qs import warnings import weakref try: @@ -596,9 +599,8 @@ logging.raiseExceptions = old_raise sys.stderr = old_stderr - -TEST_SMTP_PORT = 9025 - +# -- The following section could be moved into a server_helper.py module +# -- if it proves to be of wider utility than just test_logging class TestSMTPChannel(smtpd.SMTPChannel): def __init__(self, server, conn, addr, sockmap): @@ -642,6 +644,7 @@ # try to re-use a server port if possible self.set_reuse_addr() self.bind(addr) + self.port = sock.getsockname()[1] self.listen(5) except: self.close() @@ -666,23 +669,162 @@ def serve_forever(self, poll_interval): asyncore.loop(poll_interval, map=self.sockmap) - def stop(self): + def stop(self, timeout=None): self.close() - self._thread.join() + self._thread.join(timeout) self._thread = None +class ControlMixin(object): + """ + This mixin is used to start a server on a separate thread, and + shut it down programmatically. Request handling is simplified - instead + of needing to derive a suitable RequestHandler subclass, you just + provide a callable which will be passed each received request to be + processed. + + :param handler: A handler callable which will be called with a + single parameter - the request - in order to + process the request. This handler is called on the + server thread, effectively meaning that requests are + processed serially. While not quite Web scale ;-), + this should be fine for testing applications. + :param poll_interval: The polling interval in seconds. + """ + def __init__(self, handler, poll_interval): + self._thread = None + self.poll_interval = poll_interval + self._handler = handler + self.ready = threading.Event() + + def start(self): + """ + Create a daemon thread to run the server, and start it. + """ + self._thread = t = threading.Thread(target=self.serve_forever, + args=(self.poll_interval,)) + t.setDaemon(True) + t.start() + + def serve_forever(self, poll_interval): + self.ready.set() + super(ControlMixin, self).serve_forever(poll_interval) + + def stop(self, timeout=None): + """ + Tell the server thread to stop, and wait for it to do so. + """ + self.shutdown() + if self._thread is not None: + self._thread.join(timeout) + self._thread = None + self.server_close() + self.ready.clear() + +class TestHTTPServer(ControlMixin, HTTPServer): + """ + An HTTP server which is controllable using :class:`ControlMixin`. + + :param addr: A tuple with the IP address and port to listen on. + :param handler: A handler callable which will be called with a + single parameter - the request - in order to + process the request. + :param poll_interval: The polling interval in seconds. + """ + def __init__(self, addr, handler, poll_interval=0.5, log=False): + class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler): + def __getattr__(self, name, default=None): + if name.startswith('do_'): + return self.process_request + raise AttributeError(name) + + def process_request(self): + self.server._handler(self) + + def log_message(self, format, *args): + if log: + super(DelegatingHTTPRequestHandler, + self).log_message(format, *args) + HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler) + ControlMixin.__init__(self, handler, poll_interval) + +class TestTCPServer(ControlMixin, ThreadingTCPServer): + """ + A TCP server which is controllable using :class:`ControlMixin`. + + :param addr: A tuple with the IP address and port to listen on. + :param handler: A handler callable which will be called with a single + parameter - the request - in order to process the request. + :param poll_interval: The polling interval in seconds. + :bind_and_activate: If True (the default), binds the server and starts it + listening. If False, you need to call + :meth:`server_bind` and :meth:`server_activate` at + some later time before calling :meth:`start`, so that + the server will set up the socket and listen on it. + """ + + allow_reuse_address = True + + def __init__(self, addr, handler, poll_interval=0.5, + bind_and_activate=True): + class DelegatingTCPRequestHandler(StreamRequestHandler): + + def handle(self): + self.server._handler(self) + ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler, + bind_and_activate) + ControlMixin.__init__(self, handler, poll_interval) + + def server_bind(self): + super(TestTCPServer, self).server_bind() + self.port = self.socket.getsockname()[1] + +class TestUDPServer(ControlMixin, ThreadingUDPServer): + """ + A UDP server which is controllable using :class:`ControlMixin`. + + :param addr: A tuple with the IP address and port to listen on. + :param handler: A handler callable which will be called with a + single parameter - the request - in order to + process the request. + :param poll_interval: The polling interval for shutdown requests, + in seconds. + :bind_and_activate: If True (the default), binds the server and + starts it listening. If False, you need to + call :meth:`server_bind` and + :meth:`server_activate` at some later time + before calling :meth:`start`, so that the server will + set up the socket and listen on it. + """ + def __init__(self, addr, handler, poll_interval=0.5, bind_and_activate=True): + class DelegatingUDPRequestHandler(DatagramRequestHandler): + + def handle(self): + self.server._handler(self) + ThreadingUDPServer.__init__(self, addr, DelegatingUDPRequestHandler, + bind_and_activate) + ControlMixin.__init__(self, handler, poll_interval) + + def server_bind(self): + super(TestUDPServer, self).server_bind() + self.port = self.socket.getsockname()[1] + + +# - end of server_helper section class SMTPHandlerTest(BaseTest): def test_basic(self): - addr = ('localhost', TEST_SMTP_PORT) + sockmap = {} + server = TestSMTPServer(('localhost', 0), self.process_message, 0.001, + sockmap) + server.start() + addr = ('localhost', server.port) h = logging.handlers.SMTPHandler(addr, 'me', 'you', 'Log') self.assertEqual(h.toaddrs, ['you']) self.messages = [] - sockmap = {} - server = TestSMTPServer(addr, self.process_message, 0.001, sockmap) - server.start() r = logging.makeLogRecord({'msg': 'Hello'}) + self.handled = threading.Event() h.handle(r) + self.handled.wait() server.stop() self.assertEqual(len(self.messages), 1) peer, mailfrom, rcpttos, data = self.messages[0] @@ -694,7 +836,7 @@ def process_message(self, *args): self.messages.append(args) - + self.handled.set() class MemoryHandlerTest(BaseTest): @@ -1068,68 +1210,6 @@ # Original logger output is empty. self.assert_log_lines([]) -class LogRecordStreamHandler(StreamRequestHandler): - - """Handler for a streaming logging request. It saves the log message in the - TCP server's 'log_output' attribute.""" - - TCP_LOG_END = "!!!END!!!" - - def handle(self): - """Handle multiple requests - each expected to be of 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.handle_log_record(record) - - def unpickle(self, data): - return pickle.loads(data) - - def handle_log_record(self, record): - # If the end-of-messages sentinel is seen, tell the server to - # terminate. - if self.TCP_LOG_END in record.msg: - self.server.abort = 1 - return - self.server.log_output += record.msg + "\n" - - -class LogRecordSocketReceiver(ThreadingTCPServer): - - """A simple-minded TCP socket-based logging receiver suitable for test - purposes.""" - - allow_reuse_address = 1 - log_output = "" - - def __init__(self, host='localhost', - port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, - handler=LogRecordStreamHandler): - ThreadingTCPServer.__init__(self, (host, port), handler) - self.abort = False - self.timeout = 0.1 - self.finished = threading.Event() - - def serve_until_stopped(self): - while not self.abort: - rd, wr, ex = select.select([self.socket.fileno()], [], [], - self.timeout) - if rd: - self.handle_request() - # Notify the main thread that we're about to exit - self.finished.set() - # close the listen socket - self.server_close() - @unittest.skipUnless(threading, 'Threading required for this test.') class SocketHandlerTest(BaseTest): @@ -1140,51 +1220,54 @@ """Set up a TCP server to receive log messages, and a SocketHandler pointing to that server's address and port.""" BaseTest.setUp(self) - self.tcpserver = LogRecordSocketReceiver(port=0) - self.port = self.tcpserver.socket.getsockname()[1] - self.threads = [ - threading.Thread(target=self.tcpserver.serve_until_stopped)] - for thread in self.threads: - thread.start() - - self.sock_hdlr = logging.handlers.SocketHandler('localhost', self.port) - self.sock_hdlr.setFormatter(self.root_formatter) + addr = ('localhost', 0) + self.server = server = TestTCPServer(addr, self.handle_socket, + 0.01) + server.start() + server.ready.wait() + self.sock_hdlr = logging.handlers.SocketHandler('localhost', + server.port) + self.log_output = '' self.root_logger.removeHandler(self.root_logger.handlers[0]) self.root_logger.addHandler(self.sock_hdlr) + self.handled = threading.Semaphore(0) def tearDown(self): """Shutdown the TCP server.""" try: - if hasattr(self, 'tcpserver'): - self.tcpserver.abort = True - del self.tcpserver + self.server.stop(2.0) self.root_logger.removeHandler(self.sock_hdlr) self.sock_hdlr.close() - for thread in self.threads: - thread.join(2.0) finally: BaseTest.tearDown(self) - def get_output(self): - """Get the log output as received by the TCP server.""" - # Signal the TCP receiver and wait for it to terminate. - self.root_logger.critical(LogRecordStreamHandler.TCP_LOG_END) - self.tcpserver.finished.wait(2.0) - return self.tcpserver.log_output + def handle_socket(self, request): + conn = request.connection + while True: + chunk = conn.recv(4) + if len(chunk) < 4: + break + slen = struct.unpack(">L", chunk)[0] + chunk = conn.recv(slen) + while len(chunk) < slen: + chunk = chunk + conn.recv(slen - len(chunk)) + obj = pickle.loads(chunk) + record = logging.makeLogRecord(obj) + self.log_output += record.msg + '\n' + self.handled.release() def test_output(self): # The log message sent to the SocketHandler is properly received. logger = logging.getLogger("tcp") logger.error("spam") + self.handled.acquire() logger.debug("eggs") - self.assertEqual(self.get_output(), "spam\neggs\n") + self.handled.acquire() + self.assertEqual(self.log_output, "spam\neggs\n") def test_noserver(self): # Kill the server - self.tcpserver.abort = True - del self.tcpserver - for thread in self.threads: - thread.join(2.0) + self.server.stop(2.0) #The logging call should try to connect, which should fail try: raise RuntimeError('Deliberate mistake') @@ -1196,6 +1279,143 @@ time.sleep(self.sock_hdlr.retryTime - now + 0.001) self.root_logger.error('Nor this') + + at unittest.skipUnless(threading, 'Threading required for this test.') +class DatagramHandlerTest(BaseTest): + + """Test for DatagramHandler.""" + + def setUp(self): + """Set up a UDP server to receive log messages, and a DatagramHandler + pointing to that server's address and port.""" + BaseTest.setUp(self) + addr = ('localhost', 0) + self.server = server = TestUDPServer(addr, self.handle_datagram, + 0.01) + server.start() + server.ready.wait() + self.sock_hdlr = logging.handlers.DatagramHandler('localhost', + server.port) + self.log_output = '' + self.root_logger.removeHandler(self.root_logger.handlers[0]) + self.root_logger.addHandler(self.sock_hdlr) + self.handled = threading.Event() + + def tearDown(self): + """Shutdown the UDP server.""" + try: + self.server.stop(2.0) + self.root_logger.removeHandler(self.sock_hdlr) + self.sock_hdlr.close() + finally: + BaseTest.tearDown(self) + + def handle_datagram(self, request): + slen = struct.pack('>L', 0) # length of prefix + packet = request.packet[len(slen):] + obj = pickle.loads(packet) + record = logging.makeLogRecord(obj) + self.log_output += record.msg + '\n' + self.handled.set() + + def test_output(self): + # The log message sent to the DatagramHandler is properly received. + logger = logging.getLogger("udp") + logger.error("spam") + self.handled.wait() + self.assertEqual(self.log_output, "spam\n") + + + at unittest.skipUnless(threading, 'Threading required for this test.') +class SysLogHandlerTest(BaseTest): + + """Test for SysLogHandler using UDP.""" + + def setUp(self): + """Set up a UDP server to receive log messages, and a SysLogHandler + pointing to that server's address and port.""" + BaseTest.setUp(self) + addr = ('localhost', 0) + self.server = server = TestUDPServer(addr, self.handle_datagram, + 0.01) + server.start() + server.ready.wait() + self.sl_hdlr = logging.handlers.SysLogHandler(('localhost', + server.port)) + self.log_output = '' + self.root_logger.removeHandler(self.root_logger.handlers[0]) + self.root_logger.addHandler(self.sl_hdlr) + self.handled = threading.Event() + + def tearDown(self): + """Shutdown the UDP server.""" + try: + self.server.stop(2.0) + self.root_logger.removeHandler(self.sl_hdlr) + self.sl_hdlr.close() + finally: + BaseTest.tearDown(self) + + def handle_datagram(self, request): + self.log_output = request.packet + self.handled.set() + + def test_output(self): + # The log message sent to the SysLogHandler is properly received. + logger = logging.getLogger("slh") + logger.error("sp\xe4m") + self.handled.wait() + self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m\x00') + + + at unittest.skipUnless(threading, 'Threading required for this test.') +class HTTPHandlerTest(BaseTest): + + """Test for HTTPHandler.""" + + def setUp(self): + """Set up an HTTP server to receive log messages, and a HTTPHandler + pointing to that server's address and port.""" + BaseTest.setUp(self) + addr = ('localhost', 0) + self.server = server = TestHTTPServer(addr, self.handle_request, + 0.01) + server.start() + server.ready.wait() + host = 'localhost:%d' % server.server_port + self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob') + self.log_data = None + self.root_logger.removeHandler(self.root_logger.handlers[0]) + self.root_logger.addHandler(self.h_hdlr) + self.handled = threading.Event() + + def tearDown(self): + """Shutdown the UDP server.""" + try: + self.server.stop(2.0) + self.root_logger.removeHandler(self.h_hdlr) + self.h_hdlr.close() + finally: + BaseTest.tearDown(self) + + def handle_request(self, request): + self.log_data = urlparse(request.path) + request.send_response(200) + self.handled.set() + + def test_output(self): + # The log message sent to the SysLogHandler is properly received. + logger = logging.getLogger("http") + msg = "sp\xe4m" + logger.error(msg) + self.handled.wait() + self.assertEqual(self.log_data.path, '/frob') + d = parse_qs(self.log_data.query) + self.assertEqual(d['name'], ['http']) + self.assertEqual(d['funcName'], ['test_output']) + self.assertEqual(d['msg'], [msg]) + + class MemoryTest(BaseTest): """Test memory persistence of logger objects.""" @@ -3129,7 +3349,7 @@ def assertLogFile(self, filename): "Assert a log file is there and register it for deletion" self.assertTrue(os.path.exists(filename), - msg="Log file %r does not exist") + msg="Log file %r does not exist" % filename) self.rmfiles.append(filename) @@ -3181,8 +3401,18 @@ rh.close() class TimedRotatingFileHandlerTest(BaseFileTest): - # test methods added below - pass + # other test methods added below + def test_rollover(self): + fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S') + r = logging.makeLogRecord({'msg': 'testing'}) + fh.emit(r) + self.assertLogFile(self.fn) + time.sleep(1.0) + fh.emit(r) + now = datetime.datetime.now() + prevsec = now - datetime.timedelta(seconds=1) + suffix = prevsec.strftime(".%Y-%m-%d_%H-%M-%S") + self.assertLogFile(self.fn + suffix) def secs(**kw): return datetime.timedelta(**kw) // datetime.timedelta(seconds=1) @@ -3238,14 +3468,15 @@ def test_main(): run_unittest(BuiltinLevelsTest, BasicFilterTest, CustomLevelsAndFiltersTest, HandlerTest, MemoryHandlerTest, - ConfigFileTest, SocketHandlerTest, MemoryTest, - EncodingTest, WarningsTest, ConfigDictTest, ManagerTest, - FormatterTest, BufferingFormatterTest, StreamHandlerTest, - LogRecordFactoryTest, ChildLoggerTest, QueueHandlerTest, - ShutdownTest, ModuleLevelMiscTest, BasicConfigTest, - LoggerAdapterTest, LoggerTest, SMTPHandlerTest, - FileHandlerTest, RotatingFileHandlerTest, + ConfigFileTest, SocketHandlerTest, DatagramHandlerTest, + MemoryTest, EncodingTest, WarningsTest, ConfigDictTest, + ManagerTest, FormatterTest, BufferingFormatterTest, + StreamHandlerTest, LogRecordFactoryTest, ChildLoggerTest, + QueueHandlerTest, ShutdownTest, ModuleLevelMiscTest, + BasicConfigTest, LoggerAdapterTest, LoggerTest, + SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest, LastResortTest, LogRecordTest, ExceptionTest, + SysLogHandlerTest, HTTPHandlerTest, TimedRotatingFileHandlerTest ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 14:18:29 2011 From: python-checkins at python.org (vinay.sajip) Date: Mon, 02 May 2011 14:18:29 +0200 Subject: [Python-checkins] cpython (merge default -> default): Merge. Message-ID: http://hg.python.org/cpython/rev/51fe7d3250a1 changeset: 69776:51fe7d3250a1 parent: 69775:347fa1c0b953 parent: 69764:92f563a14076 user: Vinay Sajip date: Mon May 02 13:18:21 2011 +0100 summary: Merge. files: Doc/documenting/markup.rst | 4 ++-- Doc/library/stdtypes.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -239,8 +239,8 @@ Describes an object method. The parameters should not include the ``self`` parameter. The description should include similar information to that - described for ``function``. This method should be nested in a class - method, like in the example above. + described for ``function``. This directive should be nested in a class + directive, like in the example above. .. describe:: decoratormethod diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -440,7 +440,7 @@ ----------------------------------- The int type implements the :class:`numbers.Integral` :term:`abstract base -class`. In addition, it provides one more method +class`. In addition, it provides one more method: .. method:: int.bit_length() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 14:48:44 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 02 May 2011 14:48:44 +0200 Subject: [Python-checkins] cpython (3.2): I was right, hardconding the localhost IP doesn't work in linux-vserver. Message-ID: http://hg.python.org/cpython/rev/89b9b7094068 changeset: 69777:89b9b7094068 branch: 3.2 parent: 69763:b1f28a2d6d33 user: R David Murray date: Mon May 02 08:47:24 2011 -0400 summary: I was right, hardconding the localhost IP doesn't work in linux-vserver. files: Lib/test/test_smtplib.py | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -290,8 +290,7 @@ self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds - # XXX: I'm not sure hardcoding this IP will work on linux-vserver. - m['X-Peer'] = '127.0.0.1' + m['X-Peer'] = socket.gethostbyname('localhost') mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) @@ -311,8 +310,7 @@ self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds - # XXX: I'm not sure hardcoding this IP will work on linux-vserver. - m['X-Peer'] = '127.0.0.1' + m['X-Peer'] = socket.gethostbyname('localhost') # The Bcc header is deleted before serialization. del m['Bcc'] mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) @@ -341,8 +339,7 @@ self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds - # XXX: I'm not sure hardcoding this IP will work on linux-vserver. - m['X-Peer'] = '127.0.0.1' + m['X-Peer'] = socket.gethostbyname('localhost') mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) debugout = smtpd.DEBUGSTREAM.getvalue() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 14:48:48 2011 From: python-checkins at python.org (r.david.murray) Date: Mon, 02 May 2011 14:48:48 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: I was right, hardconding the localhost IP doesn't work in linux-vserver. Message-ID: http://hg.python.org/cpython/rev/07613ea46dbc changeset: 69778:07613ea46dbc parent: 69776:51fe7d3250a1 parent: 69777:89b9b7094068 user: R David Murray date: Mon May 02 08:48:00 2011 -0400 summary: Merge: I was right, hardconding the localhost IP doesn't work in linux-vserver. files: Lib/test/test_smtplib.py | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -290,8 +290,7 @@ self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds - # XXX: I'm not sure hardcoding this IP will work on linux-vserver. - m['X-Peer'] = '127.0.0.1' + m['X-Peer'] = socket.gethostbyname('localhost') mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) @@ -311,8 +310,7 @@ self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds - # XXX: I'm not sure hardcoding this IP will work on linux-vserver. - m['X-Peer'] = '127.0.0.1' + m['X-Peer'] = socket.gethostbyname('localhost') # The Bcc header is deleted before serialization. del m['Bcc'] mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) @@ -341,8 +339,7 @@ self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds - # XXX: I'm not sure hardcoding this IP will work on linux-vserver. - m['X-Peer'] = '127.0.0.1' + m['X-Peer'] = socket.gethostbyname('localhost') mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) debugout = smtpd.DEBUGSTREAM.getvalue() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 15:31:25 2011 From: python-checkins at python.org (vinay.sajip) Date: Mon, 02 May 2011 15:31:25 +0200 Subject: [Python-checkins] cpython: Updated docstrings. Message-ID: http://hg.python.org/cpython/rev/f587197864b0 changeset: 69779:f587197864b0 user: Vinay Sajip date: Mon May 02 14:31:16 2011 +0100 summary: Updated docstrings. files: Lib/test/test_logging.py | 64 +++++++++++++++++++++++++++- 1 files changed, 63 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -603,6 +603,12 @@ # -- if it proves to be of wider utility than just test_logging class TestSMTPChannel(smtpd.SMTPChannel): + """ + This derived class has had to be created because smtpd does not + support use of custom channel maps, although they are allowed by + asyncore's design. Issue #11959 has been raised to address this, + and if resolved satisfactorily, some of this code can be removed. + """ def __init__(self, server, conn, addr, sockmap): asynchat.async_chat.__init__(self, conn, sockmap) self.smtp_server = server @@ -630,6 +636,25 @@ class TestSMTPServer(smtpd.SMTPServer): + """ + This class implements a test SMTP server. + + :param addr: A (host, port) tuple which the server listens on. + You can specify a port value of zero: the server's + *port* attribute will hold the actual port number + used, which can be used in client connections. + :param handler: A callable which will be called to process + incoming messages. The handler will be passed + the client address tuple, who the message is from, + a list of recipients and the message data. + :param poll_interval: The interval, in seconds, used in the underlying + :func:`select` or :func:`poll` call by + :func:`asyncore.loop`. + :param sockmap: A dictionary which will be used to hold + :class:`asyncore.dispatcher` instances used by + :func:`asyncore.loop`. This avoids changing the + :mod:`asyncore` module's global state. + """ channel_class = TestSMTPChannel def __init__(self, addr, handler, poll_interval, sockmap): @@ -654,22 +679,51 @@ self.poll_interval = poll_interval def handle_accepted(self, conn, addr): - print('Incoming connection from %s' % repr(addr), file=smtpd.DEBUGSTREAM) + """ + Redefined only because the base class does not pass in a + map, forcing use of a global in :mod:`asyncore`. + """ channel = self.channel_class(self, conn, addr, self.sockmap) def process_message(self, peer, mailfrom, rcpttos, data): + """ + Delegates to the handler passed in to the server's constructor. + + Typically, this will be a test case method. + :param peer: The client (host, port) tuple. + :param mailfrom: The address of the sender. + :param rcpttos: The addresses of the recipients. + :param data: The message. + """ self._handler(peer, mailfrom, rcpttos, data) def start(self): + """ + Start the server running on a separate daemon thread. + """ self._thread = t = threading.Thread(target=self.serve_forever, args=(self.poll_interval,)) t.setDaemon(True) t.start() def serve_forever(self, poll_interval): + """ + Run the :mod:`asyncore` loop until normal termination + conditions arise. + :param poll_interval: The interval, in seconds, used in the underlying + :func:`select` or :func:`poll` call by + :func:`asyncore.loop`. + """ asyncore.loop(poll_interval, map=self.sockmap) def stop(self, timeout=None): + """ + Stop the thread by closing the server instance. + Wait for the server thread to terminate. + + :param timeout: How long to wait for the server thread + to terminate. + """ self.close() self._thread.join(timeout) self._thread = None @@ -706,12 +760,19 @@ t.start() def serve_forever(self, poll_interval): + """ + Run the server. Set the ready flag before entering the + service loop. + """ self.ready.set() super(ControlMixin, self).serve_forever(poll_interval) def stop(self, timeout=None): """ Tell the server thread to stop, and wait for it to do so. + + :param timeout: How long to wait for the server thread + to terminate. """ self.shutdown() if self._thread is not None: @@ -729,6 +790,7 @@ single parameter - the request - in order to process the request. :param poll_interval: The polling interval in seconds. + :param log: Pass ``True`` to enable log messages. """ def __init__(self, addr, handler, poll_interval=0.5, log=False): class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 15:43:08 2011 From: python-checkins at python.org (vinay.sajip) Date: Mon, 02 May 2011 15:43:08 +0200 Subject: [Python-checkins] cpython: Improved thread interlocks in tests. Message-ID: http://hg.python.org/cpython/rev/7fe328d0fa5f changeset: 69780:7fe328d0fa5f user: Vinay Sajip date: Mon May 02 14:43:00 2011 +0100 summary: Improved thread interlocks in tests. files: Lib/test/test_logging.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1385,7 +1385,10 @@ logger = logging.getLogger("udp") logger.error("spam") self.handled.wait() - self.assertEqual(self.log_output, "spam\n") + self.handled.clear() + logger.error("eggs") + self.handled.wait() + self.assertEqual(self.log_output, "spam\neggs\n") @unittest.skipUnless(threading, 'Threading required for this test.') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 16:14:37 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 02 May 2011 16:14:37 +0200 Subject: [Python-checkins] cpython (3.2): logging: don't define QueueListener if Python has no thread support Message-ID: http://hg.python.org/cpython/rev/728e573d7816 changeset: 69781:728e573d7816 branch: 3.2 parent: 69777:89b9b7094068 user: Victor Stinner date: Mon May 02 16:11:28 2011 +0200 summary: logging: don't define QueueListener if Python has no thread support files: Lib/logging/handlers.py | 184 +++++++++++++------------- Lib/test/test_logging.py | 2 + Misc/NEWS | 2 + 3 files changed, 98 insertions(+), 90 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -27,7 +27,10 @@ import logging, socket, os, pickle, struct, time, re from stat import ST_DEV, ST_INO, ST_MTIME import queue -import threading +try: + import threading +except ImportError: + threading = None try: import codecs @@ -1218,106 +1221,107 @@ except: self.handleError(record) -class QueueListener(object): - """ - This class implements an internal threaded listener which watches for - LogRecords being added to a queue, removes them and passes them to a - list of handlers for processing. - """ - _sentinel = None +if threading: + class QueueListener(object): + """ + This class implements an internal threaded listener which watches for + LogRecords being added to a queue, removes them and passes them to a + list of handlers for processing. + """ + _sentinel = None - def __init__(self, queue, *handlers): - """ - Initialise an instance with the specified queue and - handlers. - """ - self.queue = queue - self.handlers = handlers - self._stop = threading.Event() - self._thread = None + def __init__(self, queue, *handlers): + """ + Initialise an instance with the specified queue and + handlers. + """ + self.queue = queue + self.handlers = handlers + self._stop = threading.Event() + self._thread = None - def dequeue(self, block): - """ - Dequeue a record and return it, optionally blocking. + def dequeue(self, block): + """ + Dequeue 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. - """ - return self.queue.get(block) + The base implementation uses get. You may want to override this method + if you want to use timeouts or work with custom queue implementations. + """ + return self.queue.get(block) - def start(self): - """ - Start the listener. + def start(self): + """ + Start the listener. - This starts up a background thread to monitor the queue for - LogRecords to process. - """ - self._thread = t = threading.Thread(target=self._monitor) - t.setDaemon(True) - t.start() + This starts up a background thread to monitor the queue for + LogRecords to process. + """ + self._thread = t = threading.Thread(target=self._monitor) + t.setDaemon(True) + t.start() - def prepare(self , record): - """ - Prepare a record for handling. + def prepare(self , record): + """ + Prepare a record for handling. - This method 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. - """ - return record + This method 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. + """ + return record - def handle(self, record): - """ - Handle a record. + def handle(self, record): + """ + Handle a record. - This just loops through the handlers offering them the record - to handle. - """ - record = self.prepare(record) - for handler in self.handlers: - handler.handle(record) + This just loops through the handlers offering them the record + to handle. + """ + record = self.prepare(record) + for handler in self.handlers: + handler.handle(record) - def _monitor(self): - """ - Monitor the queue for records, and ask the handler - to deal with them. + def _monitor(self): + """ + Monitor the queue for records, and ask the handler + to deal with them. - This method runs on a separate, internal thread. - The thread will terminate if it sees a sentinel object in the queue. - """ - q = self.queue - has_task_done = hasattr(q, 'task_done') - while not self._stop.isSet(): - try: - record = self.dequeue(True) - if record is self._sentinel: + This method runs on a separate, internal thread. + The thread will terminate if it sees a sentinel object in the queue. + """ + q = self.queue + has_task_done = hasattr(q, 'task_done') + while not self._stop.isSet(): + try: + record = self.dequeue(True) + if record is self._sentinel: + break + self.handle(record) + if has_task_done: + q.task_done() + except queue.Empty: + pass + # There might still be records in the queue. + while True: + try: + record = self.dequeue(False) + if record is self._sentinel: + break + self.handle(record) + if has_task_done: + q.task_done() + except queue.Empty: break - self.handle(record) - if has_task_done: - q.task_done() - except queue.Empty: - pass - # There might still be records in the queue. - while True: - try: - record = self.dequeue(False) - if record is self._sentinel: - break - self.handle(record) - if has_task_done: - q.task_done() - except queue.Empty: - break - def stop(self): - """ - Stop the listener. + def stop(self): + """ + Stop 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. - """ - self._stop.set() - self.queue.put_nowait(self._sentinel) - self._thread.join() - self._thread = None + 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. + """ + self._stop.set() + self.queue.put_nowait(self._sentinel) + self._thread.join() + self._thread = None diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2093,6 +2093,8 @@ self.assertEqual(data.name, self.que_logger.name) self.assertEqual((data.msg, data.args), (msg, None)) + @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'), + 'logging.handlers.QueueListener required for this test') def test_queue_listener(self): handler = TestHandler(Matcher()) listener = logging.handlers.QueueListener(self.queue, handler) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -79,6 +79,8 @@ Library ------- +- logging: don't define QueueListener if Python has no thread support. + - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 16:14:41 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 02 May 2011 16:14:41 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) logging: don't define QueueListener if Python has no thread support Message-ID: http://hg.python.org/cpython/rev/ac1bf4591b5f changeset: 69782:ac1bf4591b5f parent: 69780:7fe328d0fa5f parent: 69781:728e573d7816 user: Victor Stinner date: Mon May 02 16:14:16 2011 +0200 summary: (Merge 3.2) logging: don't define QueueListener if Python has no thread support files: Lib/logging/handlers.py | 200 +++++++++++++------------- Lib/test/test_logging.py | 2 + Misc/NEWS | 2 + 3 files changed, 106 insertions(+), 98 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -27,7 +27,10 @@ import logging, socket, os, pickle, struct, time, re from stat import ST_DEV, ST_INO, ST_MTIME import queue -import threading +try: + import threading +except ImportError: + threading = None try: import codecs @@ -1218,116 +1221,117 @@ except: self.handleError(record) -class QueueListener(object): - """ - This class implements an internal threaded listener which watches for - LogRecords being added to a queue, removes them and passes them to a - list of handlers for processing. - """ - _sentinel = None +if threading: + class QueueListener(object): + """ + This class implements an internal threaded listener which watches for + LogRecords being added to a queue, removes them and passes them to a + list of handlers for processing. + """ + _sentinel = None - def __init__(self, queue, *handlers): - """ - Initialise an instance with the specified queue and - handlers. - """ - self.queue = queue - self.handlers = handlers - self._stop = threading.Event() - self._thread = None + def __init__(self, queue, *handlers): + """ + Initialise an instance with the specified queue and + handlers. + """ + self.queue = queue + self.handlers = handlers + self._stop = threading.Event() + self._thread = None - def dequeue(self, block): - """ - Dequeue a record and return it, optionally blocking. + def dequeue(self, block): + """ + Dequeue 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. - """ - return self.queue.get(block) + The base implementation uses get. You may want to override this method + if you want to use timeouts or work with custom queue implementations. + """ + return self.queue.get(block) - def start(self): - """ - Start the listener. + def start(self): + """ + Start the listener. - This starts up a background thread to monitor the queue for - LogRecords to process. - """ - self._thread = t = threading.Thread(target=self._monitor) - t.setDaemon(True) - t.start() + This starts up a background thread to monitor the queue for + LogRecords to process. + """ + self._thread = t = threading.Thread(target=self._monitor) + t.setDaemon(True) + t.start() - def prepare(self , record): - """ - Prepare a record for handling. + def prepare(self , record): + """ + Prepare a record for handling. - This method 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. - """ - return record + This method 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. + """ + return record - def handle(self, record): - """ - Handle a record. + def handle(self, record): + """ + Handle a record. - This just loops through the handlers offering them the record - to handle. - """ - record = self.prepare(record) - for handler in self.handlers: - handler.handle(record) + This just loops through the handlers offering them the record + to handle. + """ + record = self.prepare(record) + for handler in self.handlers: + handler.handle(record) - def _monitor(self): - """ - Monitor the queue for records, and ask the handler - to deal with them. + def _monitor(self): + """ + Monitor the queue for records, and ask the handler + to deal with them. - This method runs on a separate, internal thread. - The thread will terminate if it sees a sentinel object in the queue. - """ - q = self.queue - has_task_done = hasattr(q, 'task_done') - while not self._stop.isSet(): - try: - record = self.dequeue(True) - if record is self._sentinel: + This method runs on a separate, internal thread. + The thread will terminate if it sees a sentinel object in the queue. + """ + q = self.queue + has_task_done = hasattr(q, 'task_done') + while not self._stop.isSet(): + try: + record = self.dequeue(True) + if record is self._sentinel: + break + self.handle(record) + if has_task_done: + q.task_done() + except queue.Empty: + pass + # There might still be records in the queue. + while True: + try: + record = self.dequeue(False) + if record is self._sentinel: + break + self.handle(record) + if has_task_done: + q.task_done() + except queue.Empty: break - self.handle(record) - if has_task_done: - q.task_done() - except queue.Empty: - pass - # There might still be records in the queue. - while True: - try: - record = self.dequeue(False) - if record is self._sentinel: - break - self.handle(record) - if has_task_done: - q.task_done() - except queue.Empty: - break - def enqueue_sentinel(self): - """ - This is used to enqueue the sentinel record. + def enqueue_sentinel(self): + """ + This is used to enqueue the sentinel record. - The base implementation uses put_nowait. You may want to override this - method if you want to use timeouts or work with custom queue - implementations. - """ - self.queue.put_nowait(self._sentinel) + The base implementation uses put_nowait. You may want to override this + method if you want to use timeouts or work with custom queue + implementations. + """ + self.queue.put_nowait(self._sentinel) - def stop(self): - """ - Stop the listener. + def stop(self): + """ + Stop 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. - """ - self._stop.set() - self.enqueue_sentinel() - self._thread.join() - self._thread = None + 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. + """ + self._stop.set() + self.enqueue_sentinel() + self._thread.join() + self._thread = None diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2634,6 +2634,8 @@ self.assertEqual(data.name, self.que_logger.name) self.assertEqual((data.msg, data.args), (msg, None)) + @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'), + 'logging.handlers.QueueListener required for this test') def test_queue_listener(self): handler = TestHandler(Matcher()) listener = logging.handlers.QueueListener(self.queue, handler) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -132,6 +132,8 @@ Library ------- +- logging: don't define QueueListener if Python has no thread support. + - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 16:17:35 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 02 May 2011 16:17:35 +0200 Subject: [Python-checkins] cpython: cleanup signalmodule.c: use PyModule_AddIntMacro() Message-ID: http://hg.python.org/cpython/rev/edee31e24bda changeset: 69783:edee31e24bda user: Victor Stinner date: Mon May 02 16:15:43 2011 +0200 summary: cleanup signalmodule.c: use PyModule_AddIntMacro() files: Modules/signalmodule.c | 20 ++++++-------------- 1 files changed, 6 insertions(+), 14 deletions(-) diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -720,24 +720,16 @@ Py_DECREF(x); #ifdef SIG_BLOCK - x = PyLong_FromLong(SIG_BLOCK); - if (!x || PyDict_SetItemString(d, "SIG_BLOCK", x) < 0) - goto finally; - Py_DECREF(x); + if (PyModule_AddIntMacro(m, SIG_BLOCK)) + goto finally; #endif - #ifdef SIG_UNBLOCK - x = PyLong_FromLong(SIG_UNBLOCK); - if (!x || PyDict_SetItemString(d, "SIG_UNBLOCK", x) < 0) - goto finally; - Py_DECREF(x); + if (PyModule_AddIntMacro(m, SIG_UNBLOCK)) + goto finally; #endif - #ifdef SIG_SETMASK - x = PyLong_FromLong(SIG_SETMASK); - if (!x || PyDict_SetItemString(d, "SIG_SETMASK", x) < 0) - goto finally; - Py_DECREF(x); + if (PyModule_AddIntMacro(m, SIG_SETMASK)) + goto finally; #endif x = IntHandler = PyDict_GetItemString(d, "default_int_handler"); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 18:31:43 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 02 May 2011 18:31:43 +0200 Subject: [Python-checkins] cpython: Issue #11930: Remove deprecated time.accept2dyear. Message-ID: http://hg.python.org/cpython/rev/e6f6ac8c2502 changeset: 69784:e6f6ac8c2502 parent: 69779:f587197864b0 user: Alexander Belopolsky date: Mon May 02 12:20:52 2011 -0400 summary: Issue #11930: Remove deprecated time.accept2dyear. files: Doc/library/time.rst | 48 +---------------------- Lib/test/test_time.py | 63 ++---------------------------- Modules/timemodule.c | 55 +-------------------------- 3 files changed, 9 insertions(+), 157 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -41,25 +41,6 @@ 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 single: Coordinated Universal Time @@ -117,24 +98,6 @@ The module defines the following functions and data items: - -.. data:: accept2dyear - - 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 The offset of the local DST timezone, in seconds west of UTC, if one is defined. @@ -308,7 +271,7 @@ | ``%y`` | Year without century as a decimal number | | | | [00,99]. | | +-----------+------------------------------------------------+-------+ - | ``%Y`` | Year with century as a decimal number. | \(4) | + | ``%Y`` | Year with century as a decimal number. | | | | | | +-----------+------------------------------------------------+-------+ | ``%Z`` | Time zone name (no characters if no time zone | | @@ -332,12 +295,6 @@ 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. [#]_ :: @@ -418,8 +375,7 @@ +-------+-------------------+---------------------------------+ Note that unlike the C structure, the month value is a range of [1, 12], not - [0, 11]. A year value will be handled as described under :ref:`Year 2000 - (Y2K) issues ` above. A ``-1`` argument as the daylight + [0, 11]. A ``-1`` argument as the daylight savings flag, passed to :func:`mktime` will usually result in the correct daylight savings state to be filled in. diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -96,12 +96,13 @@ self._bounds_checking(lambda tup: time.strftime('', tup)) def test_default_values_for_zero(self): - # Make sure that using all zeros uses the proper default values. - # No test for daylight savings since strftime() does not change output - # based on its value. + # Make sure that using all zeros uses the proper default + # values. No test for daylight savings since strftime() does + # not change output based on its value and no test for year + # because systems vary in their support for year 0. expected = "2000 01 01 00 00 00 1 001" with support.check_warnings(): - result = time.strftime("%Y %m %d %H %M %S %w %j", (0,)*9) + result = time.strftime("%Y %m %d %H %M %S %w %j", (2000,)+(0,)*8) self.assertEqual(expected, result) def test_strptime(self): @@ -271,15 +272,6 @@ class _BaseYearTest(unittest.TestCase): - accept2dyear = None - - def setUp(self): - self.saved_accept2dyear = time.accept2dyear - time.accept2dyear = self.accept2dyear - - def tearDown(self): - time.accept2dyear = self.saved_accept2dyear - def yearstr(self, y): raise NotImplementedError() @@ -306,23 +298,7 @@ self.assertEqual(text, '12345') self.assertEqual(self.yearstr(123456789), '123456789') -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') - self.assertEqual(self.yearstr(68), '2068') - self.assertEqual(self.yearstr(99), '1999') - - def test_invalid(self): - self.assertRaises(ValueError, self.yearstr, -1) - self.assertRaises(ValueError, self.yearstr, 100) - self.assertRaises(ValueError, self.yearstr, 999) - class _Test4dYear(_BaseYearTest): - accept2dyear = 0 def test_year(self): self.assertIn(self.yearstr(1), ('1', '0001')) @@ -361,46 +337,19 @@ except OverflowError: pass -class TestAsctimeAccept2dYear(_TestAsctimeYear, _Test2dYear): - pass - -class TestStrftimeAccept2dYear(_TestStrftimeYear, _Test2dYear): - pass - class TestAsctime4dyear(_TestAsctimeYear, _Test4dYear): pass class TestStrftime4dyear(_TestStrftimeYear, _Test4dYear): pass -class Test2dyearBool(_TestAsctimeYear, _Test2dYear): - accept2dyear = True - -class Test4dyearBool(_TestAsctimeYear, _Test4dYear): - accept2dyear = False - -class TestAccept2YearBad(_TestAsctimeYear, _BaseYearTest): - 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) - def test_main(): support.run_unittest( TimeTestCase, TestLocale, - TestAsctimeAccept2dYear, - TestStrftimeAccept2dYear, TestAsctime4dyear, - TestStrftime4dyear, - Test2dyearBool, - Test4dyearBool, - TestAccept2YearBad) + TestStrftime4dyear) if __name__ == "__main__": test_main() diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -66,9 +66,6 @@ static int floatsleep(double); static double floattime(void); -/* For Y2K check */ -static PyObject *moddict; - static PyObject * time_time(PyObject *self, PyObject *unused) { @@ -311,49 +308,6 @@ &p->tm_hour, &p->tm_min, &p->tm_sec, &p->tm_wday, &p->tm_yday, &p->tm_isdst)) return 0; - - /* 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 < 1000) { - PyObject *accept = PyDict_GetItemString(moddict, - "accept2dyear"); - 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; - } - } - else - return 0; - } p->tm_year = y - 1900; p->tm_mon--; p->tm_wday = (p->tm_wday + 1) % 7; @@ -863,7 +817,7 @@ \n\ The other representation is a tuple of 9 integers giving local time.\n\ The tuple items are:\n\ - year (four digits, e.g. 1998)\n\ + year (including century, e.g. 1998)\n\ month (1-12)\n\ day (1-31)\n\ hours (0-23)\n\ @@ -920,13 +874,6 @@ if (m == NULL) return NULL; - /* Accept 2-digit dates unless PYTHONY2K is set and non-empty */ - p = Py_GETENV("PYTHONY2K"); - PyModule_AddIntConstant(m, "accept2dyear", (long) (!p || !*p)); - /* Squirrel away the module's dictionary for the y2k check */ - moddict = PyModule_GetDict(m); - Py_INCREF(moddict); - /* Set, or reset, module variables like time.timezone */ PyInit_timezone(m); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 18:31:45 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 02 May 2011 18:31:45 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge Message-ID: http://hg.python.org/cpython/rev/2e3346fc880f changeset: 69785:2e3346fc880f parent: 69784:e6f6ac8c2502 parent: 69783:edee31e24bda user: Alexander Belopolsky date: Mon May 02 12:31:17 2011 -0400 summary: merge files: Lib/logging/handlers.py | 200 +++++++++++++------------- Lib/test/test_logging.py | 7 +- Misc/NEWS | 2 + Modules/signalmodule.c | 20 +- 4 files changed, 116 insertions(+), 113 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -27,7 +27,10 @@ import logging, socket, os, pickle, struct, time, re from stat import ST_DEV, ST_INO, ST_MTIME import queue -import threading +try: + import threading +except ImportError: + threading = None try: import codecs @@ -1218,116 +1221,117 @@ except: self.handleError(record) -class QueueListener(object): - """ - This class implements an internal threaded listener which watches for - LogRecords being added to a queue, removes them and passes them to a - list of handlers for processing. - """ - _sentinel = None +if threading: + class QueueListener(object): + """ + This class implements an internal threaded listener which watches for + LogRecords being added to a queue, removes them and passes them to a + list of handlers for processing. + """ + _sentinel = None - def __init__(self, queue, *handlers): - """ - Initialise an instance with the specified queue and - handlers. - """ - self.queue = queue - self.handlers = handlers - self._stop = threading.Event() - self._thread = None + def __init__(self, queue, *handlers): + """ + Initialise an instance with the specified queue and + handlers. + """ + self.queue = queue + self.handlers = handlers + self._stop = threading.Event() + self._thread = None - def dequeue(self, block): - """ - Dequeue a record and return it, optionally blocking. + def dequeue(self, block): + """ + Dequeue 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. - """ - return self.queue.get(block) + The base implementation uses get. You may want to override this method + if you want to use timeouts or work with custom queue implementations. + """ + return self.queue.get(block) - def start(self): - """ - Start the listener. + def start(self): + """ + Start the listener. - This starts up a background thread to monitor the queue for - LogRecords to process. - """ - self._thread = t = threading.Thread(target=self._monitor) - t.setDaemon(True) - t.start() + This starts up a background thread to monitor the queue for + LogRecords to process. + """ + self._thread = t = threading.Thread(target=self._monitor) + t.setDaemon(True) + t.start() - def prepare(self , record): - """ - Prepare a record for handling. + def prepare(self , record): + """ + Prepare a record for handling. - This method 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. - """ - return record + This method 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. + """ + return record - def handle(self, record): - """ - Handle a record. + def handle(self, record): + """ + Handle a record. - This just loops through the handlers offering them the record - to handle. - """ - record = self.prepare(record) - for handler in self.handlers: - handler.handle(record) + This just loops through the handlers offering them the record + to handle. + """ + record = self.prepare(record) + for handler in self.handlers: + handler.handle(record) - def _monitor(self): - """ - Monitor the queue for records, and ask the handler - to deal with them. + def _monitor(self): + """ + Monitor the queue for records, and ask the handler + to deal with them. - This method runs on a separate, internal thread. - The thread will terminate if it sees a sentinel object in the queue. - """ - q = self.queue - has_task_done = hasattr(q, 'task_done') - while not self._stop.isSet(): - try: - record = self.dequeue(True) - if record is self._sentinel: + This method runs on a separate, internal thread. + The thread will terminate if it sees a sentinel object in the queue. + """ + q = self.queue + has_task_done = hasattr(q, 'task_done') + while not self._stop.isSet(): + try: + record = self.dequeue(True) + if record is self._sentinel: + break + self.handle(record) + if has_task_done: + q.task_done() + except queue.Empty: + pass + # There might still be records in the queue. + while True: + try: + record = self.dequeue(False) + if record is self._sentinel: + break + self.handle(record) + if has_task_done: + q.task_done() + except queue.Empty: break - self.handle(record) - if has_task_done: - q.task_done() - except queue.Empty: - pass - # There might still be records in the queue. - while True: - try: - record = self.dequeue(False) - if record is self._sentinel: - break - self.handle(record) - if has_task_done: - q.task_done() - except queue.Empty: - break - def enqueue_sentinel(self): - """ - This is used to enqueue the sentinel record. + def enqueue_sentinel(self): + """ + This is used to enqueue the sentinel record. - The base implementation uses put_nowait. You may want to override this - method if you want to use timeouts or work with custom queue - implementations. - """ - self.queue.put_nowait(self._sentinel) + The base implementation uses put_nowait. You may want to override this + method if you want to use timeouts or work with custom queue + implementations. + """ + self.queue.put_nowait(self._sentinel) - def stop(self): - """ - Stop the listener. + def stop(self): + """ + Stop 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. - """ - self._stop.set() - self.enqueue_sentinel() - self._thread.join() - self._thread = None + 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. + """ + self._stop.set() + self.enqueue_sentinel() + self._thread.join() + self._thread = None diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1385,7 +1385,10 @@ logger = logging.getLogger("udp") logger.error("spam") self.handled.wait() - self.assertEqual(self.log_output, "spam\n") + self.handled.clear() + logger.error("eggs") + self.handled.wait() + self.assertEqual(self.log_output, "spam\neggs\n") @unittest.skipUnless(threading, 'Threading required for this test.') @@ -2631,6 +2634,8 @@ self.assertEqual(data.name, self.que_logger.name) self.assertEqual((data.msg, data.args), (msg, None)) + @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'), + 'logging.handlers.QueueListener required for this test') def test_queue_listener(self): handler = TestHandler(Matcher()) listener = logging.handlers.QueueListener(self.queue, handler) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -132,6 +132,8 @@ Library ------- +- logging: don't define QueueListener if Python has no thread support. + - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -720,24 +720,16 @@ Py_DECREF(x); #ifdef SIG_BLOCK - x = PyLong_FromLong(SIG_BLOCK); - if (!x || PyDict_SetItemString(d, "SIG_BLOCK", x) < 0) - goto finally; - Py_DECREF(x); + if (PyModule_AddIntMacro(m, SIG_BLOCK)) + goto finally; #endif - #ifdef SIG_UNBLOCK - x = PyLong_FromLong(SIG_UNBLOCK); - if (!x || PyDict_SetItemString(d, "SIG_UNBLOCK", x) < 0) - goto finally; - Py_DECREF(x); + if (PyModule_AddIntMacro(m, SIG_UNBLOCK)) + goto finally; #endif - #ifdef SIG_SETMASK - x = PyLong_FromLong(SIG_SETMASK); - if (!x || PyDict_SetItemString(d, "SIG_SETMASK", x) < 0) - goto finally; - Py_DECREF(x); + if (PyModule_AddIntMacro(m, SIG_SETMASK)) + goto finally; #endif x = IntHandler = PyDict_GetItemString(d, "default_int_handler"); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 18:53:49 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 02 May 2011 18:53:49 +0200 Subject: [Python-checkins] cpython (3.2): Backport code cleanup for namedtuples. Message-ID: http://hg.python.org/cpython/rev/b312f8f512a9 changeset: 69786:b312f8f512a9 branch: 3.2 parent: 69781:728e573d7816 user: Raymond Hettinger date: Mon May 02 09:50:15 2011 -0700 summary: Backport code cleanup for namedtuples. files: Lib/collections.py | 133 +++++++++++++++++++------------- 1 files changed, 80 insertions(+), 53 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -236,10 +236,62 @@ ### namedtuple ################################################################################ +_class_template = '''\ +from builtins import property as _property, tuple as _tuple +from operator import itemgetter as _itemgetter +from collections import OrderedDict + +class {typename}(tuple): + '{typename}({arg_list})' + + __slots__ = () + + _fields = {field_names!r} + + def __new__(_cls, {arg_list}): + 'Create new instance of {typename}({arg_list})' + return _tuple.__new__(_cls, ({arg_list})) + + @classmethod + def _make(cls, iterable, new=tuple.__new__, len=len): + 'Make a new {typename} object from a sequence or iterable' + result = new(cls, iterable) + if len(result) != {num_fields:d}: + raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result)) + return result + + def __repr__(self): + 'Return a nicely formatted representation string' + return self.__class__.__name__ + '({repr_fmt})' % self + + def _asdict(self): + 'Return a new OrderedDict which maps field names to their values' + return OrderedDict(zip(self._fields, self)) + + def _replace(_self, **kwds): + 'Return a new {typename} object replacing specified fields with new values' + result = _self._make(map(kwds.pop, {field_names!r}, _self)) + if kwds: + raise ValueError('Got unexpected field names: %r' % list(kwds)) + return result + + def __getnewargs__(self): + 'Return self as a plain tuple. Used by copy and pickle.' + return tuple(self) + +{field_defs} +''' + +_repr_template = '{name}=%r' + +_field_template = '''\ + {name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}') +''' + def namedtuple(typename, field_names, verbose=False, rename=False): """Returns a new subclass of tuple with named fields. - >>> Point = namedtuple('Point', 'x y') + >>> Point = namedtuple('Point', ['x', 'y']) >>> Point.__doc__ # docstring for the new class 'Point(x, y)' >>> p = Point(11, y=22) # instantiate with positional args or keywords @@ -264,79 +316,54 @@ # generating informative error messages and preventing template injection attacks. if isinstance(field_names, str): field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas - field_names = tuple(map(str, field_names)) + field_names = list(map(str, field_names)) if rename: - names = list(field_names) seen = set() - for i, name in enumerate(names): - if (not all(c.isalnum() or c=='_' for c in name) or _iskeyword(name) - or not name or name[0].isdigit() or name.startswith('_') + for index, name in enumerate(field_names): + if (not all(c.isalnum() or c=='_' for c in name) + or _iskeyword(name) + or not name + or name[0].isdigit() + or name.startswith('_') or name in seen): - names[i] = '_%d' % i + field_names[index] = '_%d' % index seen.add(name) - field_names = tuple(names) - for name in (typename,) + field_names: + for name in [typename] + field_names: if not all(c.isalnum() or c=='_' for c in name): raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name) if _iskeyword(name): raise ValueError('Type names and field names cannot be a keyword: %r' % name) if name[0].isdigit(): raise ValueError('Type names and field names cannot start with a number: %r' % name) - seen_names = set() + seen = set() for name in field_names: if name.startswith('_') and not rename: raise ValueError('Field names cannot start with an underscore: %r' % name) - if name in seen_names: + if name in seen: raise ValueError('Encountered duplicate field name: %r' % name) - seen_names.add(name) + seen.add(name) - # Create and fill-in the class template - numfields = len(field_names) - argtxt = repr(field_names).replace("'", "")[1:-1] # tuple repr without parens or quotes - reprtxt = ', '.join('%s=%%r' % name for name in field_names) - template = '''class %(typename)s(tuple): - '%(typename)s(%(argtxt)s)' \n - __slots__ = () \n - _fields = %(field_names)r \n - def __new__(_cls, %(argtxt)s): - 'Create new instance of %(typename)s(%(argtxt)s)' - return _tuple.__new__(_cls, (%(argtxt)s)) \n - @classmethod - def _make(cls, iterable, new=tuple.__new__, len=len): - 'Make a new %(typename)s object from a sequence or iterable' - result = new(cls, iterable) - if len(result) != %(numfields)d: - raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result)) - return result \n - def __repr__(self): - 'Return a nicely formatted representation string' - return self.__class__.__name__ + '(%(reprtxt)s)' %% self \n - def _asdict(self): - 'Return a new OrderedDict which maps field names to their values' - return OrderedDict(zip(self._fields, self)) \n - def _replace(_self, **kwds): - 'Return a new %(typename)s object replacing specified fields with new values' - result = _self._make(map(kwds.pop, %(field_names)r, _self)) - if kwds: - raise ValueError('Got unexpected field names: %%r' %% kwds.keys()) - return result \n - def __getnewargs__(self): - 'Return self as a plain tuple. Used by copy and pickle.' - return tuple(self) \n\n''' % locals() - for i, name in enumerate(field_names): - template += " %s = _property(_itemgetter(%d), doc='Alias for field number %d')\n" % (name, i, i) - if verbose: - print(template) + # Fill-in the class template + class_definition = _class_template.format( + typename = typename, + field_names = tuple(field_names), + num_fields = len(field_names), + arg_list = repr(tuple(field_names)).replace("'", "")[1:-1], + repr_fmt = ', '.join(_repr_template.format(name=name) for name in field_names), + field_defs = '\n'.join(_field_template.format(index=index, name=name) + for index, name in enumerate(field_names)) + ) # Execute the template string in a temporary namespace and # support tracing utilities by setting a value for frame.f_globals['__name__'] - namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, - OrderedDict=OrderedDict, _property=property, _tuple=tuple) + namespace = dict(__name__='namedtuple_%s' % typename) try: - exec(template, namespace) + exec(class_definition, namespace) except SyntaxError as e: - raise SyntaxError(e.msg + ':\n\n' + template) + raise SyntaxError(e.msg + ':\n\n' + class_definition) result = namespace[typename] + if verbose: + print(class_definition) # For pickling to work, the __module__ variable needs to be set to the frame # where the named tuple is created. Bypass this step in enviroments where -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 18:53:50 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 02 May 2011 18:53:50 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): dummy merge Message-ID: http://hg.python.org/cpython/rev/d62d107a61e7 changeset: 69787:d62d107a61e7 parent: 69785:2e3346fc880f parent: 69786:b312f8f512a9 user: Raymond Hettinger date: Mon May 02 09:53:36 2011 -0700 summary: dummy merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 19:14:47 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 02 May 2011 19:14:47 +0200 Subject: [Python-checkins] cpython: Issue #11930: Remove year >= 1000 limitation from datetime.strftime. Message-ID: http://hg.python.org/cpython/rev/db2ac3dc6cc2 changeset: 69788:db2ac3dc6cc2 user: Alexander Belopolsky date: Mon May 02 13:14:24 2011 -0400 summary: Issue #11930: Remove year >= 1000 limitation from datetime.strftime. Patch by Victor Stinner. files: Doc/library/datetime.rst | 8 ++------ Lib/datetime.py | 4 ---- Lib/test/datetimetester.py | 10 ++++------ Modules/_datetimemodule.c | 25 ------------------------- 4 files changed, 6 insertions(+), 41 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1750,8 +1750,7 @@ | | decimal number [00,99]. | | +-----------+--------------------------------+-------+ | ``%Y`` | Year with century as a decimal | \(5) | -| | number [0001,9999] (strptime), | | -| | [1000,9999] (strftime). | | +| | number [0001,9999]. | | +-----------+--------------------------------+-------+ | ``%z`` | UTC offset in the form +HHMM | \(6) | | | or -HHMM (empty string if the | | @@ -1785,10 +1784,7 @@ 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 + The :meth:`strptime` method can parse years in the full [1, 9999] range, but years < 1000 must be zero-filled to 4-digit width. diff --git a/Lib/datetime.py b/Lib/datetime.py --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -172,10 +172,6 @@ # Correctly substitute for %z and %Z escapes in strftime formats. def _wrap_strftime(object, format, timetuple): - year = timetuple[0] - 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 diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1289,12 +1289,10 @@ self.assertTrue(self.theclass.min) self.assertTrue(self.theclass.max) - def test_strftime_out_of_range(self): - # For nasty technical reasons, we can't handle years before 1000. - cls = self.theclass - 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_strftime_y2k(self): + for y in (1, 49, 70, 99, 100, 999, 1000, 1970): + self.assertEqual(self.theclass(y, 1, 1).strftime("%Y"), + '%04d' % y) def test_replace(self): cls = self.theclass diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1166,31 +1166,6 @@ if (!pin) return NULL; - /* 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 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 - * an option in the Python implementation of this module. - */ - { - long year; - PyObject *pyyear = PySequence_GetItem(timetuple, 0); - if (pyyear == NULL) return NULL; - assert(PyLong_Check(pyyear)); - year = PyLong_AsLong(pyyear); - Py_DECREF(pyyear); - if (year < 1000) { - PyErr_Format(PyExc_ValueError, "year=%ld is before " - "1000; the datetime strftime() " - "methods require year >= 1000", - year); - return NULL; - } - } - /* Scan the input format, looking for %z/%Z/%f escapes, building * a new format. Since computing the replacements for those codes * is expensive, don't unless they're actually used. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 19:44:40 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 02 May 2011 19:44:40 +0200 Subject: [Python-checkins] cpython: Removed unused variable Message-ID: http://hg.python.org/cpython/rev/52e794d80bb4 changeset: 69789:52e794d80bb4 user: Alexander Belopolsky date: Mon May 02 13:44:20 2011 -0400 summary: Removed unused variable files: Modules/timemodule.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -869,7 +869,6 @@ PyInit_time(void) { PyObject *m; - char *p; m = PyModule_Create(&timemodule); if (m == NULL) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 19:48:34 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 02 May 2011 19:48:34 +0200 Subject: [Python-checkins] cpython: Relax %Y test. Message-ID: http://hg.python.org/cpython/rev/777f4bb3ec3b changeset: 69790:777f4bb3ec3b user: Alexander Belopolsky date: Mon May 02 13:48:09 2011 -0400 summary: Relax %Y test. files: Lib/test/datetimetester.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1291,8 +1291,8 @@ def test_strftime_y2k(self): for y in (1, 49, 70, 99, 100, 999, 1000, 1970): - self.assertEqual(self.theclass(y, 1, 1).strftime("%Y"), - '%04d' % y) + self.assertIn(self.theclass(y, 1, 1).strftime("%Y"), + [str(y),'%04d' % y]) def test_replace(self): cls = self.theclass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 20:03:46 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 02 May 2011 20:03:46 +0200 Subject: [Python-checkins] cpython (3.2): Backport 3.3 fixes and cleans ups. Message-ID: http://hg.python.org/cpython/rev/bb58d777eaa9 changeset: 69791:bb58d777eaa9 branch: 3.2 parent: 69786:b312f8f512a9 user: Raymond Hettinger date: Mon May 02 11:02:13 2011 -0700 summary: Backport 3.3 fixes and cleans ups. files: Lib/collections.py | 3 ++ Lib/test/test_collections.py | 30 +++++++++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -716,6 +716,9 @@ def __contains__(self, key): return any(key in m for m in self.maps) + def __bool__(self): + return any(self.maps) + @_recursive_repr() def __repr__(self): return '{0.__class__.__name__}({1})'.format( diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -23,10 +23,12 @@ ### _ChainMap (helper class for configparser) ################################################################################ +ChainMap = _ChainMap # rename to keep test code in sync with 3.3 version + class TestChainMap(unittest.TestCase): def test_basics(self): - c = _ChainMap() + c = ChainMap() c['a'] = 1 c['b'] = 2 d = c.new_child() @@ -71,19 +73,25 @@ for m1, m2 in zip(d.maps, e.maps): self.assertIsNot(m1, m2, e) - d = d.new_child() - d['b'] = 5 - self.assertEqual(d.maps, [{'b': 5}, {'c':30}, {'a':1, 'b':2}]) - self.assertEqual(d.parents.maps, [{'c':30}, {'a':1, 'b':2}]) # check parents - self.assertEqual(d['b'], 5) # find first in chain - self.assertEqual(d.parents['b'], 2) # look beyond maps[0] + f = d.new_child() + f['b'] = 5 + self.assertEqual(f.maps, [{'b': 5}, {'c':30}, {'a':1, 'b':2}]) + self.assertEqual(f.parents.maps, [{'c':30}, {'a':1, 'b':2}]) # check parents + self.assertEqual(f['b'], 5) # find first in chain + self.assertEqual(f.parents['b'], 2) # look beyond maps[0] def test_contructor(self): - self.assertEqual(_ChainMap().maps, [{}]) # no-args --> one new dict - self.assertEqual(_ChainMap({1:2}).maps, [{1:2}]) # 1 arg --> list + self.assertEqual(ChainMap().maps, [{}]) # no-args --> one new dict + self.assertEqual(ChainMap({1:2}).maps, [{1:2}]) # 1 arg --> list + + def test_bool(self): + self.assertFalse(ChainMap()) + self.assertFalse(ChainMap({}, {})) + self.assertTrue(ChainMap({1:2}, {})) + self.assertTrue(ChainMap({}, {1:2})) def test_missing(self): - class DefaultChainMap(_ChainMap): + class DefaultChainMap(ChainMap): def __missing__(self, key): return 999 d = DefaultChainMap(dict(a=1, b=2), dict(b=20, c=30)) @@ -100,7 +108,7 @@ d.popitem() def test_dict_coercion(self): - d = _ChainMap(dict(a=1, b=2), dict(b=20, c=30)) + d = ChainMap(dict(a=1, b=2), dict(b=20, c=30)) self.assertEqual(dict(d), dict(a=1, b=2, c=30)) self.assertEqual(dict(d.items()), dict(a=1, b=2, c=30)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 20:03:47 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 02 May 2011 20:03:47 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/1d07820d66e9 changeset: 69792:1d07820d66e9 parent: 69790:777f4bb3ec3b parent: 69791:bb58d777eaa9 user: Raymond Hettinger date: Mon May 02 11:03:37 2011 -0700 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 2 20:15:12 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 02 May 2011 20:15:12 +0200 Subject: [Python-checkins] cpython: Issue #11930: Added Misc/NEWS and versionchanged entries. Message-ID: http://hg.python.org/cpython/rev/bfd741162741 changeset: 69793:bfd741162741 user: Alexander Belopolsky date: Mon May 02 14:14:48 2011 -0400 summary: Issue #11930: Added Misc/NEWS and versionchanged entries. files: Doc/library/datetime.rst | 4 ++++ Misc/NEWS | 3 +++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1792,6 +1792,10 @@ In previous versions, :meth:`strftime` method was restricted to years >= 1900. + .. versionchanged:: 3.3 + In version 3.2, :meth:`strftime` method was restricted to + years >= 1000. + (6) For example, if :meth:`utcoffset` returns ``timedelta(hours=-3, minutes=-30)``, ``%z`` is replaced with the string ``'-0330'``. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -132,6 +132,9 @@ Library ------- +- Issue #11930: Removed deprecated time.accept2dyear variable. + Removed year >= 1000 restriction from datetime.strftime. + - logging: don't define QueueListener if Python has no thread support. - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 02:36:15 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 03 May 2011 02:36:15 +0200 Subject: [Python-checkins] peps: Add Windows 2000 and support of COMSPEC->command.com environments. Message-ID: http://hg.python.org/peps/rev/b9390aa12855 changeset: 3872:b9390aa12855 user: Brian Curtin date: Mon May 02 19:35:58 2011 -0500 summary: Add Windows 2000 and support of COMSPEC->command.com environments. files: pep-0011.txt | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/pep-0011.txt b/pep-0011.txt --- a/pep-0011.txt +++ b/pep-0011.txt @@ -172,6 +172,14 @@ Unsupported in: Python 3.3 Code removed in: Python 3.4 + Name: Windows 2000 + Unsupported in: Python 3.3 + Code removed in: Python 3.4 + + Name: Windows systems where COMSPEC points to command.com + Unsupported in: Python 3.3 + Code removed in: Python 3.4 + Platform Maintainers Cygwin Jason Tishler (jason at tishler.net) -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Tue May 3 04:57:58 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 03 May 2011 04:57:58 +0200 Subject: [Python-checkins] Daily reference leaks (bfd741162741): sum=0 Message-ID: results for bfd741162741 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogvePQ24', '-x'] From python-checkins at python.org Tue May 3 05:30:25 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 03 May 2011 05:30:25 +0200 Subject: [Python-checkins] cpython: Adjust OS/2 & VMS grammar, and add Windows 2000 to the unsupported list. Message-ID: http://hg.python.org/cpython/rev/d074f18291f7 changeset: 69794:d074f18291f7 user: Brian Curtin date: Mon May 02 22:30:06 2011 -0500 summary: Adjust OS/2 & VMS grammar, and add Windows 2000 to the unsupported list. files: Doc/whatsnew/3.3.rst | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -148,7 +148,10 @@ Unsupported Operating Systems ============================= -OS/2 and VMS are no more supported because of the lack of a maintainer. +OS/2 and VMS are no longer supported due to the lack of a maintainer. + +Windows 2000 and Windows platforms which set ``COMSPEC`` to ``command.com`` +are no longer supported due to maintenance burden. Porting to Python 3.3 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 14:11:51 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 May 2011 14:11:51 +0200 Subject: [Python-checkins] cpython: Issue #8407: Fix pthread_sigmask() tests on Mac OS X Message-ID: http://hg.python.org/cpython/rev/d003ce770ba1 changeset: 69795:d003ce770ba1 user: Victor Stinner date: Tue May 03 14:11:22 2011 +0200 summary: Issue #8407: Fix pthread_sigmask() tests on Mac OS X Disable faulthandler timeout thread on Mac OS X: it interacts with pthread_sigmask() tests. files: Lib/test/test_signal.py | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -504,6 +504,21 @@ def read_sigmask(): return signal.pthread_sigmask(signal.SIG_BLOCK, []) + if sys.platform == "darwin": + import faulthandler + # The fault handler timeout thread masks all signals. If the main + # thread masks also SIGUSR1, all threads mask this signal. In this + # case, on Mac OS X, if we send SIGUSR1 to the process, the signal + # is pending in the main or the faulthandler timeout thread. + # Unblock SIGUSR1 in the main thread calls the signal handler only + # if the signal is pending for the main thread. + # + # Stop the faulthandler timeout thread to workaround this problem. + # Another solution would be to send the signal directly to the main + # thread using pthread_kill(), but Python doesn't expose this + # function. + faulthandler.cancel_dump_tracebacks_later() + old_handler = signal.signal(signum, handler) self.addCleanup(signal.signal, signum, old_handler) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 14:36:43 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 May 2011 14:36:43 +0200 Subject: [Python-checkins] cpython (2.7): (Merge 3.1) Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X Message-ID: http://hg.python.org/cpython/rev/618c3e971e80 changeset: 69796:618c3e971e80 branch: 2.7 parent: 69774:a13310c045b0 user: Victor Stinner date: Tue May 03 14:36:36 2011 +0200 summary: (Merge 3.1) Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. files: Doc/library/mmap.rst | 4 ++++ Misc/NEWS | 3 +++ Modules/mmapmodule.c | 9 +++++++++ 3 files changed, 16 insertions(+), 0 deletions(-) diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -94,6 +94,10 @@ defaults to 0. *offset* must be a multiple of the PAGESIZE or ALLOCATIONGRANULARITY. + To ensure validity of the created memory mapping the file specified + by the descriptor *fileno* is internally automatically synchronized + with physical backing store on Mac OS X and OpenVMS. + This example shows a simple way of using :class:`mmap`:: import mmap diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -70,6 +70,9 @@ Library ------- +- Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get + around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. + - Issue #10761: Fix tarfile.extractall failure when symlinked files are present. Initial patch by Scott Leerssen. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -23,6 +23,9 @@ #ifndef MS_WINDOWS #define UNIX +# ifdef __APPLE__ +# include +# endif #endif #ifdef MS_WINDOWS @@ -1170,6 +1173,12 @@ "mmap invalid access parameter."); } +#ifdef __APPLE__ + /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific + fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */ + if (fd != -1) + (void)fcntl(fd, F_FULLFSYNC); +#endif #ifdef HAVE_FSTAT # ifdef __VMS /* on OpenVMS we must ensure that all bytes are written to the file */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 14:57:18 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 May 2011 14:57:18 +0200 Subject: [Python-checkins] cpython: Issue #8407: pthread_sigmask() checks immediatly if signal handlers have been Message-ID: http://hg.python.org/cpython/rev/c9207c6ce24a changeset: 69797:c9207c6ce24a parent: 69795:d003ce770ba1 user: Victor Stinner date: Tue May 03 14:57:12 2011 +0200 summary: Issue #8407: pthread_sigmask() checks immediatly if signal handlers have been called. The test checks that SIG_UNBLOCK calls immediatly the signal handler of the pending SIGUSR1. Improve also the tests using an exception (division by zero) instead of a flag (a function attribute). files: Lib/test/test_signal.py | 30 +++++++++++++++------------- Modules/signalmodule.c | 4 +++ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -498,8 +498,7 @@ signum = signal.SIGUSR1 def handler(signum, frame): - handler.tripped = True - handler.tripped = False + 1/0 def read_sigmask(): return signal.pthread_sigmask(signal.SIG_BLOCK, []) @@ -519,36 +518,39 @@ # function. faulthandler.cancel_dump_tracebacks_later() + # Install our signal handler old_handler = signal.signal(signum, handler) self.addCleanup(signal.signal, signum, old_handler) - # unblock SIGUSR1, copy the old mask and test our signal handler + # Unblock SIGUSR1 (and copy the old mask) to test our signal handler old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, old_mask) - os.kill(pid, signum) - self.assertTrue(handler.tripped) + with self.assertRaises(ZeroDivisionError): + os.kill(pid, signum) - # block SIGUSR1 - handler.tripped = False + # Block and then raise SIGUSR1. The signal is blocked: the signal + # handler is not called, and the signal is now pending signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) os.kill(pid, signum) - self.assertFalse(handler.tripped) - # check the mask + # Check the new mask blocked = read_sigmask() self.assertIn(signum, blocked) self.assertEqual(set(old_mask) ^ set(blocked), {signum}) - # unblock SIGUSR1 - signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) - os.kill(pid, signum) - self.assertTrue(handler.tripped) + # Unblock SIGUSR1 + with self.assertRaises(ZeroDivisionError): + # unblock the pending signal calls immediatly the signal handler + signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + with self.assertRaises(ZeroDivisionError): + os.kill(pid, signum) - # check the mask + # Check the new mask unblocked = read_sigmask() self.assertNotIn(signum, unblocked) self.assertEqual(set(blocked) ^ set(unblocked), {signum}) self.assertSequenceEqual(old_mask, unblocked) + # Finally, restore the previous signal handler and the signal mask def test_main(): diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -573,6 +573,10 @@ return NULL; } + /* if signals was unblocked, signal handlers have been called */ + if (PyErr_CheckSignals()) + return NULL; + result = PyList_New(0); if (result == NULL) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 15:08:12 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 May 2011 15:08:12 +0200 Subject: [Python-checkins] cpython (2.7): Issue #8651: Fix "z#" format of PyArg_Parse*() function: the size was not Message-ID: http://hg.python.org/cpython/rev/509f1c15a1e1 changeset: 69798:509f1c15a1e1 branch: 2.7 parent: 69796:618c3e971e80 user: Victor Stinner date: Tue May 03 15:06:11 2011 +0200 summary: Issue #8651: Fix "z#" format of PyArg_Parse*() function: the size was not written if PY_SSIZE_T_CLEAN is defined. files: Misc/NEWS | 3 +++ Python/getargs.c | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #8651: Fix "z#" format of PyArg_Parse*() function: the size was not + written if PY_SSIZE_T_CLEAN is defined. + - Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. Fix a crash if a class override its __class__ attribute (e.g. a proxy of the diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -984,10 +984,11 @@ if (*format == '#') { FETCH_SIZE; assert(0); /* XXX redundant with if-case */ - if (arg == Py_None) - *q = 0; - else - *q = PyString_Size(arg); + if (arg == Py_None) { + STORE_SIZE(0); + } else { + STORE_SIZE(PyString_Size(arg)); + } format++; } else if (*p != NULL && -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 15:09:31 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 May 2011 15:09:31 +0200 Subject: [Python-checkins] cpython (2.7): Issue #8651: PyArg_Parse*() functions raise an OverflowError if the file Message-ID: http://hg.python.org/cpython/rev/a0681e7a6ded changeset: 69799:a0681e7a6ded branch: 2.7 user: Victor Stinner date: Tue May 03 15:09:24 2011 +0200 summary: 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). files: Lib/test/test_xml_etree_c.py | 16 ++++++++++++++++ Misc/NEWS | 4 ++++ Python/getargs.c | 12 +++++++++++- 3 files changed, 31 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -1,6 +1,8 @@ # xml.etree test for cElementTree from test import test_support +from test.test_support import precisionbigmemtest, _2G +import unittest cET = test_support.import_module('xml.etree.cElementTree') @@ -15,6 +17,20 @@ """ +class MiscTests(unittest.TestCase): + # Issue #8651. + @precisionbigmemtest(size=_2G + 100, memuse=1) + def test_length_overflow(self, size): + if size < _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 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,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 #8651: Fix "z#" format of PyArg_Parse*() function: the size was not written if PY_SSIZE_T_CLEAN is defined. diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -585,7 +585,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; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 15:19:34 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 May 2011 15:19:34 +0200 Subject: [Python-checkins] cpython (2.7): Issue #10276: test_zlib checks that inputs of 2 GB are handled correctly by Message-ID: http://hg.python.org/cpython/rev/f43213129ba8 changeset: 69800:f43213129ba8 branch: 2.7 user: Victor Stinner date: Tue May 03 15:19:23 2011 +0200 summary: Issue #10276: test_zlib checks that inputs of 2 GB are handled correctly by crc32() and adler32(). Patch written by Steffen Daode Nurpmeso. files: Lib/test/test_zlib.py | 41 ++++++++++++++++++++++++++++-- 1 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -1,10 +1,16 @@ import unittest -from test import test_support +from test.test_support import TESTFN, run_unittest, import_module, unlink, requires import binascii import random from test.test_support import precisionbigmemtest, _1G +import sys -zlib = test_support.import_module('zlib') +try: + import mmap +except ImportError: + mmap = None + +zlib = import_module('zlib') class ChecksumTestCase(unittest.TestCase): @@ -66,6 +72,34 @@ zlib.crc32('spam', (2**31))) +# Issue #10276 - check that inputs of 2 GB are handled correctly. +# Be aware of issues #1202, #8650, #8651 and #10276 +class ChecksumBigBufferTestCase(unittest.TestCase): + int_max = 0x7FFFFFFF + + @unittest.skipUnless(mmap, "mmap() is not available.") + def test_big_buffer(self): + if sys.platform[:3] == 'win' or sys.platform == 'darwin': + requires('largefile', + 'test requires %s bytes and a long time to run' % + str(self.int_max)) + try: + with open(TESTFN, "wb+") as f: + f.seek(self.int_max-4) + f.write("asdf") + f.flush() + try: + m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) + self.assertEqual(zlib.crc32(m), 0x709418e7) + self.assertEqual(zlib.adler32(m), -2072837729) + finally: + m.close() + except (IOError, OverflowError): + raise unittest.SkipTest("filesystem doesn't have largefile support") + finally: + unlink(TESTFN) + + class ExceptionTestCase(unittest.TestCase): # make sure we generate some expected errors def test_badlevel(self): @@ -546,8 +580,9 @@ def test_main(): - test_support.run_unittest( + run_unittest( ChecksumTestCase, + ChecksumBigBufferTestCase, ExceptionTestCase, CompressTestCase, CompressObjectTestCase -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 16:36:48 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 03 May 2011 16:36:48 +0200 Subject: [Python-checkins] cpython (3.2): Fix typo in name of private function Message-ID: http://hg.python.org/cpython/rev/4219747d3765 changeset: 69801:4219747d3765 branch: 3.2 parent: 69791:bb58d777eaa9 user: Antoine Pitrou date: Tue May 03 16:34:42 2011 +0200 summary: Fix typo in name of private function files: Lib/concurrent/futures/process.py | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -169,12 +169,12 @@ del pending_work_items[work_id] continue -def _queue_manangement_worker(executor_reference, - processes, - pending_work_items, - work_ids_queue, - call_queue, - result_queue): +def _queue_management_worker(executor_reference, + processes, + pending_work_items, + work_ids_queue, + call_queue, + result_queue): """Manages the communication between this process and the worker processes. This function is run in a local thread. @@ -302,7 +302,7 @@ q.put(None) if self._queue_management_thread is None: self._queue_management_thread = threading.Thread( - target=_queue_manangement_worker, + target=_queue_management_worker, args=(weakref.ref(self, weakref_cb), self._processes, self._pending_work_items, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 16:36:49 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 03 May 2011 16:36:49 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Fix typo in name of private function Message-ID: http://hg.python.org/cpython/rev/2761c62aefff changeset: 69802:2761c62aefff parent: 69797:c9207c6ce24a parent: 69801:4219747d3765 user: Antoine Pitrou date: Tue May 03 16:35:43 2011 +0200 summary: Fix typo in name of private function files: Lib/concurrent/futures/process.py | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -170,12 +170,12 @@ del pending_work_items[work_id] continue -def _queue_manangement_worker(executor_reference, - processes, - pending_work_items, - work_ids_queue, - call_queue, - result_queue): +def _queue_management_worker(executor_reference, + processes, + pending_work_items, + work_ids_queue, + call_queue, + result_queue): """Manages the communication between this process and the worker processes. This function is run in a local thread. @@ -303,7 +303,7 @@ q.put(None) if self._queue_management_thread is None: self._queue_management_thread = threading.Thread( - target=_queue_manangement_worker, + target=_queue_management_worker, args=(weakref.ref(self, weakref_cb), self._processes, self._pending_work_items, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 17:20:52 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 May 2011 17:20:52 +0200 Subject: [Python-checkins] cpython: Issue #8407: disable faulthandler timeout thread on all platforms Message-ID: http://hg.python.org/cpython/rev/96a532eaa2d1 changeset: 69803:96a532eaa2d1 user: Victor Stinner date: Tue May 03 17:20:31 2011 +0200 summary: Issue #8407: disable faulthandler timeout thread on all platforms The problem is not specific to Mac OS X. files: Lib/test/test_signal.py | 27 +++++++++++++-------------- 1 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -494,6 +494,7 @@ self.assertRaises(RuntimeError, signal.pthread_sigmask, 1700, []) def test_block_unlock(self): + import faulthandler pid = os.getpid() signum = signal.SIGUSR1 @@ -503,20 +504,18 @@ def read_sigmask(): return signal.pthread_sigmask(signal.SIG_BLOCK, []) - if sys.platform == "darwin": - import faulthandler - # The fault handler timeout thread masks all signals. If the main - # thread masks also SIGUSR1, all threads mask this signal. In this - # case, on Mac OS X, if we send SIGUSR1 to the process, the signal - # is pending in the main or the faulthandler timeout thread. - # Unblock SIGUSR1 in the main thread calls the signal handler only - # if the signal is pending for the main thread. - # - # Stop the faulthandler timeout thread to workaround this problem. - # Another solution would be to send the signal directly to the main - # thread using pthread_kill(), but Python doesn't expose this - # function. - faulthandler.cancel_dump_tracebacks_later() + # The fault handler timeout thread masks all signals. If the main + # thread masks also SIGUSR1, all threads mask this signal. In this + # case, if we send SIGUSR1 to the process, the signal is pending in the + # main or the faulthandler timeout thread. Unblock SIGUSR1 in the main + # thread calls the signal handler only if the signal is pending for the + # main thread. + # + # Stop the faulthandler timeout thread to workaround this problem. + # Another solution would be to send the signal directly to the main + # thread using pthread_kill(), but Python doesn't expose this + # function. + faulthandler.cancel_dump_tracebacks_later() # Install our signal handler old_handler = signal.signal(signum, handler) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 17:25:46 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 May 2011 17:25:46 +0200 Subject: [Python-checkins] cpython (2.7): Issue #10276: Fix test_zlib, m may be undefined in the finally block Message-ID: http://hg.python.org/cpython/rev/dd58f8072216 changeset: 69804:dd58f8072216 branch: 2.7 parent: 69800:f43213129ba8 user: Victor Stinner date: Tue May 03 17:25:28 2011 +0200 summary: Issue #10276: Fix test_zlib, m may be undefined in the finally block files: Lib/test/test_zlib.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -88,8 +88,8 @@ f.seek(self.int_max-4) f.write("asdf") f.flush() + m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) try: - m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) self.assertEqual(zlib.crc32(m), 0x709418e7) self.assertEqual(zlib.adler32(m), -2072837729) finally: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 18:19:20 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 03 May 2011 18:19:20 +0200 Subject: [Python-checkins] cpython: Issue #11849: Make it more likely for the system allocator to release Message-ID: http://hg.python.org/cpython/rev/f8a697bc3ca8 changeset: 69805:f8a697bc3ca8 parent: 69803:96a532eaa2d1 user: Antoine Pitrou date: Tue May 03 18:18:59 2011 +0200 summary: Issue #11849: Make it more likely for the system allocator to release free()d memory arenas on glibc-based systems. Patch by Charles-Fran?ois Natali. files: Misc/NEWS | 4 + Objects/obmalloc.c | 29 +- configure | 1065 +++++++++++++++---------------- configure.in | 9 + pyconfig.h.in | 3 + 5 files changed, 564 insertions(+), 546 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #11849: Make it more likely for the system allocator to release + free()d memory arenas on glibc-based systems. Patch by Charles-Fran?ois + Natali. + - Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. Fix a crash if a class override its __class__ attribute (e.g. a proxy of the diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -2,6 +2,10 @@ #ifdef WITH_PYMALLOC +#ifdef HAVE_MALLOPT_MMAP_THRESHOLD + #include +#endif + #ifdef WITH_VALGRIND #include @@ -75,7 +79,8 @@ * Allocation strategy abstract: * * For small requests, the allocator sub-allocates blocks of memory. - * Requests greater than 256 bytes are routed to the system's allocator. + * Requests greater than SMALL_REQUEST_THRESHOLD bytes are routed to the + * system's allocator. * * Small requests are grouped in size classes spaced 8 bytes apart, due * to the required valid alignment of the returned address. Requests of @@ -107,10 +112,11 @@ * 57-64 64 7 * 65-72 72 8 * ... ... ... - * 241-248 248 30 - * 249-256 256 31 + * 497-504 504 62 + * 505-512 512 63 * - * 0, 257 and up: routed to the underlying allocator. + * 0, SMALL_REQUEST_THRESHOLD + 1 and up: routed to the underlying + * allocator. */ /*==========================================================================*/ @@ -139,14 +145,17 @@ * small enough in order to use preallocated memory pools. You can tune * this value according to your application behaviour and memory needs. * + * Note: a size threshold of 512 guarantees that newly created dictionaries + * will be allocated from preallocated memory pools on 64-bit. + * * The following invariants must hold: - * 1) ALIGNMENT <= SMALL_REQUEST_THRESHOLD <= 256 + * 1) ALIGNMENT <= SMALL_REQUEST_THRESHOLD <= 512 * 2) SMALL_REQUEST_THRESHOLD is evenly divisible by ALIGNMENT * * Although not required, for better performance and space efficiency, * it is recommended that SMALL_REQUEST_THRESHOLD is set to a power of 2. */ -#define SMALL_REQUEST_THRESHOLD 256 +#define SMALL_REQUEST_THRESHOLD 512 #define NB_SMALL_SIZE_CLASSES (SMALL_REQUEST_THRESHOLD / ALIGNMENT) /* @@ -440,6 +449,9 @@ , PT(48), PT(49), PT(50), PT(51), PT(52), PT(53), PT(54), PT(55) #if NB_SMALL_SIZE_CLASSES > 56 , PT(56), PT(57), PT(58), PT(59), PT(60), PT(61), PT(62), PT(63) +#if NB_SMALL_SIZE_CLASSES > 64 +#error "NB_SMALL_SIZE_CLASSES should be less than 64" +#endif /* NB_SMALL_SIZE_CLASSES > 64 */ #endif /* NB_SMALL_SIZE_CLASSES > 56 */ #endif /* NB_SMALL_SIZE_CLASSES > 48 */ #endif /* NB_SMALL_SIZE_CLASSES > 40 */ @@ -545,6 +557,11 @@ if (numarenas > PY_SIZE_MAX / sizeof(*arenas)) return NULL; /* overflow */ #endif +#ifdef HAVE_MALLOPT_MMAP_THRESHOLD + /* Ensure arenas are allocated by mmap to avoid heap fragmentation. */ + if (numarenas == INITIAL_ARENA_OBJECTS) + mallopt(M_MMAP_THRESHOLD, ARENA_SIZE); +#endif nbytes = numarenas * sizeof(*arenas); arenaobj = (struct arena_object *)realloc(arenas, nbytes); if (arenaobj == NULL) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,14 +1,14 @@ #! /bin/sh # From configure.in Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for python 3.3. +# Generated by GNU Autoconf 2.65 for python 3.3. # # 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 @@ -92,7 +92,6 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -218,18 +217,11 @@ # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. - # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL - case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; - esac - exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -328,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 @@ -368,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 @@ -542,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` @@ -839,9 +831,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. @@ -886,7 +877,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 @@ -912,7 +903,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 @@ -1116,7 +1107,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 @@ -1132,7 +1123,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 @@ -1162,8 +1153,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." ;; *=*) @@ -1171,7 +1162,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 ;; @@ -1181,7 +1172,7 @@ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac @@ -1189,13 +1180,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 @@ -1218,7 +1209,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' @@ -1232,8 +1223,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 @@ -1248,9 +1239,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. @@ -1289,11 +1280,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 @@ -1333,7 +1324,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 @@ -1518,9 +1509,9 @@ if $ac_init_version; then cat <<\_ACEOF python configure 3.3 -generated by GNU Autoconf 2.68 - -Copyright (C) 2010 Free Software Foundation, Inc. +generated by GNU Autoconf 2.65 + +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 @@ -1564,7 +1555,7 @@ ac_retval=1 fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile @@ -1590,7 +1581,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 : @@ -1601,7 +1592,7 @@ ac_retval=1 fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp @@ -1614,10 +1605,10 @@ ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; 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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -1653,7 +1644,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; } @@ -1676,15 +1667,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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -1693,7 +1686,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel @@ -1734,7 +1727,7 @@ ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run @@ -1748,7 +1741,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 \${$3+:} false; 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 @@ -1766,7 +1759,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile @@ -1811,7 +1804,7 @@ # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link @@ -1825,7 +1818,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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1866,7 +1859,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_type @@ -1879,7 +1872,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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1909,7 +1902,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 @@ -1919,7 +1913,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_find_uintX_t @@ -1932,7 +1926,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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1943,11 +1937,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))]; +int +main () +{ +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 ; @@ -1958,11 +1952,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) +int +main () +{ +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 @@ -1983,7 +1977,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 @@ -1993,7 +1988,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_find_intX_t @@ -2170,7 +2165,7 @@ rm -f conftest.val fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_compute_int @@ -2183,7 +2178,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 \${$3+:} false; 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 @@ -2238,7 +2233,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func @@ -2251,7 +2246,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 \${$4+:} false; 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 @@ -2295,22 +2290,19 @@ eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # 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 \${$3+:} false; 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 @@ -2319,12 +2311,8 @@ int main () { -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif +#ifndef $2 + (void) $2; #endif ; @@ -2341,7 +2329,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_decl cat >config.log <<_ACEOF @@ -2349,7 +2337,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by python $as_me 3.3, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ @@ -2459,9 +2447,11 @@ { echo - $as_echo "## ---------------- ## + cat <<\_ASBOX +## ---------------- ## ## Cache variables. ## -## ---------------- ##" +## ---------------- ## +_ASBOX echo # The following way of writing the cache mishandles newlines in values, ( @@ -2495,9 +2485,11 @@ ) echo - $as_echo "## ----------------- ## + cat <<\_ASBOX +## ----------------- ## ## Output variables. ## -## ----------------- ##" +## ----------------- ## +_ASBOX echo for ac_var in $ac_subst_vars do @@ -2510,9 +2502,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 @@ -2526,9 +2520,11 @@ fi if test -s confdefs.h; then - $as_echo "## ----------- ## + cat <<\_ASBOX +## ----------- ## ## confdefs.h. ## -## ----------- ##" +## ----------- ## +_ASBOX echo cat confdefs.h echo @@ -2583,12 +2579,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 @@ -2603,11 +2594,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 @@ -2683,7 +2670,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. ## @@ -2784,7 +2771,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 @@ -3176,7 +3163,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 @@ -3196,7 +3183,7 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3236,7 +3223,7 @@ set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3289,7 +3276,7 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3329,7 +3316,7 @@ set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3388,7 +3375,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3432,7 +3419,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3486,8 +3473,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 @@ -3601,8 +3588,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; } @@ -3644,8 +3632,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 @@ -3702,9 +3690,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 @@ -3715,7 +3703,7 @@ ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : +if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3755,8 +3743,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 @@ -3766,7 +3754,7 @@ ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : +if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3803,7 +3791,7 @@ ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : +if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag @@ -3881,7 +3869,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : +if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no @@ -4016,7 +4004,7 @@ set dummy g++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CXX+:} false; then : +if test "${ac_cv_path_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4057,7 +4045,7 @@ set dummy c++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CXX+:} false; then : +if test "${ac_cv_path_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4108,7 +4096,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : +if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then @@ -4179,7 +4167,7 @@ CPP= fi if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : + if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded @@ -4209,7 +4197,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. @@ -4225,11 +4213,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 @@ -4268,7 +4256,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. @@ -4284,18 +4272,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 @@ -4307,7 +4295,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : +if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -4356,7 +4344,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 @@ -4370,7 +4358,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : +if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -4422,7 +4410,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 @@ -4437,7 +4425,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : +if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4554,7 +4542,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 @@ -4566,7 +4555,7 @@ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = xyes; then : +if test "x$ac_cv_header_minix_config_h" = x""yes; then : MINIX=yes else MINIX= @@ -4588,7 +4577,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if ${ac_cv_safe_to_define___extensions__+:} false; then : +if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4781,7 +4770,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } -if ${ac_cv_c_inline+:} false; then : +if test "${ac_cv_c_inline+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no @@ -4977,7 +4966,7 @@ set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : +if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then @@ -5017,7 +5006,7 @@ set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then @@ -5071,7 +5060,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : +if test "${ac_cv_prog_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then @@ -5123,7 +5112,7 @@ set dummy hg; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_HAS_HG+:} false; then : +if test "${ac_cv_prog_HAS_HG+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$HAS_HG"; then @@ -5178,22 +5167,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, @@ -5222,7 +5205,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : +if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5408,7 +5391,7 @@ ac_save_cc="$CC" CC="$CC -fno-strict-aliasing" save_CFLAGS="$CFLAGS" - if ${ac_cv_no_strict_aliasing+:} false; then : + if test "${ac_cv_no_strict_aliasing+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5531,7 +5514,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 @@ -5658,7 +5641,7 @@ # options before we can check whether -Kpthread improves anything. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads are available without options" >&5 $as_echo_n "checking whether pthreads are available without options... " >&6; } -if ${ac_cv_pthread_is_default+:} false; then : +if test "${ac_cv_pthread_is_default+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -5711,7 +5694,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kpthread" >&5 $as_echo_n "checking whether $CC accepts -Kpthread... " >&6; } -if ${ac_cv_kpthread+:} false; then : +if test "${ac_cv_kpthread+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5760,7 +5743,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kthread" >&5 $as_echo_n "checking whether $CC accepts -Kthread... " >&6; } -if ${ac_cv_kthread+:} false; then : +if test "${ac_cv_kthread+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5809,7 +5792,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -pthread" >&5 $as_echo_n "checking whether $CC accepts -pthread... " >&6; } -if ${ac_cv_thread+:} false; then : +if test "${ac_cv_thread+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5894,7 +5877,7 @@ # checks for header files { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : +if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6019,7 +6002,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 @@ -6033,7 +6017,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 \${$as_ac_Header+:} false; 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 @@ -6060,7 +6044,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 @@ -6073,7 +6058,7 @@ if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : +if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6107,11 +6092,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : + if test "${ac_cv_search_opendir+set}" = set; then : break fi done -if ${ac_cv_search_opendir+:} false; then : +if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no @@ -6130,7 +6115,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : +if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6164,11 +6149,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : + if test "${ac_cv_search_opendir+set}" = set; then : break fi done -if ${ac_cv_search_opendir+:} false; then : +if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no @@ -6188,7 +6173,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 $as_echo_n "checking whether sys/types.h defines makedev... " >&6; } -if ${ac_cv_header_sys_types_h_makedev+:} false; then : +if test "${ac_cv_header_sys_types_h_makedev+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6216,7 +6201,7 @@ if test $ac_cv_header_sys_types_h_makedev = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : +if test "x$ac_cv_header_sys_mkdev_h" = x""yes; then : $as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h @@ -6226,7 +6211,7 @@ if test $ac_cv_header_sys_mkdev_h = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then : +if test "x$ac_cv_header_sys_sysmacros_h" = x""yes; then : $as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h @@ -6246,7 +6231,7 @@ #endif " -if test "x$ac_cv_header_term_h" = xyes; then : +if test "x$ac_cv_header_term_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_TERM_H 1 _ACEOF @@ -6268,7 +6253,7 @@ #endif " -if test "x$ac_cv_header_linux_netlink_h" = xyes; then : +if test "x$ac_cv_header_linux_netlink_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_NETLINK_H 1 _ACEOF @@ -6404,7 +6389,7 @@ # Type availability checks ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" -if test "x$ac_cv_type_mode_t" = xyes; then : +if test "x$ac_cv_type_mode_t" = x""yes; then : else @@ -6415,7 +6400,7 @@ fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" -if test "x$ac_cv_type_off_t" = xyes; then : +if test "x$ac_cv_type_off_t" = x""yes; then : else @@ -6426,7 +6411,7 @@ fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = xyes; then : +if test "x$ac_cv_type_pid_t" = x""yes; then : else @@ -6442,7 +6427,7 @@ _ACEOF ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : +if test "x$ac_cv_type_size_t" = x""yes; then : else @@ -6454,7 +6439,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if ${ac_cv_type_uid_t+:} false; then : +if test "${ac_cv_type_uid_t+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6533,7 +6518,7 @@ esac ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" -if test "x$ac_cv_type_ssize_t" = xyes; then : +if test "x$ac_cv_type_ssize_t" = x""yes; then : $as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h @@ -6548,7 +6533,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 $as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : +if test "${ac_cv_sizeof_int+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : @@ -6557,8 +6542,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 @@ -6581,7 +6567,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } -if ${ac_cv_sizeof_long+:} false; then : +if test "${ac_cv_sizeof_long+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : @@ -6590,8 +6576,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 @@ -6614,7 +6601,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 $as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : +if test "${ac_cv_sizeof_void_p+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : @@ -6623,8 +6610,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 @@ -6647,7 +6635,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 $as_echo_n "checking size of short... " >&6; } -if ${ac_cv_sizeof_short+:} false; then : +if test "${ac_cv_sizeof_short+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : @@ -6656,8 +6644,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 @@ -6680,7 +6669,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 $as_echo_n "checking size of float... " >&6; } -if ${ac_cv_sizeof_float+:} false; then : +if test "${ac_cv_sizeof_float+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default"; then : @@ -6689,8 +6678,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 @@ -6713,7 +6703,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 $as_echo_n "checking size of double... " >&6; } -if ${ac_cv_sizeof_double+:} false; then : +if test "${ac_cv_sizeof_double+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then : @@ -6722,8 +6712,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 @@ -6746,7 +6737,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 $as_echo_n "checking size of fpos_t... " >&6; } -if ${ac_cv_sizeof_fpos_t+:} false; then : +if test "${ac_cv_sizeof_fpos_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default"; then : @@ -6755,8 +6746,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 @@ -6779,7 +6771,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 $as_echo_n "checking size of size_t... " >&6; } -if ${ac_cv_sizeof_size_t+:} false; then : +if test "${ac_cv_sizeof_size_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : @@ -6788,8 +6780,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 @@ -6812,7 +6805,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 $as_echo_n "checking size of pid_t... " >&6; } -if ${ac_cv_sizeof_pid_t+:} false; then : +if test "${ac_cv_sizeof_pid_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default"; then : @@ -6821,8 +6814,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 @@ -6872,7 +6866,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 $as_echo_n "checking size of long long... " >&6; } -if ${ac_cv_sizeof_long_long+:} false; then : +if test "${ac_cv_sizeof_long_long+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : @@ -6881,8 +6875,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 @@ -6933,7 +6928,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 $as_echo_n "checking size of long double... " >&6; } -if ${ac_cv_sizeof_long_double+:} false; then : +if test "${ac_cv_sizeof_long_double+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then : @@ -6942,8 +6937,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 @@ -6995,7 +6991,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of _Bool" >&5 $as_echo_n "checking size of _Bool... " >&6; } -if ${ac_cv_sizeof__Bool+:} false; then : +if test "${ac_cv_sizeof__Bool+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default"; then : @@ -7004,8 +7000,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 @@ -7031,7 +7028,7 @@ #include #endif " -if test "x$ac_cv_type_uintptr_t" = xyes; then : +if test "x$ac_cv_type_uintptr_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINTPTR_T 1 @@ -7043,7 +7040,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 $as_echo_n "checking size of uintptr_t... " >&6; } -if ${ac_cv_sizeof_uintptr_t+:} false; then : +if test "${ac_cv_sizeof_uintptr_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default"; then : @@ -7052,8 +7049,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 @@ -7079,7 +7077,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 $as_echo_n "checking size of off_t... " >&6; } -if ${ac_cv_sizeof_off_t+:} false; then : +if test "${ac_cv_sizeof_off_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " @@ -7093,8 +7091,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 @@ -7138,7 +7137,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 $as_echo_n "checking size of time_t... " >&6; } -if ${ac_cv_sizeof_time_t+:} false; then : +if test "${ac_cv_sizeof_time_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " @@ -7155,8 +7154,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 @@ -7213,7 +7213,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 $as_echo_n "checking size of pthread_t... " >&6; } -if ${ac_cv_sizeof_pthread_t+:} false; then : +if test "${ac_cv_sizeof_pthread_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " @@ -7227,8 +7227,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 @@ -7315,7 +7316,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 @@ -7327,7 +7328,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 @@ -7353,7 +7354,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 @@ -7659,7 +7660,7 @@ # checks for libraries { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile in -lsendfile" >&5 $as_echo_n "checking for sendfile in -lsendfile... " >&6; } -if ${ac_cv_lib_sendfile_sendfile+:} false; then : +if test "${ac_cv_lib_sendfile_sendfile+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7693,7 +7694,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sendfile_sendfile" >&5 $as_echo "$ac_cv_lib_sendfile_sendfile" >&6; } -if test "x$ac_cv_lib_sendfile_sendfile" = xyes; then : +if test "x$ac_cv_lib_sendfile_sendfile" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSENDFILE 1 _ACEOF @@ -7704,7 +7705,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7738,7 +7739,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF @@ -7749,7 +7750,7 @@ # Dynamic linking for SunOS/Solaris and SYSV { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } -if ${ac_cv_lib_dld_shl_load+:} false; then : +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7783,7 +7784,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes; then : +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDLD 1 _ACEOF @@ -7797,7 +7798,7 @@ if test "$with_threads" = "yes" -o -z "$with_threads"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5 $as_echo_n "checking for library containing sem_init... " >&6; } -if ${ac_cv_search_sem_init+:} false; then : +if test "${ac_cv_search_sem_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -7831,11 +7832,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if ${ac_cv_search_sem_init+:} false; then : + if test "${ac_cv_search_sem_init+set}" = set; then : break fi done -if ${ac_cv_search_sem_init+:} false; then : +if test "${ac_cv_search_sem_init+set}" = set; then : else ac_cv_search_sem_init=no @@ -7858,7 +7859,7 @@ # check if we need libintl for locale functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for textdomain in -lintl" >&5 $as_echo_n "checking for textdomain in -lintl... " >&6; } -if ${ac_cv_lib_intl_textdomain+:} false; then : +if test "${ac_cv_lib_intl_textdomain+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7892,7 +7893,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_textdomain" >&5 $as_echo "$ac_cv_lib_intl_textdomain" >&6; } -if test "x$ac_cv_lib_intl_textdomain" = xyes; then : +if test "x$ac_cv_lib_intl_textdomain" = x""yes; then : $as_echo "#define WITH_LIBINTL 1" >>confdefs.h @@ -7939,7 +7940,7 @@ # Most SVR4 platforms (e.g. Solaris) need -lsocket and -lnsl. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for t_open in -lnsl" >&5 $as_echo_n "checking for t_open in -lnsl... " >&6; } -if ${ac_cv_lib_nsl_t_open+:} false; then : +if test "${ac_cv_lib_nsl_t_open+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7973,13 +7974,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 $as_echo "$ac_cv_lib_nsl_t_open" >&6; } -if test "x$ac_cv_lib_nsl_t_open" = xyes; then : +if test "x$ac_cv_lib_nsl_t_open" = x""yes; then : LIBS="-lnsl $LIBS" fi # SVR4 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 $as_echo_n "checking for socket in -lsocket... " >&6; } -if ${ac_cv_lib_socket_socket+:} false; then : +if test "${ac_cv_lib_socket_socket+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8013,7 +8014,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 $as_echo "$ac_cv_lib_socket_socket" >&6; } -if test "x$ac_cv_lib_socket_socket" = xyes; then : +if test "x$ac_cv_lib_socket_socket" = x""yes; then : LIBS="-lsocket $LIBS" fi # SVR4 sockets @@ -8039,7 +8040,7 @@ set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PKG_CONFIG+:} false; then : +if test "${ac_cv_path_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in @@ -8082,7 +8083,7 @@ set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : +if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in @@ -8193,12 +8194,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 @@ -8347,7 +8348,7 @@ $as_echo "#define _REENTRANT 1" >>confdefs.h ac_fn_c_check_header_mongrel "$LINENO" "cthreads.h" "ac_cv_header_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_cthreads_h" = xyes; then : +if test "x$ac_cv_header_cthreads_h" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8360,7 +8361,7 @@ else ac_fn_c_check_header_mongrel "$LINENO" "mach/cthreads.h" "ac_cv_header_mach_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_mach_cthreads_h" = xyes; then : +if test "x$ac_cv_header_mach_cthreads_h" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8404,7 +8405,7 @@ LIBS=$_libs ac_fn_c_check_func "$LINENO" "pthread_detach" "ac_cv_func_pthread_detach" -if test "x$ac_cv_func_pthread_detach" = xyes; then : +if test "x$ac_cv_func_pthread_detach" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8413,7 +8414,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 $as_echo_n "checking for pthread_create in -lpthreads... " >&6; } -if ${ac_cv_lib_pthreads_pthread_create+:} false; then : +if test "${ac_cv_lib_pthreads_pthread_create+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8447,7 +8448,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 $as_echo "$ac_cv_lib_pthreads_pthread_create" >&6; } -if test "x$ac_cv_lib_pthreads_pthread_create" = xyes; then : +if test "x$ac_cv_lib_pthreads_pthread_create" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8457,7 +8458,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 $as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if ${ac_cv_lib_c_r_pthread_create+:} false; then : +if test "${ac_cv_lib_c_r_pthread_create+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8491,7 +8492,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 $as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : +if test "x$ac_cv_lib_c_r_pthread_create" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8501,7 +8502,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_create_system in -lpthread" >&5 $as_echo_n "checking for __pthread_create_system in -lpthread... " >&6; } -if ${ac_cv_lib_pthread___pthread_create_system+:} false; then : +if test "${ac_cv_lib_pthread___pthread_create_system+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8535,7 +8536,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_create_system" >&5 $as_echo "$ac_cv_lib_pthread___pthread_create_system" >&6; } -if test "x$ac_cv_lib_pthread___pthread_create_system" = xyes; then : +if test "x$ac_cv_lib_pthread___pthread_create_system" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8545,7 +8546,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lcma" >&5 $as_echo_n "checking for pthread_create in -lcma... " >&6; } -if ${ac_cv_lib_cma_pthread_create+:} false; then : +if test "${ac_cv_lib_cma_pthread_create+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8579,7 +8580,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cma_pthread_create" >&5 $as_echo "$ac_cv_lib_cma_pthread_create" >&6; } -if test "x$ac_cv_lib_cma_pthread_create" = xyes; then : +if test "x$ac_cv_lib_cma_pthread_create" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8611,7 +8612,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usconfig in -lmpc" >&5 $as_echo_n "checking for usconfig in -lmpc... " >&6; } -if ${ac_cv_lib_mpc_usconfig+:} false; then : +if test "${ac_cv_lib_mpc_usconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8645,7 +8646,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mpc_usconfig" >&5 $as_echo "$ac_cv_lib_mpc_usconfig" >&6; } -if test "x$ac_cv_lib_mpc_usconfig" = xyes; then : +if test "x$ac_cv_lib_mpc_usconfig" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lmpc" @@ -8657,7 +8658,7 @@ if test "$posix_threads" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for thr_create in -lthread" >&5 $as_echo_n "checking for thr_create in -lthread... " >&6; } -if ${ac_cv_lib_thread_thr_create+:} false; then : +if test "${ac_cv_lib_thread_thr_create+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8691,7 +8692,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_thread_thr_create" >&5 $as_echo "$ac_cv_lib_thread_thr_create" >&6; } -if test "x$ac_cv_lib_thread_thr_create" = xyes; then : +if test "x$ac_cv_lib_thread_thr_create" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lthread" @@ -8731,7 +8732,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PTHREAD_SCOPE_SYSTEM is supported" >&5 $as_echo_n "checking if PTHREAD_SCOPE_SYSTEM is supported... " >&6; } - if ${ac_cv_pthread_system_supported+:} false; then : + if test "${ac_cv_pthread_system_supported+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -8774,7 +8775,7 @@ for ac_func in pthread_sigmask do : ac_fn_c_check_func "$LINENO" "pthread_sigmask" "ac_cv_func_pthread_sigmask" -if test "x$ac_cv_func_pthread_sigmask" = xyes; then : +if test "x$ac_cv_func_pthread_sigmask" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_SIGMASK 1 _ACEOF @@ -9166,12 +9167,12 @@ $as_echo "$with_valgrind" >&6; } if test "$with_valgrind" != no; then ac_fn_c_check_header_mongrel "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_valgrind_h" = xyes; then : +if test "x$ac_cv_header_valgrind_valgrind_h" = x""yes; then : $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 @@ -9188,7 +9189,7 @@ for ac_func in dlopen do : ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes; then : +if test "x$ac_cv_func_dlopen" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLOPEN 1 _ACEOF @@ -9268,7 +9269,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 @@ -9518,7 +9520,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock declaration" >&5 $as_echo_n "checking for flock declaration... " >&6; } -if ${ac_cv_flock_decl+:} false; then : +if test "${ac_cv_flock_decl+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -9548,7 +9550,7 @@ for ac_func in flock do : ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" -if test "x$ac_cv_func_flock" = xyes; then : +if test "x$ac_cv_func_flock" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FLOCK 1 _ACEOF @@ -9556,7 +9558,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 $as_echo_n "checking for flock in -lbsd... " >&6; } -if ${ac_cv_lib_bsd_flock+:} false; then : +if test "${ac_cv_lib_bsd_flock+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9590,7 +9592,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_flock" >&5 $as_echo "$ac_cv_lib_bsd_flock" >&6; } -if test "x$ac_cv_lib_bsd_flock" = xyes; then : +if test "x$ac_cv_lib_bsd_flock" = x""yes; then : $as_echo "#define HAVE_FLOCK 1" >>confdefs.h @@ -9633,13 +9635,41 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mallopt can set malloc mmap threshold" >&5 +$as_echo_n "checking whether mallopt can set malloc mmap threshold... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ +mallopt(M_MMAP_THRESHOLD, 256 * 1024) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_MALLOPT_MMAP_THRESHOLD 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + for ac_prog in true do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_TRUE+:} false; then : +if test "${ac_cv_prog_TRUE+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$TRUE"; then @@ -9679,7 +9709,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lc" >&5 $as_echo_n "checking for inet_aton in -lc... " >&6; } -if ${ac_cv_lib_c_inet_aton+:} false; then : +if test "${ac_cv_lib_c_inet_aton+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9713,12 +9743,12 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_aton" >&5 $as_echo "$ac_cv_lib_c_inet_aton" >&6; } -if test "x$ac_cv_lib_c_inet_aton" = xyes; then : +if test "x$ac_cv_lib_c_inet_aton" = x""yes; then : $ac_cv_prog_TRUE else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 $as_echo_n "checking for inet_aton in -lresolv... " >&6; } -if ${ac_cv_lib_resolv_inet_aton+:} false; then : +if test "${ac_cv_lib_resolv_inet_aton+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9752,7 +9782,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5 $as_echo "$ac_cv_lib_resolv_inet_aton" >&6; } -if test "x$ac_cv_lib_resolv_inet_aton" = xyes; then : +if test "x$ac_cv_lib_resolv_inet_aton" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF @@ -9769,7 +9799,7 @@ # exit Python { $as_echo "$as_me:${as_lineno-$LINENO}: checking for chflags" >&5 $as_echo_n "checking for chflags... " >&6; } -if ${ac_cv_have_chflags+:} false; then : +if test "${ac_cv_have_chflags+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -9803,7 +9833,7 @@ $as_echo "$ac_cv_have_chflags" >&6; } if test "$ac_cv_have_chflags" = cross ; then ac_fn_c_check_func "$LINENO" "chflags" "ac_cv_func_chflags" -if test "x$ac_cv_func_chflags" = xyes; then : +if test "x$ac_cv_func_chflags" = x""yes; then : ac_cv_have_chflags="yes" else ac_cv_have_chflags="no" @@ -9818,7 +9848,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lchflags" >&5 $as_echo_n "checking for lchflags... " >&6; } -if ${ac_cv_have_lchflags+:} false; then : +if test "${ac_cv_have_lchflags+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -9852,7 +9882,7 @@ $as_echo "$ac_cv_have_lchflags" >&6; } if test "$ac_cv_have_lchflags" = cross ; then ac_fn_c_check_func "$LINENO" "lchflags" "ac_cv_func_lchflags" -if test "x$ac_cv_func_lchflags" = xyes; then : +if test "x$ac_cv_func_lchflags" = x""yes; then : ac_cv_have_lchflags="yes" else ac_cv_have_lchflags="no" @@ -9876,7 +9906,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 $as_echo_n "checking for inflateCopy in -lz... " >&6; } -if ${ac_cv_lib_z_inflateCopy+:} false; then : +if test "${ac_cv_lib_z_inflateCopy+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9910,7 +9940,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 $as_echo "$ac_cv_lib_z_inflateCopy" >&6; } -if test "x$ac_cv_lib_z_inflateCopy" = xyes; then : +if test "x$ac_cv_lib_z_inflateCopy" = x""yes; then : $as_echo "#define HAVE_ZLIB_COPY 1" >>confdefs.h @@ -10053,7 +10083,7 @@ for ac_func in openpty do : ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty" -if test "x$ac_cv_func_openpty" = xyes; then : +if test "x$ac_cv_func_openpty" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENPTY 1 _ACEOF @@ -10061,7 +10091,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 $as_echo_n "checking for openpty in -lutil... " >&6; } -if ${ac_cv_lib_util_openpty+:} false; then : +if test "${ac_cv_lib_util_openpty+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10095,13 +10125,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 $as_echo "$ac_cv_lib_util_openpty" >&6; } -if test "x$ac_cv_lib_util_openpty" = xyes; then : +if test "x$ac_cv_lib_util_openpty" = x""yes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 $as_echo_n "checking for openpty in -lbsd... " >&6; } -if ${ac_cv_lib_bsd_openpty+:} false; then : +if test "${ac_cv_lib_bsd_openpty+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10135,7 +10165,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_openpty" >&5 $as_echo "$ac_cv_lib_bsd_openpty" >&6; } -if test "x$ac_cv_lib_bsd_openpty" = xyes; then : +if test "x$ac_cv_lib_bsd_openpty" = x""yes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10150,7 +10180,7 @@ for ac_func in forkpty do : ac_fn_c_check_func "$LINENO" "forkpty" "ac_cv_func_forkpty" -if test "x$ac_cv_func_forkpty" = xyes; then : +if test "x$ac_cv_func_forkpty" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FORKPTY 1 _ACEOF @@ -10158,7 +10188,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 $as_echo_n "checking for forkpty in -lutil... " >&6; } -if ${ac_cv_lib_util_forkpty+:} false; then : +if test "${ac_cv_lib_util_forkpty+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10192,13 +10222,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_forkpty" >&5 $as_echo "$ac_cv_lib_util_forkpty" >&6; } -if test "x$ac_cv_lib_util_forkpty" = xyes; then : +if test "x$ac_cv_lib_util_forkpty" = x""yes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 $as_echo_n "checking for forkpty in -lbsd... " >&6; } -if ${ac_cv_lib_bsd_forkpty+:} false; then : +if test "${ac_cv_lib_bsd_forkpty+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10232,7 +10262,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_forkpty" >&5 $as_echo "$ac_cv_lib_bsd_forkpty" >&6; } -if test "x$ac_cv_lib_bsd_forkpty" = xyes; then : +if test "x$ac_cv_lib_bsd_forkpty" = x""yes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10249,7 +10279,7 @@ for ac_func in memmove do : ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" -if test "x$ac_cv_func_memmove" = xyes; then : +if test "x$ac_cv_func_memmove" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MEMMOVE 1 _ACEOF @@ -10263,7 +10293,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 @@ -10272,50 +10303,31 @@ done -ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" -if test "x$ac_cv_func_dup2" = xyes; then : - $as_echo "#define HAVE_DUP2 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 - *" dup2.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS dup2.$ac_objext" + *" $ac_func.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;; esac fi - -ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" -if test "x$ac_cv_func_getcwd" = xyes; 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" = xyes; then : - $as_echo "#define HAVE_STRDUP 1" >>confdefs.h - -else - case " $LIBOBJS " in - *" strdup.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS strdup.$ac_objext" - ;; -esac - -fi +done for ac_func in getpgrp do : ac_fn_c_check_func "$LINENO" "getpgrp" "ac_cv_func_getpgrp" -if test "x$ac_cv_func_getpgrp" = xyes; then : +if test "x$ac_cv_func_getpgrp" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETPGRP 1 _ACEOF @@ -10343,7 +10355,7 @@ for ac_func in setpgrp do : ac_fn_c_check_func "$LINENO" "setpgrp" "ac_cv_func_setpgrp" -if test "x$ac_cv_func_setpgrp" = xyes; then : +if test "x$ac_cv_func_setpgrp" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETPGRP 1 _ACEOF @@ -10371,7 +10383,7 @@ for ac_func in gettimeofday do : ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" -if test "x$ac_cv_func_gettimeofday" = xyes; then : +if test "x$ac_cv_func_gettimeofday" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETTIMEOFDAY 1 _ACEOF @@ -10473,7 +10485,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking getaddrinfo bug" >&5 $as_echo_n "checking getaddrinfo bug... " >&6; } - if ${ac_cv_buggy_getaddrinfo+:} false; then : + if test "${ac_cv_buggy_getaddrinfo+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10602,7 +10614,7 @@ for ac_func in getnameinfo do : ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo" -if test "x$ac_cv_func_getnameinfo" = xyes; then : +if test "x$ac_cv_func_getnameinfo" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETNAMEINFO 1 _ACEOF @@ -10614,7 +10626,7 @@ # checks for structures { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if ${ac_cv_header_time+:} false; then : +if test "${ac_cv_header_time+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10649,7 +10661,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if ${ac_cv_struct_tm+:} false; then : +if test "${ac_cv_struct_tm+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10686,7 +10698,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -10702,7 +10714,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = xyes; then : +if test "x$ac_cv_have_decl_tzname" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -10714,7 +10726,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if ${ac_cv_var_tzname+:} false; then : +if test "${ac_cv_var_tzname+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10750,7 +10762,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_RDEV 1 @@ -10760,7 +10772,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_blksize" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 @@ -10770,7 +10782,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_flags" "ac_cv_member_struct_stat_st_flags" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_flags" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_flags" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_FLAGS 1 @@ -10780,7 +10792,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_gen" "ac_cv_member_struct_stat_st_gen" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_gen" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_gen" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_GEN 1 @@ -10790,7 +10802,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtime" "ac_cv_member_struct_stat_st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtime" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_birthtime" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 @@ -10800,7 +10812,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_blocks" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLOCKS 1 @@ -10822,7 +10834,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 $as_echo_n "checking for time.h that defines altzone... " >&6; } -if ${ac_cv_header_time_altzone+:} false; then : +if test "${ac_cv_header_time_altzone+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -10886,7 +10898,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for addrinfo" >&5 $as_echo_n "checking for addrinfo... " >&6; } -if ${ac_cv_struct_addrinfo+:} false; then : +if test "${ac_cv_struct_addrinfo+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10918,7 +10930,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sockaddr_storage" >&5 $as_echo_n "checking for sockaddr_storage... " >&6; } -if ${ac_cv_struct_sockaddr_storage+:} false; then : +if test "${ac_cv_struct_sockaddr_storage+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10954,7 +10966,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether char is unsigned" >&5 $as_echo_n "checking whether char is unsigned... " >&6; } -if ${ac_cv_c_char_unsigned+:} false; then : +if test "${ac_cv_c_char_unsigned+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10986,7 +10998,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if ${ac_cv_c_const+:} false; then : +if test "${ac_cv_c_const+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11274,7 +11286,7 @@ ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" -if test "x$ac_cv_func_gethostbyname_r" = xyes; then : +if test "x$ac_cv_func_gethostbyname_r" = x""yes; then : $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h @@ -11405,7 +11417,7 @@ for ac_func in gethostbyname do : ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = xyes; then : +if test "x$ac_cv_func_gethostbyname" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTBYNAME 1 _ACEOF @@ -11427,12 +11439,12 @@ # Linux requires this for correct f.p. operations ac_fn_c_check_func "$LINENO" "__fpu_control" "ac_cv_func___fpu_control" -if test "x$ac_cv_func___fpu_control" = xyes; then : +if test "x$ac_cv_func___fpu_control" = x""yes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 $as_echo_n "checking for __fpu_control in -lieee... " >&6; } -if ${ac_cv_lib_ieee___fpu_control+:} false; then : +if test "${ac_cv_lib_ieee___fpu_control+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -11466,7 +11478,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee___fpu_control" >&5 $as_echo "$ac_cv_lib_ieee___fpu_control" >&6; } -if test "x$ac_cv_lib_ieee___fpu_control" = xyes; then : +if test "x$ac_cv_lib_ieee___fpu_control" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBIEEE 1 _ACEOF @@ -11522,7 +11534,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 @@ -11546,7 +11558,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 @@ -11560,7 +11572,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are little-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are little-endian IEEE 754 binary64... " >&6; } -if ${ac_cv_little_endian_double+:} false; then : +if test "${ac_cv_little_endian_double+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -11602,7 +11614,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are big-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are big-endian IEEE 754 binary64... " >&6; } -if ${ac_cv_big_endian_double+:} false; then : +if test "${ac_cv_big_endian_double+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -11648,7 +11660,7 @@ # conversions work. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are ARM mixed-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are ARM mixed-endian IEEE 754 binary64... " >&6; } -if ${ac_cv_mixed_endian_double+:} false; then : +if test "${ac_cv_mixed_endian_double+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -11796,7 +11808,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 @@ -11808,7 +11821,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 @@ -11818,7 +11832,7 @@ ac_fn_c_check_decl "$LINENO" "isinf" "ac_cv_have_decl_isinf" "#include " -if test "x$ac_cv_have_decl_isinf" = xyes; then : +if test "x$ac_cv_have_decl_isinf" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11829,7 +11843,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isnan" "ac_cv_have_decl_isnan" "#include " -if test "x$ac_cv_have_decl_isnan" = xyes; then : +if test "x$ac_cv_have_decl_isnan" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11840,7 +11854,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isfinite" "ac_cv_have_decl_isfinite" "#include " -if test "x$ac_cv_have_decl_isfinite" = xyes; then : +if test "x$ac_cv_have_decl_isfinite" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11855,7 +11869,7 @@ # -0. on some architectures. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tanh preserves the sign of zero" >&5 $as_echo_n "checking whether tanh preserves the sign of zero... " >&6; } -if ${ac_cv_tanh_preserves_zero_sign+:} false; then : +if test "${ac_cv_tanh_preserves_zero_sign+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -11903,7 +11917,7 @@ # -0. See issue #9920. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether log1p drops the sign of negative zero" >&5 $as_echo_n "checking whether log1p drops the sign of negative zero... " >&6; } - if ${ac_cv_log1p_drops_zero_sign+:} false; then : + if test "${ac_cv_log1p_drops_zero_sign+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -11955,7 +11969,7 @@ # sem_open results in a 'Signal 12' error. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX semaphores are enabled" >&5 $as_echo_n "checking whether POSIX semaphores are enabled... " >&6; } -if ${ac_cv_posix_semaphores_enabled+:} false; then : +if test "${ac_cv_posix_semaphores_enabled+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12006,7 +12020,7 @@ # Multiprocessing check for broken sem_getvalue { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken sem_getvalue" >&5 $as_echo_n "checking for broken sem_getvalue... " >&6; } -if ${ac_cv_broken_sem_getvalue+:} false; then : +if test "${ac_cv_broken_sem_getvalue+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12071,7 +12085,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; } @@ -12089,7 +12103,7 @@ # check for wchar.h ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" -if test "x$ac_cv_header_wchar_h" = xyes; then : +if test "x$ac_cv_header_wchar_h" = x""yes; then : $as_echo "#define HAVE_WCHAR_H 1" >>confdefs.h @@ -12112,7 +12126,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 $as_echo_n "checking size of wchar_t... " >&6; } -if ${ac_cv_sizeof_wchar_t+:} false; then : +if test "${ac_cv_sizeof_wchar_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include @@ -12122,8 +12136,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 @@ -12178,7 +12193,7 @@ # check whether wchar_t is signed or not { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wchar_t is signed" >&5 $as_echo_n "checking whether wchar_t is signed... " >&6; } - if ${ac_cv_wchar_t_signed+:} false; then : + if test "${ac_cv_wchar_t_signed+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -12274,7 +12289,7 @@ # check for endianness { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if ${ac_cv_c_bigendian+:} false; then : +if test "${ac_cv_c_bigendian+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown @@ -12492,7 +12507,7 @@ ;; #( *) - as_fn_error $? "unknown endianness + as_fn_error "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac @@ -12565,7 +12580,7 @@ # or fills with zeros (like the Cray J90, according to Tim Peters). { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether right shift extends the sign bit" >&5 $as_echo_n "checking whether right shift extends the sign bit... " >&6; } -if ${ac_cv_rshift_extends_sign+:} false; then : +if test "${ac_cv_rshift_extends_sign+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -12604,7 +12619,7 @@ # check for getc_unlocked and related locking functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getc_unlocked() and friends" >&5 $as_echo_n "checking for getc_unlocked() and friends... " >&6; } -if ${ac_cv_have_getc_unlocked+:} false; then : +if test "${ac_cv_have_getc_unlocked+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -12702,7 +12717,7 @@ # check for readline 2.1 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_callback_handler_install in -lreadline" >&5 $as_echo_n "checking for rl_callback_handler_install in -lreadline... " >&6; } -if ${ac_cv_lib_readline_rl_callback_handler_install+:} false; then : +if test "${ac_cv_lib_readline_rl_callback_handler_install+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12736,7 +12751,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_callback_handler_install" >&5 $as_echo "$ac_cv_lib_readline_rl_callback_handler_install" >&6; } -if test "x$ac_cv_lib_readline_rl_callback_handler_install" = xyes; then : +if test "x$ac_cv_lib_readline_rl_callback_handler_install" = x""yes; then : $as_echo "#define HAVE_RL_CALLBACK 1" >>confdefs.h @@ -12754,7 +12769,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 @@ -12788,7 +12803,7 @@ # check for readline 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_pre_input_hook in -lreadline" >&5 $as_echo_n "checking for rl_pre_input_hook in -lreadline... " >&6; } -if ${ac_cv_lib_readline_rl_pre_input_hook+:} false; then : +if test "${ac_cv_lib_readline_rl_pre_input_hook+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12822,7 +12837,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_pre_input_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_pre_input_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_pre_input_hook" = xyes; then : +if test "x$ac_cv_lib_readline_rl_pre_input_hook" = x""yes; then : $as_echo "#define HAVE_RL_PRE_INPUT_HOOK 1" >>confdefs.h @@ -12832,7 +12847,7 @@ # also in 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_display_matches_hook in -lreadline" >&5 $as_echo_n "checking for rl_completion_display_matches_hook in -lreadline... " >&6; } -if ${ac_cv_lib_readline_rl_completion_display_matches_hook+:} false; then : +if test "${ac_cv_lib_readline_rl_completion_display_matches_hook+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12866,7 +12881,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_display_matches_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_display_matches_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = xyes; then : +if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = x""yes; then : $as_echo "#define HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK 1" >>confdefs.h @@ -12876,7 +12891,7 @@ # check for readline 4.2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_matches in -lreadline" >&5 $as_echo_n "checking for rl_completion_matches in -lreadline... " >&6; } -if ${ac_cv_lib_readline_rl_completion_matches+:} false; then : +if test "${ac_cv_lib_readline_rl_completion_matches+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12910,7 +12925,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_matches" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_matches" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_matches" = xyes; then : +if test "x$ac_cv_lib_readline_rl_completion_matches" = x""yes; then : $as_echo "#define HAVE_RL_COMPLETION_MATCHES 1" >>confdefs.h @@ -12928,7 +12943,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 @@ -12951,7 +12966,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken nice()" >&5 $as_echo_n "checking for broken nice()... " >&6; } -if ${ac_cv_broken_nice+:} false; then : +if test "${ac_cv_broken_nice+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -12992,7 +13007,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken poll()" >&5 $as_echo_n "checking for broken poll()... " >&6; } -if ${ac_cv_broken_poll+:} false; then : +if test "${ac_cv_broken_poll+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13047,7 +13062,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -13063,7 +13078,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = xyes; then : +if test "x$ac_cv_have_decl_tzname" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -13075,7 +13090,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if ${ac_cv_var_tzname+:} false; then : +if test "${ac_cv_var_tzname+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13114,7 +13129,7 @@ # check tzset(3) exists and works like we expect it to { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working tzset()" >&5 $as_echo_n "checking for working tzset()... " >&6; } -if ${ac_cv_working_tzset+:} false; then : +if test "${ac_cv_working_tzset+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -13211,7 +13226,7 @@ # Look for subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec in struct stat" >&5 $as_echo_n "checking for tv_nsec in struct stat... " >&6; } -if ${ac_cv_stat_tv_nsec+:} false; then : +if test "${ac_cv_stat_tv_nsec+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13248,7 +13263,7 @@ # Look for BSD style subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec2 in struct stat" >&5 $as_echo_n "checking for tv_nsec2 in struct stat... " >&6; } -if ${ac_cv_stat_tv_nsec2+:} false; then : +if test "${ac_cv_stat_tv_nsec2+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13285,7 +13300,7 @@ # On HP/UX 11.0, mvwdelch is a block with a return statement { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mvwdelch is an expression" >&5 $as_echo_n "checking whether mvwdelch is an expression... " >&6; } -if ${ac_cv_mvwdelch_is_expression+:} false; then : +if test "${ac_cv_mvwdelch_is_expression+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13322,7 +13337,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether WINDOW has _flags" >&5 $as_echo_n "checking whether WINDOW has _flags... " >&6; } -if ${ac_cv_window_has_flags+:} false; then : +if test "${ac_cv_window_has_flags+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13470,7 +13485,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %lld and %llu printf() format support" >&5 $as_echo_n "checking for %lld and %llu printf() format support... " >&6; } - if ${ac_cv_have_long_long_format+:} false; then : + if test "${ac_cv_have_long_long_format+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13540,7 +13555,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %zd printf() format support" >&5 $as_echo_n "checking for %zd printf() format support... " >&6; } -if ${ac_cv_have_size_t_format+:} false; then : +if test "${ac_cv_have_size_t_format+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13613,7 +13628,7 @@ #endif " -if test "x$ac_cv_type_socklen_t" = xyes; then : +if test "x$ac_cv_type_socklen_t" = x""yes; then : else @@ -13624,7 +13639,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken mbstowcs" >&5 $as_echo_n "checking for broken mbstowcs... " >&6; } -if ${ac_cv_broken_mbstowcs+:} false; then : +if test "${ac_cv_broken_mbstowcs+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13664,7 +13679,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports computed gotos" >&5 $as_echo_n "checking whether $CC supports computed gotos... " >&6; } -if ${ac_cv_computed_gotos+:} false; then : +if test "${ac_cv_computed_gotos+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13744,7 +13759,7 @@ ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" -if test "x$ac_cv_func_pipe2" = xyes; then : +if test "x$ac_cv_func_pipe2" = x""yes; then : $as_echo "#define HAVE_PIPE2 1" >>confdefs.h @@ -13839,21 +13854,10 @@ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then + test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi + cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} @@ -13869,7 +13873,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$//' @@ -13886,7 +13889,7 @@ -: "${CONFIG_STATUS=./config.status}" +: ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" @@ -13987,7 +13990,6 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -14033,19 +14035,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 @@ -14241,7 +14243,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 @@ -14295,7 +14297,7 @@ # values after options handling. ac_log=" This file was extended by python $as_me 3.3, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -14319,8 +14321,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 @@ -14357,10 +14359,10 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ python config.status 3.3 -configured by $0, generated by GNU Autoconf 2.68, +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." @@ -14376,16 +14378,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 @@ -14407,7 +14404,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;; @@ -14420,7 +14416,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 ;; @@ -14429,7 +14425,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" @@ -14488,7 +14484,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 @@ -14510,10 +14506,9 @@ # after its creation but before its name has been assigned to `$tmp'. $debug || { - tmp= ac_tmp= + tmp= trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } @@ -14521,13 +14516,12 @@ { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" + test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp +} || 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. @@ -14544,12 +14538,12 @@ 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 -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF @@ -14558,18 +14552,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 @@ -14577,7 +14571,7 @@ rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h @@ -14625,7 +14619,7 @@ rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && +cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" @@ -14657,29 +14651,21 @@ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || 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 +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# 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 @@ -14691,7 +14677,7 @@ # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || +cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF @@ -14703,11 +14689,11 @@ # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + 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 @@ -14792,7 +14778,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" @@ -14805,7 +14791,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 @@ -14824,7 +14810,7 @@ for ac_f do case $ac_f in - -) ac_f="$ac_tmp/stdin";; + -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. @@ -14833,7 +14819,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'" @@ -14859,8 +14845,8 @@ esac case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -14990,24 +14976,23 @@ s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 +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 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && + { 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;} - - rm -f "$ac_tmp/stdin" +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + -) 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) # @@ -15016,21 +15001,21 @@ if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || 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 "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error "could not create -" "$LINENO" 5 fi ;; @@ -15050,7 +15035,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. @@ -15071,7 +15056,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 diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -2608,6 +2608,15 @@ [AC_MSG_RESULT(no) ]) +AC_MSG_CHECKING(whether mallopt can set malloc mmap threshold) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +]], [[mallopt(M_MMAP_THRESHOLD, 256 * 1024)]])], + [AC_DEFINE(HAVE_MALLOPT_MMAP_THRESHOLD, 1, Define if mallopt can set malloc mmap threshold.) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no) +]) + dnl check for true AC_CHECK_PROGS(TRUE, true, /bin/true) diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -491,6 +491,9 @@ /* Define this if you have the makedev macro. */ #undef HAVE_MAKEDEV +/* Define this if mallopt can set malloc mmap threshold. */ +#undef HAVE_MALLOPT_MMAP_THRESHOLD + /* Define to 1 if you have the `mbrtowc' function. */ #undef HAVE_MBRTOWC -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 19:44:39 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 03 May 2011 19:44:39 +0200 Subject: [Python-checkins] cpython (2.7): #11985: document the return value of platform.python_implementation for PyPy. Message-ID: http://hg.python.org/cpython/rev/f6c85df15874 changeset: 69806:f6c85df15874 branch: 2.7 parent: 69804:dd58f8072216 user: Ezio Melotti date: Tue May 03 20:41:48 2011 +0300 summary: #11985: document the return value of platform.python_implementation for PyPy. files: Doc/library/platform.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -108,7 +108,7 @@ .. function:: python_implementation() Returns a string identifying the Python implementation. Possible return values - are: 'CPython', 'IronPython', 'Jython'. + are: 'CPython', 'IronPython', 'Jython', 'PyPy'. .. versionadded:: 2.6 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 19:44:41 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 03 May 2011 19:44:41 +0200 Subject: [Python-checkins] cpython (3.1): #11985: document the return value of platform.python_implementation for PyPy. Message-ID: http://hg.python.org/cpython/rev/4d946d4166fc changeset: 69807:4d946d4166fc branch: 3.1 parent: 69762:ecf41fca3273 user: Ezio Melotti date: Tue May 03 20:41:48 2011 +0300 summary: #11985: document the return value of platform.python_implementation for PyPy. files: Doc/library/platform.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -104,7 +104,7 @@ .. function:: python_implementation() Returns a string identifying the Python implementation. Possible return values - are: 'CPython', 'IronPython', 'Jython'. + are: 'CPython', 'IronPython', 'Jython', 'PyPy'. .. function:: python_revision() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 19:44:44 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 03 May 2011 19:44:44 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11985: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/5e661f5c301a changeset: 69808:5e661f5c301a branch: 3.2 parent: 69801:4219747d3765 parent: 69807:4d946d4166fc user: Ezio Melotti date: Tue May 03 20:43:48 2011 +0300 summary: #11985: merge with 3.1. files: Doc/library/platform.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -107,7 +107,7 @@ .. function:: python_implementation() Returns a string identifying the Python implementation. Possible return values - are: 'CPython', 'IronPython', 'Jython'. + are: 'CPython', 'IronPython', 'Jython', 'PyPy'. .. function:: python_revision() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 19:44:45 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 03 May 2011 19:44:45 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11985: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/847a38d787be changeset: 69809:847a38d787be parent: 69805:f8a697bc3ca8 parent: 69808:5e661f5c301a user: Ezio Melotti date: Tue May 03 20:44:26 2011 +0300 summary: #11985: merge with 3.2. files: Doc/library/platform.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -107,7 +107,7 @@ .. function:: python_implementation() Returns a string identifying the Python implementation. Possible return values - are: 'CPython', 'IronPython', 'Jython'. + are: 'CPython', 'IronPython', 'Jython', 'PyPy'. .. function:: python_revision() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 20:16:49 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 03 May 2011 20:16:49 +0200 Subject: [Python-checkins] cpython (3.2): Fix __hash__ in functools.cmp_to_key() to work with collections.Hashable. Message-ID: http://hg.python.org/cpython/rev/2675415c57c1 changeset: 69810:2675415c57c1 branch: 3.2 parent: 69808:5e661f5c301a user: Raymond Hettinger date: Tue May 03 11:01:32 2011 -0700 summary: Fix __hash__ in functools.cmp_to_key() to work with collections.Hashable. files: Lib/functools.py | 3 +-- Lib/test/test_functools.py | 5 ++++- Misc/NEWS | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -111,8 +111,7 @@ return mycmp(self.obj, other.obj) >= 0 def __ne__(self, other): return mycmp(self.obj, other.obj) != 0 - def __hash__(self): - raise TypeError('hash not implemented') + __hash__ = None return K _CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize") diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -1,4 +1,5 @@ import functools +import collections import sys import unittest from test import support @@ -446,7 +447,8 @@ return y - x key = functools.cmp_to_key(mycmp) k = key(10) - self.assertRaises(TypeError, hash(k)) + self.assertRaises(TypeError, hash, k) + self.assertFalse(isinstance(k, collections.Hashable)) class TestTotalOrdering(unittest.TestCase): @@ -660,6 +662,7 @@ TestPythonPartial, TestUpdateWrapper, TestTotalOrdering, + TestCmpToKey, TestWraps, TestReduce, TestLRU, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -81,6 +81,8 @@ - logging: don't define QueueListener if Python has no thread support. +- functools.cmp_to_key() now works with collections.Hashable(). + - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 20:16:50 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 03 May 2011 20:16:50 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Fix __hash__ in functools.cmp_to_key() to work with collections.Hashable. Message-ID: http://hg.python.org/cpython/rev/27e5c10ad0bf changeset: 69811:27e5c10ad0bf parent: 69809:847a38d787be parent: 69810:2675415c57c1 user: Raymond Hettinger date: Tue May 03 11:16:36 2011 -0700 summary: Fix __hash__ in functools.cmp_to_key() to work with collections.Hashable. files: Lib/functools.py | 3 +-- Lib/test/test_functools.py | 4 +++- Misc/NEWS | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -111,8 +111,7 @@ return mycmp(self.obj, other.obj) >= 0 def __ne__(self, other): return mycmp(self.obj, other.obj) != 0 - def __hash__(self): - raise TypeError('hash not implemented') + __hash__ = None return K try: diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -1,4 +1,5 @@ import functools +import collections import sys import unittest from test import support @@ -510,6 +511,7 @@ key = functools.cmp_to_key(mycmp) k = key(10) self.assertRaises(TypeError, hash, k) + self.assertNotIsInstance(k, collections.Hashable) class TestTotalOrdering(unittest.TestCase): @@ -718,12 +720,12 @@ def test_main(verbose=None): test_classes = ( - TestCmpToKey, TestPartial, TestPartialSubclass, TestPythonPartial, TestUpdateWrapper, TestTotalOrdering, + TestCmpToKey, TestWraps, TestReduce, TestLRU, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -141,6 +141,8 @@ - logging: don't define QueueListener if Python has no thread support. +- functools.cmp_to_key() now works with collections.Hashable(). + - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 20:36:41 2011 From: python-checkins at python.org (brian.curtin) Date: Tue, 03 May 2011 20:36:41 +0200 Subject: [Python-checkins] cpython (2.7): Denote 3.3.0 as the last supported Windows 2000 release. Message-ID: http://hg.python.org/cpython/rev/de53c52fbcbf changeset: 69812:de53c52fbcbf branch: 2.7 parent: 69806:f6c85df15874 user: Brian Curtin date: Tue May 03 13:36:34 2011 -0500 summary: Denote 3.3.0 as the last supported Windows 2000 release. This corresponds with change b9390aa12855 to PEP-11. files: Tools/msi/msi.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -505,7 +505,7 @@ " would still be Python for DOS.") c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003, - "{\\VerdanaRed9}Warning: Python 2.7.x is the last " + "{\\VerdanaRed9}Warning: Python 3.3.0 is the last " "Python release for Windows 2000.") c.condition("Hide", "VersionNT > 500") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 22:03:10 2011 From: python-checkins at python.org (mark.dickinson) Date: Tue, 03 May 2011 22:03:10 +0200 Subject: [Python-checkins] cpython: Remove an unused import and an unused local definition from test_math.py. Message-ID: http://hg.python.org/cpython/rev/465bcdd564db changeset: 69813:465bcdd564db parent: 69811:27e5c10ad0bf user: Mark Dickinson date: Tue May 03 21:02:51 2011 +0100 summary: Remove an unused import and an unused local definition from test_math.py. files: Lib/test/test_math.py | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -6,7 +6,6 @@ import math import os import sys -import random import struct import sysconfig @@ -1010,7 +1009,6 @@ @requires_IEEE_754 def test_mtestfile(self): - ALLOWED_ERROR = 20 # permitted error, in ulps fail_fmt = "{}:{}({!r}): expected {!r}, got {!r}" failures = [] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 3 22:20:07 2011 From: python-checkins at python.org (mark.dickinson) Date: Tue, 03 May 2011 22:20:07 +0200 Subject: [Python-checkins] cpython: test_math.py: Use correct signs on zeros for expected fmod results. Message-ID: http://hg.python.org/cpython/rev/21e2e06fea4a changeset: 69814:21e2e06fea4a user: Mark Dickinson date: Tue May 03 21:13:40 2011 +0100 summary: test_math.py: Use correct signs on zeros for expected fmod results. files: Lib/test/test_math.py | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -456,12 +456,12 @@ def testFmod(self): self.assertRaises(TypeError, math.fmod) - self.ftest('fmod(10,1)', math.fmod(10,1), 0) - self.ftest('fmod(10,0.5)', math.fmod(10,0.5), 0) - self.ftest('fmod(10,1.5)', math.fmod(10,1.5), 1) - self.ftest('fmod(-10,1)', math.fmod(-10,1), 0) - self.ftest('fmod(-10,0.5)', math.fmod(-10,0.5), 0) - self.ftest('fmod(-10,1.5)', math.fmod(-10,1.5), -1) + self.ftest('fmod(10, 1)', math.fmod(10, 1), 0.0) + self.ftest('fmod(10, 0.5)', math.fmod(10, 0.5), 0.0) + self.ftest('fmod(10, 1.5)', math.fmod(10, 1.5), 1.0) + self.ftest('fmod(-10, 1)', math.fmod(-10, 1), -0.0) + self.ftest('fmod(-10, 0.5)', math.fmod(-10, 0.5), -0.0) + self.ftest('fmod(-10, 1.5)', math.fmod(-10, 1.5), -1.0) self.assertTrue(math.isnan(math.fmod(NAN, 1.))) self.assertTrue(math.isnan(math.fmod(1., NAN))) self.assertTrue(math.isnan(math.fmod(NAN, NAN))) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed May 4 04:58:22 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 04 May 2011 04:58:22 +0200 Subject: [Python-checkins] Daily reference leaks (21e2e06fea4a): sum=-323 Message-ID: results for 21e2e06fea4a on branch "default" -------------------------------------------- test_pyexpat leaked [-56, -267, 0] references, sum=-323 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogz3DgRa', '-x'] From python-checkins at python.org Wed May 4 05:02:16 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 04 May 2011 05:02:16 +0200 Subject: [Python-checkins] cpython (3.1): Fix #11834. Correct site-packages paths. Message-ID: http://hg.python.org/cpython/rev/175dcc8c4b23 changeset: 69815:175dcc8c4b23 branch: 3.1 parent: 69807:4d946d4166fc user: Brian Curtin date: Tue May 03 21:57:00 2011 -0500 summary: Fix #11834. Correct site-packages paths. Patch by Bryce Verdier. files: Doc/install/index.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -241,7 +241,7 @@ +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ | Unix (non-pure) | :file:`{exec-prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) | +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Windows | :file:`{prefix}` | :file:`C:\\Python` | \(2) | +| Windows | :file:`{prefix}\\Lib\\site-packages` | :file:`C:\\Python{XY}\\Lib\\site-packages` | \(2) | +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ Notes: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 05:02:17 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 04 May 2011 05:02:17 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Fix #11834. Correct site-packages paths. Message-ID: http://hg.python.org/cpython/rev/03d511dec224 changeset: 69816:03d511dec224 branch: 3.2 parent: 69810:2675415c57c1 parent: 69815:175dcc8c4b23 user: Brian Curtin date: Tue May 03 21:57:56 2011 -0500 summary: Fix #11834. Correct site-packages paths. Patch by Bryce Verdier. files: Doc/install/index.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -241,7 +241,7 @@ +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ | Unix (non-pure) | :file:`{exec-prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) | +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Windows | :file:`{prefix}` | :file:`C:\\Python` | \(2) | +| Windows | :file:`{prefix}\\Lib\\site-packages` | :file:`C:\\Python{XY}\\Lib\\site-packages` | \(2) | +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ Notes: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 05:02:21 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 04 May 2011 05:02:21 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Fix #11834. Correct site-packages paths. Message-ID: http://hg.python.org/cpython/rev/066e63425228 changeset: 69817:066e63425228 parent: 69814:21e2e06fea4a parent: 69816:03d511dec224 user: Brian Curtin date: Tue May 03 21:58:32 2011 -0500 summary: Fix #11834. Correct site-packages paths. Patch by Bryce Verdier. files: Doc/install/index.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -241,7 +241,7 @@ +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ | Unix (non-pure) | :file:`{exec-prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) | +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Windows | :file:`{prefix}` | :file:`C:\\Python` | \(2) | +| Windows | :file:`{prefix}\\Lib\\site-packages` | :file:`C:\\Python{XY}\\Lib\\site-packages` | \(2) | +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ Notes: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 05:02:22 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 04 May 2011 05:02:22 +0200 Subject: [Python-checkins] cpython (2.7): Fix #11834. Correct site-packages paths. Message-ID: http://hg.python.org/cpython/rev/1a2f0f545f55 changeset: 69818:1a2f0f545f55 branch: 2.7 parent: 69812:de53c52fbcbf user: Brian Curtin date: Tue May 03 22:01:53 2011 -0500 summary: Fix #11834. Correct site-packages paths. Patch by Bryce Verdier. files: Doc/install/index.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -241,7 +241,7 @@ +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ | Unix (non-pure) | :file:`{exec-prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) | +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Windows | :file:`{prefix}` | :file:`C:\\Python` | \(2) | +| Windows | :file:`{prefix}\\Lib\\site-packages` | :file:`C:\\Python{XY}\\Lib\\site-packages` | \(2) | +-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ Notes: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 11:02:25 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 May 2011 11:02:25 +0200 Subject: [Python-checkins] cpython: regrtest: dump all threads on a crash, not only the current thread Message-ID: http://hg.python.org/cpython/rev/17f9019fc6e9 changeset: 69819:17f9019fc6e9 parent: 69817:066e63425228 user: Victor Stinner date: Wed May 04 11:02:12 2011 +0200 summary: regrtest: dump all threads on a crash, not only the current thread files: Lib/test/regrtest.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1589,7 +1589,7 @@ if __name__ == '__main__': # Display the Python traceback on segfault and division by zero - faulthandler.enable() + faulthandler.enable(all_threads=True) # Remove regrtest.py's own directory from the module search path. Despite # the elimination of implicit relative imports, this is still needed to -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 12:38:18 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 May 2011 12:38:18 +0200 Subject: [Python-checkins] cpython: Issue #11998, issue #8407: workaround _tkinter issue in test_signal Message-ID: http://hg.python.org/cpython/rev/88dca05ed468 changeset: 69820:88dca05ed468 user: Victor Stinner date: Wed May 04 12:38:03 2011 +0200 summary: Issue #11998, issue #8407: workaround _tkinter issue in test_signal The _tkinter module loads the Tcl library which creates a thread waiting events in select(). This thread receives signals blocked by all other threads. We cannot test blocked signals if the _tkinter module is loaded. files: Lib/test/test_signal.py | 19 ++++++++++++++++--- 1 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -517,6 +517,15 @@ # function. faulthandler.cancel_dump_tracebacks_later() + # Issue #11998: The _tkinter module loads the Tcl library which creates + # a thread waiting events in select(). This thread receives signals + # blocked by all other threads. We cannot test blocked signals if the + # _tkinter module is loaded. + can_test_blocked_signals = ('_tkinter' not in sys.modules) + if not can_test_blocked_signals: + print("WARNING: _tkinter is loaded, cannot test signals " + "blocked by pthread_sigmask() (issue #11998)") + # Install our signal handler old_handler = signal.signal(signum, handler) self.addCleanup(signal.signal, signum, old_handler) @@ -530,7 +539,8 @@ # Block and then raise SIGUSR1. The signal is blocked: the signal # handler is not called, and the signal is now pending signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) - os.kill(pid, signum) + if can_test_blocked_signals: + os.kill(pid, signum) # Check the new mask blocked = read_sigmask() @@ -538,8 +548,11 @@ self.assertEqual(set(old_mask) ^ set(blocked), {signum}) # Unblock SIGUSR1 - with self.assertRaises(ZeroDivisionError): - # unblock the pending signal calls immediatly the signal handler + if can_test_blocked_signals: + with self.assertRaises(ZeroDivisionError): + # unblock the pending signal calls immediatly the signal handler + signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + else: signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) with self.assertRaises(ZeroDivisionError): os.kill(pid, signum) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 13:20:44 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 May 2011 13:20:44 +0200 Subject: [Python-checkins] cpython: Issue #8407: signal.pthread_sigmask() returns a set instead of a list Message-ID: http://hg.python.org/cpython/rev/a5890ff5e3d5 changeset: 69821:a5890ff5e3d5 user: Victor Stinner date: Wed May 04 13:20:35 2011 +0200 summary: Issue #8407: signal.pthread_sigmask() returns a set instead of a list Update the doc. Refactor also related tests. files: Doc/library/signal.rst | 7 +- Lib/test/test_signal.py | 33 ++++++++------ Modules/signalmodule.c | 65 ++++++++++++++++------------ 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -184,7 +184,7 @@ Fetch and/or change the signal mask of the calling thread. The signal mask is the set of signals whose delivery is currently blocked for the caller. - The old signal mask is returned. + Return the old signal mask as a set of signals. The behavior of the call is dependent on the value of *how*, as follows. @@ -196,8 +196,9 @@ * :data:`SIG_SETMASK`: The set of blocked signals is set to the *mask* argument. - *mask* is a list of signal numbers (e.g. [:const:`signal.SIGINT`, - :const:`signal.SIGTERM`]). + *mask* is a set of signal numbers (e.g. {:const:`signal.SIGINT`, + :const:`signal.SIGTERM`}). Use ``range(1, signal.NSIG)`` for a full mask + including all signals. For example, ``signal.pthread_sigmask(signal.SIG_BLOCK, [])`` reads the signal mask of the calling thread. diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -486,24 +486,27 @@ @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), 'need signal.pthread_sigmask()') -class PthreadSigmaskTests(unittest.TestCase): - def test_arguments(self): +class PendingSignalsTests(unittest.TestCase): + """ + Tests for the pthread_sigmask() function. + """ + def handler(self, signum, frame): + 1/0 + + def read_sigmask(self): + return signal.pthread_sigmask(signal.SIG_BLOCK, []) + + def test_pthread_sigmask_arguments(self): self.assertRaises(TypeError, signal.pthread_sigmask) self.assertRaises(TypeError, signal.pthread_sigmask, 1) self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3) self.assertRaises(RuntimeError, signal.pthread_sigmask, 1700, []) - def test_block_unlock(self): + def test_pthread_sigmask(self): import faulthandler pid = os.getpid() signum = signal.SIGUSR1 - def handler(signum, frame): - 1/0 - - def read_sigmask(): - return signal.pthread_sigmask(signal.SIG_BLOCK, []) - # The fault handler timeout thread masks all signals. If the main # thread masks also SIGUSR1, all threads mask this signal. In this # case, if we send SIGUSR1 to the process, the signal is pending in the @@ -527,7 +530,7 @@ "blocked by pthread_sigmask() (issue #11998)") # Install our signal handler - old_handler = signal.signal(signum, handler) + old_handler = signal.signal(signum, self.handler) self.addCleanup(signal.signal, signum, old_handler) # Unblock SIGUSR1 (and copy the old mask) to test our signal handler @@ -543,9 +546,9 @@ os.kill(pid, signum) # Check the new mask - blocked = read_sigmask() + blocked = self.read_sigmask() self.assertIn(signum, blocked) - self.assertEqual(set(old_mask) ^ set(blocked), {signum}) + self.assertEqual(old_mask ^ blocked, {signum}) # Unblock SIGUSR1 if can_test_blocked_signals: @@ -558,9 +561,9 @@ os.kill(pid, signum) # Check the new mask - unblocked = read_sigmask() + unblocked = self.read_sigmask() self.assertNotIn(signum, unblocked) - self.assertEqual(set(blocked) ^ set(unblocked), {signum}) + self.assertEqual(blocked ^ unblocked, {signum}) self.assertSequenceEqual(old_mask, unblocked) # Finally, restore the previous signal handler and the signal mask @@ -570,7 +573,7 @@ support.run_unittest(BasicSignalTests, InterProcessSignalTests, WakeupSignalTests, SiginterruptTest, ItimerTest, WindowsSignalTests, - PthreadSigmaskTests) + PendingSignalsTests) finally: support.reap_children() diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -552,11 +552,45 @@ return result; } +static PyObject* +sigset_to_set(sigset_t mask) +{ + PyObject *signum, *result; + int sig; + + result = PySet_New(0); + if (result == NULL) + return NULL; + + for (sig = 1; sig < NSIG; sig++) { + if (sigismember(&mask, sig) != 1) + continue; + + /* Handle the case where it is a member by adding the signal to + the result list. Ignore the other cases because they mean the + signal isn't a member of the mask or the signal was invalid, + and an invalid signal must have been our fault in constructing + the loop boundaries. */ + signum = PyLong_FromLong(sig); + if (signum == NULL) { + Py_DECREF(result); + return NULL; + } + if (PySet_Add(result, signum) == -1) { + Py_DECREF(signum); + Py_DECREF(result); + return NULL; + } + Py_DECREF(signum); + } + return result; +} + static PyObject * signal_pthread_sigmask(PyObject *self, PyObject *args) { - int how, sig; - PyObject *signals, *result, *signum; + int how; + PyObject *signals; sigset_t mask, previous; int err; @@ -577,32 +611,7 @@ if (PyErr_CheckSignals()) return NULL; - result = PyList_New(0); - if (result == NULL) - return NULL; - - for (sig = 1; sig < NSIG; sig++) { - if (sigismember(&previous, sig) != 1) - continue; - - /* Handle the case where it is a member by adding the signal to - the result list. Ignore the other cases because they mean the - signal isn't a member of the mask or the signal was invalid, - and an invalid signal must have been our fault in constructing - the loop boundaries. */ - signum = PyLong_FromLong(sig); - if (signum == NULL) { - Py_DECREF(result); - return NULL; - } - if (PyList_Append(result, signum) == -1) { - Py_DECREF(signum); - Py_DECREF(result); - return NULL; - } - Py_DECREF(signum); - } - return result; + return sigset_to_set(previous); } PyDoc_STRVAR(signal_pthread_sigmask_doc, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 13:41:40 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 04 May 2011 13:41:40 +0200 Subject: [Python-checkins] cpython (2.7): #11982: fix json.loads('""') to return u'' rather than ''. Message-ID: http://hg.python.org/cpython/rev/9d5a50e5d8a2 changeset: 69822:9d5a50e5d8a2 branch: 2.7 parent: 69818:1a2f0f545f55 user: Ezio Melotti date: Wed May 04 14:40:53 2011 +0300 summary: #11982: fix json.loads('""') to return u'' rather than ''. files: Lib/json/tests/test_decode.py | 3 ++- Misc/NEWS | 2 ++ Modules/_json.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/json/tests/test_decode.py b/Lib/json/tests/test_decode.py --- a/Lib/json/tests/test_decode.py +++ b/Lib/json/tests/test_decode.py @@ -26,7 +26,8 @@ def test_empty_objects(self): self.assertEqual(json.loads('{}'), {}) self.assertEqual(json.loads('[]'), []) - self.assertEqual(json.loads('""'), "") + self.assertEqual(json.loads('""'), u"") + self.assertIsInstance(json.loads('""'), unicode) def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -77,6 +77,8 @@ Library ------- +- Issue #11982: fix json.loads('""') to return u'' rather than ''. + - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -595,7 +595,7 @@ Py_DECREF(chunk); } - rval = join_list_string(chunks); + rval = join_list_unicode(chunks); if (rval == NULL) { goto bail; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 13:55:47 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 May 2011 13:55:47 +0200 Subject: [Python-checkins] cpython: Replace open(filename, 'rU') by open(filename, 'r') Message-ID: http://hg.python.org/cpython/rev/be5b8d1ded34 changeset: 69823:be5b8d1ded34 parent: 69821:a5890ff5e3d5 user: Victor Stinner date: Wed May 04 13:55:36 2011 +0200 summary: Replace open(filename, 'rU') by open(filename, 'r') The U flag is no more used (but still accepted for backward compatibility). files: Lib/pkgutil.py | 4 ++-- Lib/runpy.py | 2 +- Lib/site.py | 4 ++-- Lib/test/test_tarfile.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -248,7 +248,7 @@ if self.file and self.file.closed: mod_type = self.etc[2] if mod_type==imp.PY_SOURCE: - self.file = open(self.filename, 'rU') + self.file = open(self.filename, 'r') elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION): self.file = open(self.filename, 'rb') @@ -293,7 +293,7 @@ self.file.close() elif mod_type==imp.PY_COMPILED: if os.path.exists(self.filename[:-1]): - f = open(self.filename[:-1], 'rU') + f = open(self.filename[:-1], 'r') self.source = f.read() f.close() elif mod_type==imp.PKG_DIRECTORY: diff --git a/Lib/runpy.py b/Lib/runpy.py --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -226,7 +226,7 @@ code = read_code(f) if code is None: # That didn't work, so try it as normal source code - with open(fname, "rU") as f: + with open(fname, "r") as f: code = compile(f.read(), fname, 'exec') return code diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -138,7 +138,7 @@ reset = 0 fullname = os.path.join(sitedir, name) try: - f = open(fullname, "rU") + f = open(fullname, "r") except IOError: return with f: @@ -385,7 +385,7 @@ for filename in self.__files: filename = os.path.join(dir, filename) try: - fp = open(filename, "rU") + fp = open(filename, "r") data = fp.read() fp.close() break diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -82,7 +82,7 @@ def test_fileobj_iter(self): self.tar.extract("ustar/regtype", TEMPDIR) tarinfo = self.tar.getmember("ustar/regtype") - with open(os.path.join(TEMPDIR, "ustar/regtype"), "rU") as fobj1: + with open(os.path.join(TEMPDIR, "ustar/regtype"), "r") as fobj1: lines1 = fobj1.readlines() fobj2 = self.tar.extractfile(tarinfo) try: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 14:02:20 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 May 2011 14:02:20 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11277: fix issue number in a test_zlib comment Message-ID: http://hg.python.org/cpython/rev/1ef2a7319849 changeset: 69824:1ef2a7319849 branch: 2.7 parent: 69822:9d5a50e5d8a2 user: Victor Stinner date: Wed May 04 14:02:11 2011 +0200 summary: Issue #11277: fix issue number in a test_zlib comment files: Lib/test/test_zlib.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -72,7 +72,7 @@ zlib.crc32('spam', (2**31))) -# Issue #10276 - check that inputs of 2 GB are handled correctly. +# Issue #11277 - check that inputs of 2 GB are handled correctly. # Be aware of issues #1202, #8650, #8651 and #10276 class ChecksumBigBufferTestCase(unittest.TestCase): int_max = 0x7FFFFFFF -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 14:28:45 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 04 May 2011 14:28:45 +0200 Subject: [Python-checkins] cpython (2.7): #11982: remove now unused function. Message-ID: http://hg.python.org/cpython/rev/d3bd384df8ca changeset: 69825:d3bd384df8ca branch: 2.7 user: Ezio Melotti date: Wed May 04 15:28:31 2011 +0300 summary: #11982: remove now unused function. files: Modules/_json.c | 18 ------------------ 1 files changed, 0 insertions(+), 18 deletions(-) diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -380,24 +380,6 @@ } static PyObject * -join_list_string(PyObject *lst) -{ - /* return ''.join(lst) */ - static PyObject *joinfn = NULL; - if (joinfn == NULL) { - PyObject *ustr = PyString_FromStringAndSize(NULL, 0); - if (ustr == NULL) - return NULL; - - joinfn = PyObject_GetAttrString(ustr, "join"); - Py_DECREF(ustr); - if (joinfn == NULL) - return NULL; - } - return PyObject_CallFunctionObjArgs(joinfn, lst, NULL); -} - -static PyObject * _build_rval_index_tuple(PyObject *rval, Py_ssize_t idx) { /* return (rval, idx) tuple, stealing reference to rval */ PyObject *tpl; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 16:28:49 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Wed, 04 May 2011 16:28:49 +0200 Subject: [Python-checkins] cpython: Mention that timezone is a subclass of tzinfo. Message-ID: http://hg.python.org/cpython/rev/d2a27006237b changeset: 69826:d2a27006237b parent: 69823:be5b8d1ded34 user: Alexander Belopolsky date: Wed May 04 10:28:26 2011 -0400 summary: Mention that timezone is a subclass of tzinfo. files: Doc/library/datetime.rst | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1577,11 +1577,12 @@ :class:`timezone` Objects -------------------------- -A :class:`timezone` object represents a timezone that is defined by a -fixed offset from UTC. Note that objects of this class cannot be used -to represent timezone information in the locations where different -offsets are used in different days of the year or where historical -changes have been made to civil time. +The :class:`timezone` class is a subclass of :class:`tzinfo`, each +instance of which represents a timezone defined by a fixed offset from +UTC. Note that objects of this class cannot be used to represent +timezone information in the locations where different offsets are used +in different days of the year or where historical changes have been +made to civil time. .. class:: timezone(offset[, name]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 17:40:12 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 04 May 2011 17:40:12 +0200 Subject: [Python-checkins] cpython (2.7): #11985: update docstring of platform.python_implementation. Message-ID: http://hg.python.org/cpython/rev/affec521b330 changeset: 69827:affec521b330 branch: 2.7 parent: 69825:d3bd384df8ca user: Ezio Melotti date: Wed May 04 18:37:50 2011 +0300 summary: #11985: update docstring of platform.python_implementation. files: Lib/platform.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/platform.py b/Lib/platform.py --- a/Lib/platform.py +++ b/Lib/platform.py @@ -1448,9 +1448,10 @@ """ Returns a string identifying the Python implementation. Currently, the following implementations are identified: - 'CPython' (C implementation of Python), - 'IronPython' (.NET implementation of Python), - 'Jython' (Java implementation of Python). + 'CPython' (C implementation of Python), + 'IronPython' (.NET implementation of Python), + 'Jython' (Java implementation of Python), + 'PyPy' (Python implementation of Python). """ return _sys_version()[0] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 17:40:16 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 04 May 2011 17:40:16 +0200 Subject: [Python-checkins] cpython (3.1): #11985: update docstring of platform.python_implementation. Message-ID: http://hg.python.org/cpython/rev/7bf9d7ae6c94 changeset: 69828:7bf9d7ae6c94 branch: 3.1 parent: 69815:175dcc8c4b23 user: Ezio Melotti date: Wed May 04 18:37:50 2011 +0300 summary: #11985: update docstring of platform.python_implementation. files: Lib/platform.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/platform.py b/Lib/platform.py --- a/Lib/platform.py +++ b/Lib/platform.py @@ -1398,9 +1398,10 @@ """ Returns a string identifying the Python implementation. Currently, the following implementations are identified: - 'CPython' (C implementation of Python), - 'IronPython' (.NET implementation of Python), - 'Jython' (Java implementation of Python). + 'CPython' (C implementation of Python), + 'IronPython' (.NET implementation of Python), + 'Jython' (Java implementation of Python), + 'PyPy' (Python implementation of Python). """ return _sys_version()[0] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 17:40:17 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 04 May 2011 17:40:17 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11985: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/cc7342b4e59d changeset: 69829:cc7342b4e59d branch: 3.2 parent: 69816:03d511dec224 parent: 69828:7bf9d7ae6c94 user: Ezio Melotti date: Wed May 04 18:39:29 2011 +0300 summary: #11985: merge with 3.1. files: Lib/platform.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/platform.py b/Lib/platform.py --- a/Lib/platform.py +++ b/Lib/platform.py @@ -1417,9 +1417,10 @@ """ Returns a string identifying the Python implementation. Currently, the following implementations are identified: - 'CPython' (C implementation of Python), - 'IronPython' (.NET implementation of Python), - 'Jython' (Java implementation of Python). + 'CPython' (C implementation of Python), + 'IronPython' (.NET implementation of Python), + 'Jython' (Java implementation of Python), + 'PyPy' (Python implementation of Python). """ return _sys_version()[0] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 17:40:19 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 04 May 2011 17:40:19 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11985: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/6b95bf39842f changeset: 69830:6b95bf39842f parent: 69826:d2a27006237b parent: 69829:cc7342b4e59d user: Ezio Melotti date: Wed May 04 18:39:59 2011 +0300 summary: #11985: merge with 3.2. files: Lib/platform.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/platform.py b/Lib/platform.py --- a/Lib/platform.py +++ b/Lib/platform.py @@ -1336,9 +1336,10 @@ """ Returns a string identifying the Python implementation. Currently, the following implementations are identified: - 'CPython' (C implementation of Python), - 'IronPython' (.NET implementation of Python), - 'Jython' (Java implementation of Python). + 'CPython' (C implementation of Python), + 'IronPython' (.NET implementation of Python), + 'Jython' (Java implementation of Python), + 'PyPy' (Python implementation of Python). """ return _sys_version()[0] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 18:27:34 2011 From: python-checkins at python.org (alexis.metaireau) Date: Wed, 04 May 2011 18:27:34 +0200 Subject: [Python-checkins] devguide: Add myself to the expert index for packaging Message-ID: http://hg.python.org/devguide/rev/3104feaed18b changeset: 415:3104feaed18b user: Alexis Metaireau date: Wed May 04 17:27:28 2011 +0100 summary: Add myself to the expert index for packaging files: experts.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -304,7 +304,7 @@ mathematics mark.dickinson, eric.smith, lemburg, stutzbach memory management tim_one, lemburg networking giampaolo.rodola -packaging tarek, lemburg +packaging tarek, lemburg, alexis py3 transition benjamin.peterson release management tarek, lemburg, benjamin.peterson, barry, loewis, gvanrossum, anthonybaxter -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed May 4 18:56:48 2011 From: python-checkins at python.org (nick.coghlan) Date: Wed, 04 May 2011 18:56:48 +0200 Subject: [Python-checkins] devguide: Mark theller inactive, update own modules and interest areas Message-ID: http://hg.python.org/devguide/rev/779644152e5b changeset: 416:779644152e5b user: Nick Coghlan date: Thu May 05 02:56:39 2011 +1000 summary: Mark theller inactive, update own modules and interest areas files: experts.rst | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -45,7 +45,7 @@ Module Maintainers ==================== ============================================= __future__ -__main__ gvanrossum +__main__ gvanrossum,ncoghlan _dummy_thread brett.cannon _thread pitrou abc @@ -85,7 +85,7 @@ cProfile crypt jafo* csv skip.montanaro -ctypes theller, belopolsky, amaury.forgeotdarc +ctypes theller (inactive), belopolsky, amaury.forgeotdarc curses datetime belopolsky dbm @@ -141,7 +141,7 @@ math mark.dickinson, rhettinger, stutzbach mimetypes mmap -modulefinder theller, jvr +modulefinder theller (inactive), jvr msilib loewis msvcrt multiprocessing jnoller @@ -210,7 +210,7 @@ tabnanny tim_one (inactive) tarfile lars.gustaebel telnetlib -tempfile georg.brandl +tempfile georg.brandl, ncoghlan termios test textwrap georg.brandl @@ -293,6 +293,7 @@ bug tracker ezio.melotti buildbots bytecode pitrou +context managers ncoghlan data formats mark.dickinson, georg.brandl database lemburg documentation georg.brandl, ezio.melotti @@ -310,6 +311,7 @@ gvanrossum, anthonybaxter str.format eric.smith testing michael.foord, pitrou, giampaolo.rodola, ezio.melotti +test coverage ncoghlan threads pitrou time and dates lemburg, belopolsky unicode lemburg, ezio.melotti, haypo -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed May 4 19:06:36 2011 From: python-checkins at python.org (alexis.metaireau) Date: Wed, 04 May 2011 19:06:36 +0200 Subject: [Python-checkins] cpython: Add a reference to the PEP 398 for python 3.3 release schedule Message-ID: http://hg.python.org/cpython/rev/29504a0ab56d changeset: 69831:29504a0ab56d user: Alexis Metaireau date: Wed May 04 17:58:00 2011 +0100 summary: Add a reference to the PEP 398 for python 3.3 release schedule files: README | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/README b/README --- a/README +++ b/README @@ -161,7 +161,7 @@ Release Schedule ---------------- -See PEP XXX for release details: http://www.python.org/dev/peps/pep-0XXX/ +See PEP 398 for release details: http://www.python.org/dev/peps/pep-0398/ Copyright and License Information -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 20:03:08 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Wed, 04 May 2011 20:03:08 +0200 Subject: [Python-checkins] devguide: experts.rst: move myself from 'testing' to 'test coverage' interest area Message-ID: http://hg.python.org/devguide/rev/e4fa62823052 changeset: 417:e4fa62823052 user: Giampaolo Rodola' date: Wed May 04 20:03:05 2011 +0200 summary: experts.rst: move myself from 'testing' to 'test coverage' interest area files: experts.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -310,8 +310,8 @@ release management tarek, lemburg, benjamin.peterson, barry, loewis, gvanrossum, anthonybaxter str.format eric.smith -testing michael.foord, pitrou, giampaolo.rodola, ezio.melotti -test coverage ncoghlan +testing michael.foord, pitrou, ezio.melotti +test coverage ncoghlan, giampaolo.rodola threads pitrou time and dates lemburg, belopolsky unicode lemburg, ezio.melotti, haypo -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed May 4 20:05:04 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 04 May 2011 20:05:04 +0200 Subject: [Python-checkins] cpython (3.2): Issue #1856: Avoid crashes and lockups when daemon threads run while the Message-ID: http://hg.python.org/cpython/rev/2a19d09b08f8 changeset: 69832:2a19d09b08f8 branch: 3.2 parent: 69829:cc7342b4e59d user: Antoine Pitrou date: Wed May 04 20:02:30 2011 +0200 summary: Issue #1856: Avoid crashes and lockups when daemon threads run while the interpreter is shutting down; instead, these threads are now killed when they try to take the GIL. files: Include/pythonrun.h | 2 + Lib/test/test_threading.py | 45 +++++++++++++++++++++++++- Misc/NEWS | 4 ++ Python/ceval.c | 6 +++ Python/pythonrun.c | 15 ++++++-- Python/thread_pthread.h | 4 +- 6 files changed, 69 insertions(+), 7 deletions(-) diff --git a/Include/pythonrun.h b/Include/pythonrun.h --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -214,6 +214,8 @@ PyAPI_FUNC(void) PyFloat_Fini(void); PyAPI_FUNC(void) PyOS_FiniInterrupts(void); PyAPI_FUNC(void) _PyGC_Fini(void); + +PyAPI_DATA(PyThreadState *) _Py_Finalizing; #endif /* Stuff with no proper home (yet) */ diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -12,6 +12,7 @@ import weakref import os import subprocess +from test.script_helper import assert_python_ok from test import lock_tests @@ -463,7 +464,6 @@ """ self._run_and_join(script) - @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") def test_2_join_in_forked_process(self): # Like the test above, but from a forked interpreter @@ -655,6 +655,49 @@ output = "end of worker thread\nend of main thread\n" self.assertScriptHasOutput(script, output) + def test_6_daemon_threads(self): + # Check that a daemon thread cannot crash the interpreter on shutdown + # by manipulating internal structures that are being disposed of in + # the main thread. + script = """if True: + import os + import random + import sys + import time + import threading + + thread_has_run = set() + + def random_io(): + '''Loop for a while sleeping random tiny amounts and doing some I/O.''' + blank = b'x' * 200 + while True: + in_f = open(os.__file__, 'r') + stuff = in_f.read(200) + null_f = open(os.devnull, 'w') + null_f.write(stuff) + time.sleep(random.random() / 1995) + null_f.close() + in_f.close() + thread_has_run.add(threading.current_thread()) + + def main(): + count = 0 + for _ in range(40): + new_thread = threading.Thread(target=random_io) + new_thread.daemon = True + new_thread.start() + count += 1 + while len(thread_has_run) < count: + time.sleep(0.001) + # Trigger process shutdown + sys.exit(0) + + main() + """ + rc, out, err = assert_python_ok('-c', script) + self.assertFalse(err) + class ThreadingExceptionTests(BaseTestCase): # A RuntimeError should be raised if Thread.start() is called diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #1856: Avoid crashes and lockups when daemon threads run while the + interpreter is shutting down; instead, these threads are now killed when + they try to take the GIL. + - Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. Fix a crash if a class override its __class__ attribute (e.g. a proxy of the diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -440,6 +440,12 @@ if (gil_created()) { int err = errno; take_gil(tstate); + /* _Py_Finalizing is protected by the GIL */ + if (_Py_Finalizing && tstate != _Py_Finalizing) { + drop_gil(tstate); + PyThread_exit_thread(); + assert(0); /* unreachable */ + } errno = err; } #endif diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -90,6 +90,8 @@ int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */ +PyThreadState *_Py_Finalizing = NULL; + /* PyModule_GetWarningsModule is no longer necessary as of 2.6 since _warnings is builtin. This API should not be used. */ PyObject * @@ -188,6 +190,7 @@ if (initialized) return; initialized = 1; + _Py_Finalizing = NULL; #if defined(HAVE_LANGINFO_H) && defined(HAVE_SETLOCALE) /* Set up the LC_CTYPE locale, so we can obtain @@ -388,15 +391,19 @@ * the threads created via Threading. */ call_py_exitfuncs(); + + /* Get current thread state and interpreter pointer */ + tstate = PyThreadState_GET(); + interp = tstate->interp; + + /* Remaining threads (e.g. daemon threads) will automatically exit + after taking the GIL (in PyEval_RestoreThread()). */ + _Py_Finalizing = tstate; initialized = 0; /* Flush stdout+stderr */ flush_std_files(); - /* Get current thread state and interpreter pointer */ - tstate = PyThreadState_GET(); - interp = tstate->interp; - /* Disable signal handling */ PyOS_FiniInterrupts(); diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -250,9 +250,9 @@ PyThread_exit_thread(void) { dprintf(("PyThread_exit_thread called\n")); - if (!initialized) { + if (!initialized) exit(0); - } + pthread_exit(0); } #ifdef USE_SEMAPHORES -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 20:05:07 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 04 May 2011 20:05:07 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #1856: Avoid crashes and lockups when daemon threads run while the Message-ID: http://hg.python.org/cpython/rev/c892b0321d23 changeset: 69833:c892b0321d23 parent: 69831:29504a0ab56d parent: 69832:2a19d09b08f8 user: Antoine Pitrou date: Wed May 04 20:04:29 2011 +0200 summary: Issue #1856: Avoid crashes and lockups when daemon threads run while the interpreter is shutting down; instead, these threads are now killed when they try to take the GIL. files: Include/pythonrun.h | 2 + Lib/test/test_threading.py | 45 +++++++++++++++++++++++++- Misc/NEWS | 4 ++ Python/ceval.c | 6 +++ Python/pythonrun.c | 15 ++++++-- Python/thread_pthread.h | 4 +- 6 files changed, 69 insertions(+), 7 deletions(-) diff --git a/Include/pythonrun.h b/Include/pythonrun.h --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -211,6 +211,8 @@ PyAPI_FUNC(void) PyFloat_Fini(void); PyAPI_FUNC(void) PyOS_FiniInterrupts(void); PyAPI_FUNC(void) _PyGC_Fini(void); + +PyAPI_DATA(PyThreadState *) _Py_Finalizing; #endif /* Stuff with no proper home (yet) */ diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -12,6 +12,7 @@ import weakref import os import subprocess +from test.script_helper import assert_python_ok from test import lock_tests @@ -471,7 +472,6 @@ """ self._run_and_join(script) - @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") def test_2_join_in_forked_process(self): # Like the test above, but from a forked interpreter @@ -663,6 +663,49 @@ output = "end of worker thread\nend of main thread\n" self.assertScriptHasOutput(script, output) + def test_6_daemon_threads(self): + # Check that a daemon thread cannot crash the interpreter on shutdown + # by manipulating internal structures that are being disposed of in + # the main thread. + script = """if True: + import os + import random + import sys + import time + import threading + + thread_has_run = set() + + def random_io(): + '''Loop for a while sleeping random tiny amounts and doing some I/O.''' + blank = b'x' * 200 + while True: + in_f = open(os.__file__, 'r') + stuff = in_f.read(200) + null_f = open(os.devnull, 'w') + null_f.write(stuff) + time.sleep(random.random() / 1995) + null_f.close() + in_f.close() + thread_has_run.add(threading.current_thread()) + + def main(): + count = 0 + for _ in range(40): + new_thread = threading.Thread(target=random_io) + new_thread.daemon = True + new_thread.start() + count += 1 + while len(thread_has_run) < count: + time.sleep(0.001) + # Trigger process shutdown + sys.exit(0) + + main() + """ + rc, out, err = assert_python_ok('-c', script) + self.assertFalse(err) + class ThreadingExceptionTests(BaseTestCase): # A RuntimeError should be raised if Thread.start() is called diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #1856: Avoid crashes and lockups when daemon threads run while the + interpreter is shutting down; instead, these threads are now killed when + they try to take the GIL. + - Issue #11849: Make it more likely for the system allocator to release free()d memory arenas on glibc-based systems. Patch by Charles-Fran?ois Natali. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -440,6 +440,12 @@ if (gil_created()) { int err = errno; take_gil(tstate); + /* _Py_Finalizing is protected by the GIL */ + if (_Py_Finalizing && tstate != _Py_Finalizing) { + drop_gil(tstate); + PyThread_exit_thread(); + assert(0); /* unreachable */ + } errno = err; } #endif diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -93,6 +93,8 @@ int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */ +PyThreadState *_Py_Finalizing = NULL; + /* PyModule_GetWarningsModule is no longer necessary as of 2.6 since _warnings is builtin. This API should not be used. */ PyObject * @@ -191,6 +193,7 @@ if (initialized) return; initialized = 1; + _Py_Finalizing = NULL; #if defined(HAVE_LANGINFO_H) && defined(HAVE_SETLOCALE) /* Set up the LC_CTYPE locale, so we can obtain @@ -395,15 +398,19 @@ * the threads created via Threading. */ call_py_exitfuncs(); + + /* Get current thread state and interpreter pointer */ + tstate = PyThreadState_GET(); + interp = tstate->interp; + + /* Remaining threads (e.g. daemon threads) will automatically exit + after taking the GIL (in PyEval_RestoreThread()). */ + _Py_Finalizing = tstate; initialized = 0; /* Flush stdout+stderr */ flush_std_files(); - /* Get current thread state and interpreter pointer */ - tstate = PyThreadState_GET(); - interp = tstate->interp; - /* Disable signal handling */ PyOS_FiniInterrupts(); diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -244,9 +244,9 @@ PyThread_exit_thread(void) { dprintf(("PyThread_exit_thread called\n")); - if (!initialized) { + if (!initialized) exit(0); - } + pthread_exit(0); } #ifdef USE_SEMAPHORES -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 21:27:50 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 May 2011 21:27:50 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11277: test_zlib tests a buffer of 1 GB on 32 bits Message-ID: http://hg.python.org/cpython/rev/7f3cab59ef3e changeset: 69834:7f3cab59ef3e branch: 2.7 parent: 69827:affec521b330 user: Victor Stinner date: Wed May 04 21:27:39 2011 +0200 summary: Issue #11277: test_zlib tests a buffer of 1 GB on 32 bits (instead of a buffer of 2 GB) files: Lib/test/test_zlib.py | 21 +++++++++++++++------ 1 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -2,7 +2,7 @@ from test.test_support import TESTFN, run_unittest, import_module, unlink, requires import binascii import random -from test.test_support import precisionbigmemtest, _1G +from test.test_support import precisionbigmemtest, _1G, _4G import sys try: @@ -72,20 +72,29 @@ zlib.crc32('spam', (2**31))) -# Issue #11277 - check that inputs of 2 GB are handled correctly. -# Be aware of issues #1202, #8650, #8651 and #10276 +# Issue #11277 - check that inputs of 2 GB (or 1 GB on 32 bits system) are +# handled correctly. Be aware of issues #1202. We cannot test a buffer of 4 GB +# or more (#8650, #8651 and #10276), because the zlib stores the buffer size +# into an int. class ChecksumBigBufferTestCase(unittest.TestCase): - int_max = 0x7FFFFFFF + if sys.maxsize > _4G: + # (64 bits system) crc32() and adler32() stores the buffer size into an + # int, the maximum filesize is INT_MAX (0x7FFFFFFF) + filesize = 0x7FFFFFFF + else: + # (32 bits system) On a 32 bits OS, a process cannot usually address + # more than 2 GB, so test only 1 GB + filesize = _1G @unittest.skipUnless(mmap, "mmap() is not available.") def test_big_buffer(self): if sys.platform[:3] == 'win' or sys.platform == 'darwin': requires('largefile', 'test requires %s bytes and a long time to run' % - str(self.int_max)) + str(self.filesize)) try: with open(TESTFN, "wb+") as f: - f.seek(self.int_max-4) + f.seek(self.filesize-4) f.write("asdf") f.flush() m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 21:41:21 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 May 2011 21:41:21 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11277: oops, fix checksum values of test_zlib on 32 bits Message-ID: http://hg.python.org/cpython/rev/e6a4deb84e47 changeset: 69835:e6a4deb84e47 branch: 2.7 user: Victor Stinner date: Wed May 04 21:40:36 2011 +0200 summary: Issue #11277: oops, fix checksum values of test_zlib on 32 bits files: Lib/test/test_zlib.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -99,8 +99,12 @@ f.flush() m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) try: - self.assertEqual(zlib.crc32(m), 0x709418e7) - self.assertEqual(zlib.adler32(m), -2072837729) + if sys.maxsize > _4G: + self.assertEqual(zlib.crc32(m), 0x709418e7) + self.assertEqual(zlib.adler32(m), -2072837729) + else: + self.assertEqual(zlib.crc32(m), 722071057) + self.assertEqual(zlib.adler32(m), -1002962529) finally: m.close() except (IOError, OverflowError): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 22:06:42 2011 From: python-checkins at python.org (daniel.stutzbach) Date: Wed, 04 May 2011 22:06:42 +0200 Subject: [Python-checkins] cpython (3.2): #11335: Fix memory leak after key function failure in sort Message-ID: http://hg.python.org/cpython/rev/52fb7dc721ed changeset: 69836:52fb7dc721ed branch: 3.2 parent: 69832:2a19d09b08f8 user: Daniel Stutzbach date: Wed May 04 12:46:28 2011 -0700 summary: #11335: Fix memory leak after key function failure in sort files: Lib/test/test_sort.py | 6 ++++++ Objects/listobject.c | 2 ++ 2 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_sort.py b/Lib/test/test_sort.py --- a/Lib/test/test_sort.py +++ b/Lib/test/test_sort.py @@ -111,6 +111,12 @@ s.sort(key=CmpToKey(lambda a, b: int(random.random() * 3) - 1)) check("an insane function left some permutation", x, s) + if len(x) >= 2: + def bad_key(x): + raise RuntimeError + s = x[:] + self.assertRaises(RuntimeError, s.sort, key=bad_key) + x = [Complains(i) for i in x] s = x[:] random.shuffle(s) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1944,6 +1944,8 @@ if (keys[i] == NULL) { for (i=i-1 ; i>=0 ; i--) Py_DECREF(keys[i]); + if (keys != &ms.temparray[saved_ob_size+1]) + PyMem_FREE(keys); goto keyfunc_fail; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 4 22:06:44 2011 From: python-checkins at python.org (daniel.stutzbach) Date: Wed, 04 May 2011 22:06:44 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11335: Merge from 3.2: Fix memory leak after key function failure in sort Message-ID: http://hg.python.org/cpython/rev/18e43c6acfff changeset: 69837:18e43c6acfff parent: 69833:c892b0321d23 parent: 69836:52fb7dc721ed user: Daniel Stutzbach date: Wed May 04 12:47:14 2011 -0700 summary: #11335: Merge from 3.2: Fix memory leak after key function failure in sort files: Lib/test/test_sort.py | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_sort.py b/Lib/test/test_sort.py --- a/Lib/test/test_sort.py +++ b/Lib/test/test_sort.py @@ -111,6 +111,12 @@ s.sort(key=CmpToKey(lambda a, b: int(random.random() * 3) - 1)) check("an insane function left some permutation", x, s) + if len(x) >= 2: + def bad_key(x): + raise RuntimeError + s = x[:] + self.assertRaises(RuntimeError, s.sort, key=bad_key) + x = [Complains(i) for i in x] s = x[:] random.shuffle(s) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 03:09:23 2011 From: python-checkins at python.org (r.david.murray) Date: Thu, 05 May 2011 03:09:23 +0200 Subject: [Python-checkins] cpython (2.7): #8158: add missing 'description' description to optparse docstring. Message-ID: http://hg.python.org/cpython/rev/c13d2552eb51 changeset: 69838:c13d2552eb51 branch: 2.7 parent: 69835:e6a4deb84e47 user: R David Murray date: Wed May 04 21:05:52 2011 -0400 summary: #8158: add missing 'description' description to optparse docstring. files: Lib/optparse.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -1131,6 +1131,11 @@ prog : string the name of the current program (to override os.path.basename(sys.argv[0])). + description : string + A paragraph of text giving a brief overview of your program. + optparse reformats this paragraph to fit the current terminal + width and prints it when the user requests help (after usage, + but before the list of options). epilog : string paragraph of help text to print after option help -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 03:09:24 2011 From: python-checkins at python.org (r.david.murray) Date: Thu, 05 May 2011 03:09:24 +0200 Subject: [Python-checkins] cpython (3.1): #8158: add missing 'description' description to optparse docstring. Message-ID: http://hg.python.org/cpython/rev/f559b88bcaa0 changeset: 69839:f559b88bcaa0 branch: 3.1 parent: 69828:7bf9d7ae6c94 user: R David Murray date: Wed May 04 21:06:57 2011 -0400 summary: #8158: add missing 'description' description to optparse docstring. files: Lib/optparse.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -1120,6 +1120,11 @@ prog : string the name of the current program (to override os.path.basename(sys.argv[0])). + description : string + A paragraph of text giving a brief overview of your program. + optparse reformats this paragraph to fit the current terminal + width and prints it when the user requests help (after usage, + but before the list of options). epilog : string paragraph of help text to print after option help -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 03:09:25 2011 From: python-checkins at python.org (r.david.murray) Date: Thu, 05 May 2011 03:09:25 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge #8158: add missing 'description' description to optparse docstring. Message-ID: http://hg.python.org/cpython/rev/b4b0a1458638 changeset: 69840:b4b0a1458638 branch: 3.2 parent: 69836:52fb7dc721ed parent: 69839:f559b88bcaa0 user: R David Murray date: Wed May 04 21:07:33 2011 -0400 summary: Merge #8158: add missing 'description' description to optparse docstring. files: Lib/optparse.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -1120,6 +1120,11 @@ prog : string the name of the current program (to override os.path.basename(sys.argv[0])). + description : string + A paragraph of text giving a brief overview of your program. + optparse reformats this paragraph to fit the current terminal + width and prints it when the user requests help (after usage, + but before the list of options). epilog : string paragraph of help text to print after option help -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 03:09:28 2011 From: python-checkins at python.org (r.david.murray) Date: Thu, 05 May 2011 03:09:28 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #8158: add missing 'description' description to optparse docstring. Message-ID: http://hg.python.org/cpython/rev/2a403afc4a76 changeset: 69841:2a403afc4a76 parent: 69837:18e43c6acfff parent: 69840:b4b0a1458638 user: R David Murray date: Wed May 04 21:08:07 2011 -0400 summary: Merge #8158: add missing 'description' description to optparse docstring. files: Lib/optparse.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -1126,6 +1126,11 @@ prog : string the name of the current program (to override os.path.basename(sys.argv[0])). + description : string + A paragraph of text giving a brief overview of your program. + optparse reformats this paragraph to fit the current terminal + width and prints it when the user requests help (after usage, + but before the list of options). epilog : string paragraph of help text to print after option help -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu May 5 04:58:02 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 05 May 2011 04:58:02 +0200 Subject: [Python-checkins] Daily reference leaks (2a403afc4a76): sum=0 Message-ID: results for 2a403afc4a76 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogl51Bt9', '-x'] From python-checkins at python.org Thu May 5 13:22:09 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 05 May 2011 13:22:09 +0200 Subject: [Python-checkins] cpython (2.7): #11997: fix typo in init.rst. Message-ID: http://hg.python.org/cpython/rev/76a2354aa427 changeset: 69842:76a2354aa427 branch: 2.7 parent: 69838:c13d2552eb51 user: Ezio Melotti date: Thu May 05 14:19:48 2011 +0300 summary: #11997: fix typo in init.rst. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -881,7 +881,7 @@ modules. Also note that combining this functionality with :cfunc:`PyGILState_\*` APIs -is delicate, become these APIs assume a bijection between Python thread states +is delicate, because these APIs assume a bijection between Python thread states and OS-level threads, an assumption broken by the presence of sub-interpreters. It is highly recommended that you don't switch sub-interpreters between a pair of matching :cfunc:`PyGILState_Ensure` and :cfunc:`PyGILState_Release` calls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 13:22:10 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 05 May 2011 13:22:10 +0200 Subject: [Python-checkins] cpython (3.1): #11997: fix typo in init.rst. Message-ID: http://hg.python.org/cpython/rev/3aa51217492c changeset: 69843:3aa51217492c branch: 3.1 parent: 69839:f559b88bcaa0 user: Ezio Melotti date: Thu May 05 14:19:48 2011 +0300 summary: #11997: fix typo in init.rst. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -867,7 +867,7 @@ modules. Also note that combining this functionality with :cfunc:`PyGILState_\*` APIs -is delicate, become these APIs assume a bijection between Python thread states +is delicate, because these APIs assume a bijection between Python thread states and OS-level threads, an assumption broken by the presence of sub-interpreters. It is highly recommended that you don't switch sub-interpreters between a pair of matching :cfunc:`PyGILState_Ensure` and :cfunc:`PyGILState_Release` calls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 13:22:11 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 05 May 2011 13:22:11 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11997: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/5a2d42a8c1ab changeset: 69844:5a2d42a8c1ab branch: 3.2 parent: 69840:b4b0a1458638 parent: 69843:3aa51217492c user: Ezio Melotti date: Thu May 05 14:21:18 2011 +0300 summary: #11997: merge with 3.1. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -883,7 +883,7 @@ modules. Also note that combining this functionality with :c:func:`PyGILState_\*` APIs -is delicate, become these APIs assume a bijection between Python thread states +is delicate, because these APIs assume a bijection between Python thread states and OS-level threads, an assumption broken by the presence of sub-interpreters. It is highly recommended that you don't switch sub-interpreters between a pair of matching :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release` calls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 13:22:12 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 05 May 2011 13:22:12 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11997: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/7c9717836c28 changeset: 69845:7c9717836c28 parent: 69841:2a403afc4a76 parent: 69844:5a2d42a8c1ab user: Ezio Melotti date: Thu May 05 14:21:55 2011 +0300 summary: #11997: merge with 3.2. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -883,7 +883,7 @@ modules. Also note that combining this functionality with :c:func:`PyGILState_\*` APIs -is delicate, become these APIs assume a bijection between Python thread states +is delicate, because these APIs assume a bijection between Python thread states and OS-level threads, an assumption broken by the presence of sub-interpreters. It is highly recommended that you don't switch sub-interpreters between a pair of matching :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release` calls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 14:00:10 2011 From: python-checkins at python.org (vinay.sajip) Date: Thu, 05 May 2011 14:00:10 +0200 Subject: [Python-checkins] cpython: Improved coverage and fixed bug in HTTPHandler with POST requests. Message-ID: http://hg.python.org/cpython/rev/7c5d91ac4f68 changeset: 69846:7c5d91ac4f68 parent: 69841:2a403afc4a76 user: Vinay Sajip date: Thu May 05 12:59:14 2011 +0100 summary: Improved coverage and fixed bug in HTTPHandler with POST requests. files: Lib/logging/handlers.py | 6 ++- Lib/test/test_logging.py | 42 +++++++++++++++++++++------ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -29,7 +29,7 @@ import queue try: import threading -except ImportError: +except ImportError: #pragma: no cover threading = None try: @@ -1044,7 +1044,9 @@ s = ('u%s:%s' % self.credentials).encode('utf-8') s = 'Basic ' + base64.b64encode(s).strip() h.putheader('Authorization', s) - h.endheaders(data if self.method == "POST" else None) + h.endheaders() + if self.method == "POST": + h.send(data.encode('utf-8')) h.getresponse() #can't do anything with the result except (KeyboardInterrupt, SystemExit): #pragma: no cover raise diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1464,22 +1464,34 @@ BaseTest.tearDown(self) def handle_request(self, request): + self.command = request.command self.log_data = urlparse(request.path) + if self.command == 'POST': + try: + rlen = int(request.headers['Content-Length']) + self.post_data = request.rfile.read(rlen) + except: + self.post_data = None request.send_response(200) self.handled.set() def test_output(self): # The log message sent to the SysLogHandler is properly received. logger = logging.getLogger("http") - msg = "sp\xe4m" - logger.error(msg) - self.handled.wait() - self.assertEqual(self.log_data.path, '/frob') - d = parse_qs(self.log_data.query) - self.assertEqual(d['name'], ['http']) - self.assertEqual(d['funcName'], ['test_output']) - self.assertEqual(d['msg'], [msg]) - + for method in ('GET', 'POST'): + self.h_hdlr.method = method + msg = "sp\xe4m" + logger.error(msg) + self.handled.wait() + self.assertEqual(self.log_data.path, '/frob') + self.assertEqual(self.command, method) + if method == 'GET': + d = parse_qs(self.log_data.query) + else: + d = parse_qs(self.post_data.decode('utf-8')) + self.assertEqual(d['name'], ['http']) + self.assertEqual(d['funcName'], ['test_output']) + self.assertEqual(d['msg'], [msg]) class MemoryTest(BaseTest): @@ -3470,7 +3482,8 @@ class TimedRotatingFileHandlerTest(BaseFileTest): # other test methods added below def test_rollover(self): - fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S') + fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S', + backupCount=1) r = logging.makeLogRecord({'msg': 'testing'}) fh.emit(r) self.assertLogFile(self.fn) @@ -3481,6 +3494,15 @@ suffix = prevsec.strftime(".%Y-%m-%d_%H-%M-%S") self.assertLogFile(self.fn + suffix) + def test_invalid(self): + assertRaises = self.assertRaises + assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler, + self.fn, 'X') + assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler, + self.fn, 'W') + assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler, + self.fn, 'W7') + def secs(**kw): return datetime.timedelta(**kw) // datetime.timedelta(seconds=1) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 14:00:11 2011 From: python-checkins at python.org (vinay.sajip) Date: Thu, 05 May 2011 14:00:11 +0200 Subject: [Python-checkins] cpython (merge default -> default): Merged changes. Message-ID: http://hg.python.org/cpython/rev/e4d254fbaaeb changeset: 69847:e4d254fbaaeb parent: 69846:7c5d91ac4f68 parent: 69845:7c9717836c28 user: Vinay Sajip date: Thu May 05 12:59:59 2011 +0100 summary: Merged changes. files: Doc/c-api/init.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -883,7 +883,7 @@ modules. Also note that combining this functionality with :c:func:`PyGILState_\*` APIs -is delicate, become these APIs assume a bijection between Python thread states +is delicate, because these APIs assume a bijection between Python thread states and OS-level threads, an assumption broken by the presence of sub-interpreters. It is highly recommended that you don't switch sub-interpreters between a pair of matching :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release` calls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 15:18:40 2011 From: python-checkins at python.org (vinay.sajip) Date: Thu, 05 May 2011 15:18:40 +0200 Subject: [Python-checkins] cpython: Tweaked timed rollover test to allow for test-time delays. Message-ID: http://hg.python.org/cpython/rev/97004f70ff0d changeset: 69848:97004f70ff0d user: Vinay Sajip date: Thu May 05 14:18:33 2011 +0100 summary: Tweaked timed rollover test to allow for test-time delays. files: Lib/test/test_logging.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3491,8 +3491,12 @@ fh.emit(r) now = datetime.datetime.now() prevsec = now - datetime.timedelta(seconds=1) - suffix = prevsec.strftime(".%Y-%m-%d_%H-%M-%S") - self.assertLogFile(self.fn + suffix) + earlier = now - datetime.timedelta(seconds=2) + fn1 = self.fn + prevsec.strftime(".%Y-%m-%d_%H-%M-%S") + fn2 = self.fn + earlier.strftime(".%Y-%m-%d_%H-%M-%S") + self.assertTrue(os.path.exists(fn1) or + os.path.exists(fn2), + msg="Neither exists: %s nor %s" % (fn1, fn2)) def test_invalid(self): assertRaises = self.assertRaises -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 16:04:02 2011 From: python-checkins at python.org (nick.coghlan) Date: Thu, 05 May 2011 16:04:02 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11647: allow contextmanager objects to be used as decorators as Message-ID: http://hg.python.org/cpython/rev/e4ba097123f6 changeset: 69849:e4ba097123f6 branch: 3.2 parent: 69844:5a2d42a8c1ab user: Nick Coghlan date: Thu May 05 23:49:25 2011 +1000 summary: Issue #11647: allow contextmanager objects to be used as decorators as described in the docs. Initial patch by Ysj Ray. files: Doc/library/contextlib.rst | 14 ++++++++++- Lib/contextlib.py | 28 +++++++++++++++++++++--- Lib/test/test_contextlib.py | 7 +++++- Lib/test/test_with.py | 6 ++-- Misc/ACKS | 1 + Misc/NEWS | 4 +++ 6 files changed, 50 insertions(+), 10 deletions(-) diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -54,8 +54,12 @@ the exception has been handled, and execution will resume with the statement immediately following the :keyword:`with` statement. - contextmanager uses :class:`ContextDecorator` so the context managers it - creates can be used as decorators as well as in :keyword:`with` statements. + :func:`contextmanager` uses :class:`ContextDecorator` so the context managers + it creates can be used as decorators as well as in :keyword:`with` statements. + When used as a decorator, a new generator instance is implicitly created on + each function call (this allows the otherwise "one-shot" context managers + created by :func:`contextmanager` to meet the requirement that context + managers support multiple invocations in order to be used as decorators). .. versionchanged:: 3.2 Use of :class:`ContextDecorator`. @@ -155,6 +159,12 @@ def __exit__(self, *exc): return False + .. note:: + As the decorated function must be able to be called multiple times, the + underlying context manager must support use in multiple :keyword:`with` + statements. If this is not the case, then the original construct with the + explicit :keyword:`with` statement inside the function should be used. + .. versionadded:: 3.2 diff --git a/Lib/contextlib.py b/Lib/contextlib.py --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -9,10 +9,23 @@ class ContextDecorator(object): "A base class or mixin that enables context managers to work as decorators." + + def _recreate_cm(self): + """Return a recreated instance of self. + + Allows otherwise one-shot context managers like + _GeneratorContextManager to support use as + decorators via implicit recreation. + + Note: this is a private interface just for _GCM in 3.2 but will be + renamed and documented for third party use in 3.3 + """ + return self + def __call__(self, func): @wraps(func) def inner(*args, **kwds): - with self: + with self._recreate_cm(): return func(*args, **kwds) return inner @@ -20,8 +33,15 @@ class _GeneratorContextManager(ContextDecorator): """Helper for @contextmanager decorator.""" - def __init__(self, gen): - self.gen = gen + def __init__(self, func, *args, **kwds): + self.gen = func(*args, **kwds) + self.func, self.args, self.kwds = func, args, kwds + + def _recreate_cm(self): + # _GCM instances are one-shot context managers, so the + # CM must be recreated each time a decorated function is + # called + return self.__class__(self.func, *self.args, **self.kwds) def __enter__(self): try: @@ -92,7 +112,7 @@ """ @wraps(func) def helper(*args, **kwds): - return _GeneratorContextManager(func(*args, **kwds)) + return _GeneratorContextManager(func, *args, **kwds) return helper diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -350,13 +350,13 @@ def test_contextmanager_as_decorator(self): - state = [] @contextmanager def woohoo(y): state.append(y) yield state.append(999) + state = [] @woohoo(1) def test(x): self.assertEqual(state, [1]) @@ -364,6 +364,11 @@ test('something') self.assertEqual(state, [1, 'something', 999]) + # Issue #11647: Ensure the decorated function is 'reusable' + state = [] + test('something else') + self.assertEqual(state, [1, 'something else', 999]) + # This is needed to make the test actually run under regrtest.py! def test_main(): diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -14,8 +14,8 @@ class MockContextManager(_GeneratorContextManager): - def __init__(self, gen): - _GeneratorContextManager.__init__(self, gen) + def __init__(self, func, *args, **kwds): + super().__init__(func, *args, **kwds) self.enter_called = False self.exit_called = False self.exit_args = None @@ -33,7 +33,7 @@ def mock_contextmanager(func): def helper(*args, **kwds): - return MockContextManager(func(*args, **kwds)) + return MockContextManager(func, *args, **kwds) return helper diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -704,6 +704,7 @@ Brodie Rao Antti Rasinen Sridhar Ratnakumar +Ysj Ray Eric Raymond Edward K. Ream Chris Rebert diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,10 @@ Library ------- +- Issue #11647: objects created using contextlib.contextmanager now support + more than one call to the function when used as a decorator. Initial patch + by Ysj Ray. + - logging: don't define QueueListener if Python has no thread support. - functools.cmp_to_key() now works with collections.Hashable(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 16:04:04 2011 From: python-checkins at python.org (nick.coghlan) Date: Thu, 05 May 2011 16:04:04 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #11647 update from 3.2 Message-ID: http://hg.python.org/cpython/rev/b23d1df7e47e changeset: 69850:b23d1df7e47e parent: 69848:97004f70ff0d parent: 69849:e4ba097123f6 user: Nick Coghlan date: Thu May 05 23:58:57 2011 +1000 summary: Merge #11647 update from 3.2 files: Doc/library/contextlib.rst | 14 ++++++++++- Lib/contextlib.py | 28 +++++++++++++++++++++--- Lib/test/test_contextlib.py | 7 +++++- Lib/test/test_with.py | 6 ++-- Misc/ACKS | 1 + Misc/NEWS | 4 +++ 6 files changed, 50 insertions(+), 10 deletions(-) diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -54,8 +54,12 @@ the exception has been handled, and execution will resume with the statement immediately following the :keyword:`with` statement. - contextmanager uses :class:`ContextDecorator` so the context managers it - creates can be used as decorators as well as in :keyword:`with` statements. + :func:`contextmanager` uses :class:`ContextDecorator` so the context managers + it creates can be used as decorators as well as in :keyword:`with` statements. + When used as a decorator, a new generator instance is implicitly created on + each function call (this allows the otherwise "one-shot" context managers + created by :func:`contextmanager` to meet the requirement that context + managers support multiple invocations in order to be used as decorators). .. versionchanged:: 3.2 Use of :class:`ContextDecorator`. @@ -155,6 +159,12 @@ def __exit__(self, *exc): return False + .. note:: + As the decorated function must be able to be called multiple times, the + underlying context manager must support use in multiple :keyword:`with` + statements. If this is not the case, then the original construct with the + explicit :keyword:`with` statement inside the function should be used. + .. versionadded:: 3.2 diff --git a/Lib/contextlib.py b/Lib/contextlib.py --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -9,10 +9,23 @@ class ContextDecorator(object): "A base class or mixin that enables context managers to work as decorators." + + def _recreate_cm(self): + """Return a recreated instance of self. + + Allows otherwise one-shot context managers like + _GeneratorContextManager to support use as + decorators via implicit recreation. + + Note: this is a private interface just for _GCM in 3.2 but will be + renamed and documented for third party use in 3.3 + """ + return self + def __call__(self, func): @wraps(func) def inner(*args, **kwds): - with self: + with self._recreate_cm(): return func(*args, **kwds) return inner @@ -20,8 +33,15 @@ class _GeneratorContextManager(ContextDecorator): """Helper for @contextmanager decorator.""" - def __init__(self, gen): - self.gen = gen + def __init__(self, func, *args, **kwds): + self.gen = func(*args, **kwds) + self.func, self.args, self.kwds = func, args, kwds + + def _recreate_cm(self): + # _GCM instances are one-shot context managers, so the + # CM must be recreated each time a decorated function is + # called + return self.__class__(self.func, *self.args, **self.kwds) def __enter__(self): try: @@ -92,7 +112,7 @@ """ @wraps(func) def helper(*args, **kwds): - return _GeneratorContextManager(func(*args, **kwds)) + return _GeneratorContextManager(func, *args, **kwds) return helper diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -350,13 +350,13 @@ def test_contextmanager_as_decorator(self): - state = [] @contextmanager def woohoo(y): state.append(y) yield state.append(999) + state = [] @woohoo(1) def test(x): self.assertEqual(state, [1]) @@ -364,6 +364,11 @@ test('something') self.assertEqual(state, [1, 'something', 999]) + # Issue #11647: Ensure the decorated function is 'reusable' + state = [] + test('something else') + self.assertEqual(state, [1, 'something else', 999]) + # This is needed to make the test actually run under regrtest.py! def test_main(): diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -14,8 +14,8 @@ class MockContextManager(_GeneratorContextManager): - def __init__(self, gen): - _GeneratorContextManager.__init__(self, gen) + def __init__(self, func, *args, **kwds): + super().__init__(func, *args, **kwds) self.enter_called = False self.exit_called = False self.exit_args = None @@ -33,7 +33,7 @@ def mock_contextmanager(func): def helper(*args, **kwds): - return MockContextManager(func(*args, **kwds)) + return MockContextManager(func, *args, **kwds) return helper diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -709,6 +709,7 @@ Brodie Rao Antti Rasinen Sridhar Ratnakumar +Ysj Ray Eric Raymond Edward K. Ream Chris Rebert diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,10 @@ Library ------- +- Issue #11647: objects created using contextlib.contextmanager now support + more than one call to the function when used as a decorator. Initial patch + by Ysj Ray. + - Issue #11930: Removed deprecated time.accept2dyear variable. Removed year >= 1000 restriction from datetime.strftime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 16:04:05 2011 From: python-checkins at python.org (nick.coghlan) Date: Thu, 05 May 2011 16:04:05 +0200 Subject: [Python-checkins] cpython (3.2): Remove trailing whitespace Message-ID: http://hg.python.org/cpython/rev/9b76edfddc54 changeset: 69851:9b76edfddc54 branch: 3.2 parent: 69849:e4ba097123f6 user: Nick Coghlan date: Fri May 06 00:02:12 2011 +1000 summary: Remove trailing whitespace files: Lib/contextlib.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/contextlib.py b/Lib/contextlib.py --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -12,11 +12,11 @@ def _recreate_cm(self): """Return a recreated instance of self. - + Allows otherwise one-shot context managers like _GeneratorContextManager to support use as decorators via implicit recreation. - + Note: this is a private interface just for _GCM in 3.2 but will be renamed and documented for third party use in 3.3 """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 16:04:06 2011 From: python-checkins at python.org (nick.coghlan) Date: Thu, 05 May 2011 16:04:06 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/b06d7aa8ac20 changeset: 69852:b06d7aa8ac20 parent: 69850:b23d1df7e47e parent: 69851:9b76edfddc54 user: Nick Coghlan date: Fri May 06 00:03:49 2011 +1000 summary: Merge from 3.2 files: Lib/contextlib.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/contextlib.py b/Lib/contextlib.py --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -12,11 +12,11 @@ def _recreate_cm(self): """Return a recreated instance of self. - + Allows otherwise one-shot context managers like _GeneratorContextManager to support use as decorators via implicit recreation. - + Note: this is a private interface just for _GCM in 3.2 but will be renamed and documented for third party use in 3.3 """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 18:19:03 2011 From: python-checkins at python.org (r.david.murray) Date: Thu, 05 May 2011 18:19:03 +0200 Subject: [Python-checkins] cpython (3.2): #11873: Improve test regex so random directory names don't cause test to fail Message-ID: http://hg.python.org/cpython/rev/76bd26565cc7 changeset: 69853:76bd26565cc7 branch: 3.2 parent: 69851:9b76edfddc54 user: R David Murray date: Thu May 05 11:52:44 2011 -0400 summary: #11873: Improve test regex so random directory names don't cause test to fail files: Lib/test/test_compileall.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -248,7 +248,7 @@ self.assertEqual(b'', quiet) def test_regexp(self): - self.assertRunOK('-q', '-x', 'ba.*', self.pkgdir) + self.assertRunOK('-q', '-x', 'ba[^\/]*$', self.pkgdir) self.assertNotCompiled(self.barfn) self.assertCompiled(self.initfn) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -322,6 +322,9 @@ Tests ----- +- Issue #11873: Change regex in test_compileall to fix occasional failures when + when the randomly generated temporary path happened to match the regex. + - Issue #10914: Add a minimal embedding test to test_capi. - Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 18:19:04 2011 From: python-checkins at python.org (r.david.murray) Date: Thu, 05 May 2011 18:19:04 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: #11873: Improve test regex so random directory names don't cause test to Message-ID: http://hg.python.org/cpython/rev/83e069281810 changeset: 69854:83e069281810 parent: 69852:b06d7aa8ac20 parent: 69853:76bd26565cc7 user: R David Murray date: Thu May 05 12:17:50 2011 -0400 summary: Merge: #11873: Improve test regex so random directory names don't cause test to fail files: Lib/test/test_compileall.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -248,7 +248,7 @@ self.assertEqual(b'', quiet) def test_regexp(self): - self.assertRunOK('-q', '-x', 'ba.*', self.pkgdir) + self.assertRunOK('-q', '-x', 'ba[^\/]*$', self.pkgdir) self.assertNotCompiled(self.barfn) self.assertCompiled(self.initfn) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -561,6 +561,9 @@ Tests ----- +- Issue #11873: Change regex in test_compileall to fix occasional failures when + when the randomly generated temporary path happened to match the regex. + - Issue #11958: Fix FTP tests for IPv6, bind to "::1" instead of "localhost". Patch written by Charles-Francois Natali. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 20:18:24 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 05 May 2011 20:18:24 +0200 Subject: [Python-checkins] cpython (3.2): Use shared testing facilities in test_threading Message-ID: http://hg.python.org/cpython/rev/97a4855202b8 changeset: 69855:97a4855202b8 branch: 3.2 parent: 69853:76bd26565cc7 user: Antoine Pitrou date: Thu May 05 20:17:32 2011 +0200 summary: Use shared testing facilities in test_threading files: Lib/test/test_threading.py | 65 +++++++------------------ 1 files changed, 18 insertions(+), 47 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1,18 +1,17 @@ # Very rudimentary test of threading module import test.support -from test.support import verbose, strip_python_stderr +from test.support import verbose, strip_python_stderr, import_module import random import re import sys -_thread = test.support.import_module('_thread') -threading = test.support.import_module('threading') +_thread = import_module('_thread') +threading = import_module('threading') import time import unittest import weakref import os -import subprocess -from test.script_helper import assert_python_ok +from test.script_helper import assert_python_ok, assert_python_failure from test import lock_tests @@ -163,10 +162,7 @@ # PyThreadState_SetAsyncExc() is a CPython-only gimmick, not (currently) # exposed at the Python level. This test relies on ctypes to get at it. def test_PyThreadState_SetAsyncExc(self): - try: - import ctypes - except ImportError: - raise unittest.SkipTest("cannot import ctypes") + ctypes = import_module("ctypes") set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc @@ -269,12 +265,9 @@ # Issue 1402: the PyGILState_Ensure / _Release functions may be called # very late on python exit: on deallocation of a running thread for # example. - try: - import ctypes - except ImportError: - raise unittest.SkipTest("cannot import ctypes") + import_module("ctypes") - rc = subprocess.call([sys.executable, "-c", """if 1: + rc, out, err = assert_python_failure("-c", """if 1: import ctypes, sys, time, _thread # This lock is used as a simple event variable. @@ -298,13 +291,13 @@ _thread.start_new_thread(waitingThread, ()) ready.acquire() # Be sure the other thread is waiting. sys.exit(42) - """]) + """) self.assertEqual(rc, 42) def test_finalize_with_trace(self): # Issue1733757 # Avoid a deadlock when sys.settrace steps into threading._shutdown - p = subprocess.Popen([sys.executable, "-c", """if 1: + assert_python_ok("-c", """if 1: import sys, threading # A deadlock-killer, to prevent the @@ -324,21 +317,12 @@ return func sys.settrace(func) - """], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - self.addCleanup(p.stdout.close) - self.addCleanup(p.stderr.close) - stdout, stderr = p.communicate() - rc = p.returncode - self.assertFalse(rc == 2, "interpreted was blocked") - self.assertTrue(rc == 0, - "Unexpected error: " + ascii(stderr)) + """) def test_join_nondaemon_on_shutdown(self): # Issue 1722344 # Raising SystemExit skipped threading._shutdown - p = subprocess.Popen([sys.executable, "-c", """if 1: + rc, out, err = assert_python_ok("-c", """if 1: import threading from time import sleep @@ -350,16 +334,10 @@ threading.Thread(target=child).start() raise SystemExit - """], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - self.addCleanup(p.stdout.close) - self.addCleanup(p.stderr.close) - stdout, stderr = p.communicate() - self.assertEqual(stdout.strip(), + """) + self.assertEqual(out.strip(), b"Woke up, sleep function is: ") - stderr = strip_python_stderr(stderr) - self.assertEqual(stderr, b"") + self.assertEqual(err, b"") def test_enumerate_after_join(self): # Try hard to trigger #1703448: a thread is still returned in @@ -444,13 +422,9 @@ sys.stdout.flush() \n""" + script - p = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE) - rc = p.wait() - data = p.stdout.read().decode().replace('\r', '') - p.stdout.close() + rc, out, err = assert_python_ok("-c", script) + data = out.decode().replace('\r', '') self.assertEqual(data, "end of main\nend of thread\n") - self.assertFalse(rc == 2, "interpreter was blocked") - self.assertTrue(rc == 0, "Unexpected error") def test_1_join_on_shutdown(self): # The usual case: on exit, wait for a non-daemon thread @@ -510,11 +484,8 @@ self._run_and_join(script) def assertScriptHasOutput(self, script, expected_output): - p = subprocess.Popen([sys.executable, "-c", script], - stdout=subprocess.PIPE) - stdout, stderr = p.communicate() - data = stdout.decode().replace('\r', '') - self.assertEqual(p.returncode, 0, "Unexpected error") + rc, out, err = assert_python_ok("-c", script) + data = out.decode().replace('\r', '') self.assertEqual(data, expected_output) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 20:18:25 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 05 May 2011 20:18:25 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: Use shared testing facilities in test_threading Message-ID: http://hg.python.org/cpython/rev/b06ad8458b32 changeset: 69856:b06ad8458b32 parent: 69854:83e069281810 parent: 69855:97a4855202b8 user: Antoine Pitrou date: Thu May 05 20:18:19 2011 +0200 summary: Merge: Use shared testing facilities in test_threading files: Lib/test/test_threading.py | 65 +++++++------------------ 1 files changed, 18 insertions(+), 47 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1,18 +1,17 @@ # Very rudimentary test of threading module import test.support -from test.support import verbose, strip_python_stderr +from test.support import verbose, strip_python_stderr, import_module import random import re import sys -_thread = test.support.import_module('_thread') -threading = test.support.import_module('threading') +_thread = import_module('_thread') +threading = import_module('threading') import time import unittest import weakref import os -import subprocess -from test.script_helper import assert_python_ok +from test.script_helper import assert_python_ok, assert_python_failure from test import lock_tests @@ -163,10 +162,7 @@ # PyThreadState_SetAsyncExc() is a CPython-only gimmick, not (currently) # exposed at the Python level. This test relies on ctypes to get at it. def test_PyThreadState_SetAsyncExc(self): - try: - import ctypes - except ImportError: - raise unittest.SkipTest("cannot import ctypes") + ctypes = import_module("ctypes") set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc @@ -269,12 +265,9 @@ # Issue 1402: the PyGILState_Ensure / _Release functions may be called # very late on python exit: on deallocation of a running thread for # example. - try: - import ctypes - except ImportError: - raise unittest.SkipTest("cannot import ctypes") + import_module("ctypes") - rc = subprocess.call([sys.executable, "-c", """if 1: + rc, out, err = assert_python_failure("-c", """if 1: import ctypes, sys, time, _thread # This lock is used as a simple event variable. @@ -298,13 +291,13 @@ _thread.start_new_thread(waitingThread, ()) ready.acquire() # Be sure the other thread is waiting. sys.exit(42) - """]) + """) self.assertEqual(rc, 42) def test_finalize_with_trace(self): # Issue1733757 # Avoid a deadlock when sys.settrace steps into threading._shutdown - p = subprocess.Popen([sys.executable, "-c", """if 1: + assert_python_ok("-c", """if 1: import sys, threading # A deadlock-killer, to prevent the @@ -324,21 +317,12 @@ return func sys.settrace(func) - """], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - self.addCleanup(p.stdout.close) - self.addCleanup(p.stderr.close) - stdout, stderr = p.communicate() - rc = p.returncode - self.assertFalse(rc == 2, "interpreted was blocked") - self.assertTrue(rc == 0, - "Unexpected error: " + ascii(stderr)) + """) def test_join_nondaemon_on_shutdown(self): # Issue 1722344 # Raising SystemExit skipped threading._shutdown - p = subprocess.Popen([sys.executable, "-c", """if 1: + rc, out, err = assert_python_ok("-c", """if 1: import threading from time import sleep @@ -350,16 +334,10 @@ threading.Thread(target=child).start() raise SystemExit - """], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - self.addCleanup(p.stdout.close) - self.addCleanup(p.stderr.close) - stdout, stderr = p.communicate() - self.assertEqual(stdout.strip(), + """) + self.assertEqual(out.strip(), b"Woke up, sleep function is: ") - stderr = strip_python_stderr(stderr) - self.assertEqual(stderr, b"") + self.assertEqual(err, b"") def test_enumerate_after_join(self): # Try hard to trigger #1703448: a thread is still returned in @@ -452,13 +430,9 @@ sys.stdout.flush() \n""" + script - p = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE) - rc = p.wait() - data = p.stdout.read().decode().replace('\r', '') - p.stdout.close() + rc, out, err = assert_python_ok("-c", script) + data = out.decode().replace('\r', '') self.assertEqual(data, "end of main\nend of thread\n") - self.assertFalse(rc == 2, "interpreter was blocked") - self.assertTrue(rc == 0, "Unexpected error") def test_1_join_on_shutdown(self): # The usual case: on exit, wait for a non-daemon thread @@ -518,11 +492,8 @@ self._run_and_join(script) def assertScriptHasOutput(self, script, expected_output): - p = subprocess.Popen([sys.executable, "-c", script], - stdout=subprocess.PIPE) - stdout, stderr = p.communicate() - data = stdout.decode().replace('\r', '') - self.assertEqual(p.returncode, 0, "Unexpected error") + rc, out, err = assert_python_ok("-c", script) + data = out.decode().replace('\r', '') self.assertEqual(data, expected_output) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 20:38:24 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 05 May 2011 20:38:24 +0200 Subject: [Python-checkins] cpython (3.2): Avoid codec spelling issues by just using the utf-8 default. Message-ID: http://hg.python.org/cpython/rev/1a56775c6e54 changeset: 69857:1a56775c6e54 branch: 3.2 parent: 69855:97a4855202b8 user: Raymond Hettinger date: Thu May 05 11:35:50 2011 -0700 summary: Avoid codec spelling issues by just using the utf-8 default. files: Lib/random.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -114,7 +114,7 @@ if version == 2: if isinstance(a, (str, bytes, bytearray)): if isinstance(a, str): - a = a.encode("utf8") + a = a.encode() a += _sha512(a).digest() a = int.from_bytes(a, 'big') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 20:38:27 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 05 May 2011 20:38:27 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Avoid codec spelling issues by just using the utf-8 default. Message-ID: http://hg.python.org/cpython/rev/2bc784057226 changeset: 69858:2bc784057226 parent: 69856:b06ad8458b32 parent: 69857:1a56775c6e54 user: Raymond Hettinger date: Thu May 05 11:38:06 2011 -0700 summary: Avoid codec spelling issues by just using the utf-8 default. files: Lib/random.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -114,7 +114,7 @@ if version == 2: if isinstance(a, (str, bytes, bytearray)): if isinstance(a, str): - a = a.encode("utf-8") + a = a.encode() a += _sha512(a).digest() a = int.from_bytes(a, 'big') -- Repository URL: http://hg.python.org/cpython From benjamin at python.org Thu May 5 20:41:50 2011 From: benjamin at python.org (Benjamin Peterson) Date: Thu, 5 May 2011 13:41:50 -0500 Subject: [Python-checkins] cpython (3.2): Avoid codec spelling issues by just using the utf-8 default. In-Reply-To: References: Message-ID: 2011/5/5 raymond.hettinger : > http://hg.python.org/cpython/rev/1a56775c6e54 > changeset: ? 69857:1a56775c6e54 > branch: ? ? ?3.2 > parent: ? ? ?69855:97a4855202b8 > user: ? ? ? ?Raymond Hettinger > date: ? ? ? ?Thu May 05 11:35:50 2011 -0700 > summary: > ?Avoid codec spelling issues by just using the utf-8 default. Out of curiosity, what is the issue? > > files: > ?Lib/random.py | ?2 +- > ?1 files changed, 1 insertions(+), 1 deletions(-) > > > diff --git a/Lib/random.py b/Lib/random.py > --- a/Lib/random.py > +++ b/Lib/random.py > @@ -114,7 +114,7 @@ > ? ? ? ? if version == 2: > ? ? ? ? ? ? if isinstance(a, (str, bytes, bytearray)): > ? ? ? ? ? ? ? ? if isinstance(a, str): > - ? ? ? ? ? ? ? ? ? ?a = a.encode("utf8") > + ? ? ? ? ? ? ? ? ? ?a = a.encode() -- Regards, Benjamin From python-checkins at python.org Thu May 5 20:50:47 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 05 May 2011 20:50:47 +0200 Subject: [Python-checkins] cpython (3.2): Sync-up minor code edits with the default branch. Message-ID: http://hg.python.org/cpython/rev/e2f7db1255df changeset: 69859:e2f7db1255df branch: 3.2 parent: 69857:1a56775c6e54 user: Raymond Hettinger date: Thu May 05 11:49:12 2011 -0700 summary: Sync-up minor code edits with the default branch. files: Lib/random.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -42,7 +42,7 @@ from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil 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 collections import Set as _Set, Sequence as _Sequence from hashlib import sha512 as _sha512 __all__ = ["Random","seed","random","uniform","randint","choice","sample", @@ -293,10 +293,10 @@ # preferred since the list takes less space than the # set and it doesn't suffer from frequent reselections. - if isinstance(population, _collections.Set): + if isinstance(population, _Set): population = tuple(population) - if not isinstance(population, _collections.Sequence): - raise TypeError("Population must be a sequence or Set. For dicts, use list(d).") + if not isinstance(population, _Sequence): + raise TypeError("Population must be a sequence or set. For dicts, use list(d).") randbelow = self._randbelow n = len(population) if not 0 <= k <= n: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 20:50:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 05 May 2011 20:50:48 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): null merge Message-ID: http://hg.python.org/cpython/rev/1cfa5dab709d changeset: 69860:1cfa5dab709d parent: 69858:2bc784057226 parent: 69859:e2f7db1255df user: Raymond Hettinger date: Thu May 05 11:50:36 2011 -0700 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 22:23:49 2011 From: python-checkins at python.org (vinay.sajip) Date: Thu, 05 May 2011 22:23:49 +0200 Subject: [Python-checkins] cpython: Added additional output to help diagnose buildbot failures. Message-ID: http://hg.python.org/cpython/rev/13bd08461599 changeset: 69861:13bd08461599 user: Vinay Sajip date: Thu May 05 21:23:42 2011 +0100 summary: Added additional output to help diagnose buildbot failures. files: Lib/test/test_logging.py | 16 +++++++++++++--- 1 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3494,9 +3494,19 @@ earlier = now - datetime.timedelta(seconds=2) fn1 = self.fn + prevsec.strftime(".%Y-%m-%d_%H-%M-%S") fn2 = self.fn + earlier.strftime(".%Y-%m-%d_%H-%M-%S") - self.assertTrue(os.path.exists(fn1) or - os.path.exists(fn2), - msg="Neither exists: %s nor %s" % (fn1, fn2)) + success = os.path.exists(fn1) or os.path.exists(fn2) + if not success: + # print additional diagnostic information + print('Neither %s nor %s exists' % (fn1, fn2), file=sys.stderr) + dirname = os.path.dirname(fn1) + files = os.listdir(dirname) + files = [f for f in files if f.startswith('test_logging-2-')] + print('matching files: %s' % files, file=sys.stderr) + self.assertTrue(success) + for fn in (fn1, fn2): + if os.path.exists(fn): + self.rmfiles.append(fn) + def test_invalid(self): assertRaises = self.assertRaises -- Repository URL: http://hg.python.org/cpython From raymond.hettinger at gmail.com Thu May 5 22:55:07 2011 From: raymond.hettinger at gmail.com (Raymond Hettinger) Date: Thu, 5 May 2011 13:55:07 -0700 Subject: [Python-checkins] cpython (3.2): Avoid codec spelling issues by just using the utf-8 default. In-Reply-To: References: Message-ID: <926F0913-8142-430A-8400-6E6F0CD5B8F1@gmail.com> On May 5, 2011, at 11:41 AM, Benjamin Peterson wrote: > 2011/5/5 raymond.hettinger : >> http://hg.python.org/cpython/rev/1a56775c6e54 >> changeset: 69857:1a56775c6e54 >> branch: 3.2 >> parent: 69855:97a4855202b8 >> user: Raymond Hettinger >> date: Thu May 05 11:35:50 2011 -0700 >> summary: >> Avoid codec spelling issues by just using the utf-8 default. > > Out of curiosity, what is the issue? IIRC, the performance depended on how your spelled-it. I believe that is why the spelling got changed in Py3.3. Either way, the code is simpler by just using the default. Raymond From python-checkins at python.org Thu May 5 23:16:44 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 05 May 2011 23:16:44 +0200 Subject: [Python-checkins] cpython (3.2): Sync-up minor code edits with the default branch. Message-ID: http://hg.python.org/cpython/rev/9f58612bc334 changeset: 69862:9f58612bc334 branch: 3.2 parent: 69859:e2f7db1255df user: Raymond Hettinger date: Thu May 05 14:15:12 2011 -0700 summary: Sync-up minor code edits with the default branch. files: Lib/functools.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -97,7 +97,7 @@ """Convert a cmp= function into a key= function""" class K(object): __slots__ = ['obj'] - def __init__(self, obj, *args): + def __init__(self, obj): self.obj = obj def __lt__(self, other): return mycmp(self.obj, other.obj) < 0 @@ -140,7 +140,7 @@ tuple=tuple, sorted=sorted, len=len, KeyError=KeyError): hits = misses = 0 - kwd_mark = object() # separates positional and keyword args + kwd_mark = (object(),) # separates positional and keyword args lock = Lock() # needed because ordereddicts aren't threadsafe if maxsize is None: @@ -151,7 +151,7 @@ nonlocal hits, misses key = args if kwds: - key += (kwd_mark,) + tuple(sorted(kwds.items())) + key += kwd_mark + tuple(sorted(kwds.items())) try: result = cache[key] hits += 1 @@ -170,7 +170,7 @@ nonlocal hits, misses key = args if kwds: - key += (kwd_mark,) + tuple(sorted(kwds.items())) + key += kwd_mark + tuple(sorted(kwds.items())) try: with lock: result = cache[key] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 23:16:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 05 May 2011 23:16:48 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): null merge Message-ID: http://hg.python.org/cpython/rev/444574740f5d changeset: 69863:444574740f5d parent: 69860:1cfa5dab709d parent: 69862:9f58612bc334 user: Raymond Hettinger date: Thu May 05 14:15:44 2011 -0700 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 23:16:51 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 05 May 2011 23:16:51 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge Message-ID: http://hg.python.org/cpython/rev/8a27d7fc194e changeset: 69864:8a27d7fc194e parent: 69863:444574740f5d parent: 69861:13bd08461599 user: Raymond Hettinger date: Thu May 05 14:16:16 2011 -0700 summary: merge files: Lib/test/test_logging.py | 16 +++++++++++++--- 1 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3494,9 +3494,19 @@ earlier = now - datetime.timedelta(seconds=2) fn1 = self.fn + prevsec.strftime(".%Y-%m-%d_%H-%M-%S") fn2 = self.fn + earlier.strftime(".%Y-%m-%d_%H-%M-%S") - self.assertTrue(os.path.exists(fn1) or - os.path.exists(fn2), - msg="Neither exists: %s nor %s" % (fn1, fn2)) + success = os.path.exists(fn1) or os.path.exists(fn2) + if not success: + # print additional diagnostic information + print('Neither %s nor %s exists' % (fn1, fn2), file=sys.stderr) + dirname = os.path.dirname(fn1) + files = os.listdir(dirname) + files = [f for f in files if f.startswith('test_logging-2-')] + print('matching files: %s' % files, file=sys.stderr) + self.assertTrue(success) + for fn in (fn1, fn2): + if os.path.exists(fn): + self.rmfiles.append(fn) + def test_invalid(self): assertRaises = self.assertRaises -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 5 23:34:46 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 05 May 2011 23:34:46 +0200 Subject: [Python-checkins] cpython: Userlist.copy() wasn't returning a UserList. Message-ID: http://hg.python.org/cpython/rev/f20373fcdde5 changeset: 69865:f20373fcdde5 user: Raymond Hettinger date: Thu May 05 14:34:35 2011 -0700 summary: Userlist.copy() wasn't returning a UserList. files: Lib/collections/__init__.py | 2 +- Lib/test/test_userlist.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -887,7 +887,7 @@ def pop(self, i=-1): return self.data.pop(i) def remove(self, item): self.data.remove(item) def clear(self): self.data.clear() - def copy(self): return self.data.copy() + def copy(self): return self.__class__(self) def count(self, item): return self.data.count(item) def index(self, item, *args): return self.data.index(item, *args) def reverse(self): self.data.reverse() diff --git a/Lib/test/test_userlist.py b/Lib/test/test_userlist.py --- a/Lib/test/test_userlist.py +++ b/Lib/test/test_userlist.py @@ -52,6 +52,12 @@ return str(key) + '!!!' self.assertEqual(next(iter(T((1,2)))), "0!!!") + def test_userlist_copy(self): + u = self.type2test([6, 8, 1, 9, 1]) + v = u.copy() + self.assertEqual(u, v) + self.assertEqual(type(u), type(v)) + def test_main(): support.run_unittest(UserListTest) -- Repository URL: http://hg.python.org/cpython From mal at egenix.com Fri May 6 00:32:59 2011 From: mal at egenix.com (M.-A. Lemburg) Date: Fri, 06 May 2011 00:32:59 +0200 Subject: [Python-checkins] [Python-Dev] cpython (3.2): Avoid codec spelling issues by just using the utf-8 default. In-Reply-To: <926F0913-8142-430A-8400-6E6F0CD5B8F1@gmail.com> References: <926F0913-8142-430A-8400-6E6F0CD5B8F1@gmail.com> Message-ID: <4DC3259B.5020804@egenix.com> Raymond Hettinger wrote: > > On May 5, 2011, at 11:41 AM, Benjamin Peterson wrote: > >> 2011/5/5 raymond.hettinger : >>> http://hg.python.org/cpython/rev/1a56775c6e54 >>> changeset: 69857:1a56775c6e54 >>> branch: 3.2 >>> parent: 69855:97a4855202b8 >>> user: Raymond Hettinger >>> date: Thu May 05 11:35:50 2011 -0700 >>> summary: >>> Avoid codec spelling issues by just using the utf-8 default. >> >> Out of curiosity, what is the issue? > > IIRC, the performance depended on how your spelled-it. > I believe that is why the spelling got changed in Py3.3. Not really. It got changed because we have canonical names for the codecs which the stdlib should use rather than rely on aliases. Performance-wise it only makes a difference if you use it in tight loops. > Either way, the code is simpler by just using the default. ... as long as the casual reader knows what the default it :-) I think it's better to make the choice explicit, if the code relies on a particular non-ASCII encoding. If it doesn't, than the default is fine. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, May 06 2011) >>> Python/Zope Consulting and Support ... http://www.egenix.com/ >>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/ >>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/ ________________________________________________________________________ 2011-06-20: EuroPython 2011, Florence, Italy 45 days to go ::: Try our new mxODBC.Connect Python Database Interface for free ! :::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/ From alexander.belopolsky at gmail.com Fri May 6 00:54:11 2011 From: alexander.belopolsky at gmail.com (Alexander Belopolsky) Date: Thu, 5 May 2011 18:54:11 -0400 Subject: [Python-checkins] [Python-Dev] cpython (3.2): Avoid codec spelling issues by just using the utf-8 default. In-Reply-To: <4DC3259B.5020804@egenix.com> References: <926F0913-8142-430A-8400-6E6F0CD5B8F1@gmail.com> <4DC3259B.5020804@egenix.com> Message-ID: On Thu, May 5, 2011 at 6:32 PM, M.-A. Lemburg wrote: .. >> Either way, the code is simpler by just using the default. > > ... as long as the casual reader knows what the default it :-) > .. or cares. I this particular case, it hardly matters how random bits are encoded. From solipsis at pitrou.net Fri May 6 04:57:58 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 06 May 2011 04:57:58 +0200 Subject: [Python-checkins] Daily reference leaks (f20373fcdde5): sum=0 Message-ID: results for f20373fcdde5 on branch "default" -------------------------------------------- test_pydoc leaked [-323, 323, 0] references, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogRtHbWL', '-x'] From python-checkins at python.org Fri May 6 08:19:48 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 06 May 2011 08:19:48 +0200 Subject: [Python-checkins] cpython: Close handler opened in test. Message-ID: http://hg.python.org/cpython/rev/b122745b4e22 changeset: 69866:b122745b4e22 user: Vinay Sajip date: Fri May 06 07:19:41 2011 +0100 summary: Close handler opened in test. files: Lib/test/test_logging.py | 48 ++++++++++++++------------- 1 files changed, 25 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3484,29 +3484,31 @@ def test_rollover(self): fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S', backupCount=1) - r = logging.makeLogRecord({'msg': 'testing'}) - fh.emit(r) - self.assertLogFile(self.fn) - time.sleep(1.0) - fh.emit(r) - now = datetime.datetime.now() - prevsec = now - datetime.timedelta(seconds=1) - earlier = now - datetime.timedelta(seconds=2) - fn1 = self.fn + prevsec.strftime(".%Y-%m-%d_%H-%M-%S") - fn2 = self.fn + earlier.strftime(".%Y-%m-%d_%H-%M-%S") - success = os.path.exists(fn1) or os.path.exists(fn2) - if not success: - # print additional diagnostic information - print('Neither %s nor %s exists' % (fn1, fn2), file=sys.stderr) - dirname = os.path.dirname(fn1) - files = os.listdir(dirname) - files = [f for f in files if f.startswith('test_logging-2-')] - print('matching files: %s' % files, file=sys.stderr) - self.assertTrue(success) - for fn in (fn1, fn2): - if os.path.exists(fn): - self.rmfiles.append(fn) - + try: + r = logging.makeLogRecord({'msg': 'testing'}) + fh.emit(r) + self.assertLogFile(self.fn) + time.sleep(1.0) + fh.emit(r) + now = datetime.datetime.now() + prevsec = now - datetime.timedelta(seconds=1) + earlier = now - datetime.timedelta(seconds=2) + fn1 = self.fn + prevsec.strftime(".%Y-%m-%d_%H-%M-%S") + fn2 = self.fn + earlier.strftime(".%Y-%m-%d_%H-%M-%S") + success = os.path.exists(fn1) or os.path.exists(fn2) + if not success: + # print additional diagnostic information + print('Neither %s nor %s exists' % (fn1, fn2), file=sys.stderr) + dirname = os.path.dirname(fn1) + files = os.listdir(dirname) + files = [f for f in files if f.startswith('test_logging-2-')] + print('matching files: %s' % files, file=sys.stderr) + self.assertTrue(success) + for fn in (fn1, fn2): + if os.path.exists(fn): + self.rmfiles.append(fn) + finally: + fh.close() def test_invalid(self): assertRaises = self.assertRaises -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 08:30:35 2011 From: python-checkins at python.org (eli.bendersky) Date: Fri, 06 May 2011 08:30:35 +0200 Subject: [Python-checkins] cpython: Issue #11015: bring test.support docs up to date Message-ID: http://hg.python.org/cpython/rev/2fd435ac3551 changeset: 69867:2fd435ac3551 parent: 69865:f20373fcdde5 user: Eli Bendersky date: Fri May 06 09:29:27 2011 +0300 summary: Issue #11015: bring test.support docs up to date files: Doc/library/test.rst | 116 ++++++++++++++++++++++++++++-- 1 files changed, 106 insertions(+), 10 deletions(-) diff --git a/Doc/library/test.rst b/Doc/library/test.rst --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -218,14 +218,14 @@ .. data:: verbose - :const:`True` when verbose output is enabled. Should be checked when more + ``True`` when verbose output is enabled. Should be checked when more detailed information is desired about a running test. *verbose* is set by :mod:`test.regrtest`. .. data:: is_jython - :const:`True` if the running interpreter is Jython. + ``True`` if the running interpreter is Jython. .. data:: TESTFN @@ -233,6 +233,7 @@ Set to a name that is safe to use as the name of a temporary file. Any temporary file that is created should be closed and unlinked (removed). + The :mod:`test.support` module defines the following functions: @@ -244,7 +245,7 @@ .. function:: is_resource_enabled(resource) - Return :const:`True` if *resource* is enabled and available. The list of + Return ``True`` if *resource* is enabled and available. The list of available resources is only set when :mod:`test.regrtest` is executing the tests. @@ -253,7 +254,7 @@ Raise :exc:`ResourceDenied` if *resource* is not available. *msg* is the argument to :exc:`ResourceDenied` if it is raised. Always returns - :const:`True` if called by a function whose ``__name__`` is ``'__main__'``. + ``True`` if called by a function whose ``__name__`` is ``'__main__'``. Used when tests are executed by :mod:`test.regrtest`. @@ -281,6 +282,15 @@ This will run all tests defined in the named module. +.. function:: run_doctest(module, verbosity=None) + + Run :func:`doctest.testmod` on the given *module*. Return + ``(failure_count, test_count)``. + + If *verbosity* is ``None``, :func:`doctest.testmod` is run with verbosity + set to :data:`verbose`. Otherwise, it is run with verbosity set to + ``None``. + .. function:: check_warnings(\*filters, quiet=True) A convenience wrapper for :func:`warnings.catch_warnings()` that makes it @@ -291,12 +301,12 @@ ``check_warnings`` accepts 2-tuples of the form ``("message regexp", WarningCategory)`` as positional arguments. If one or more *filters* are - provided, or if the optional keyword argument *quiet* is :const:`False`, + provided, or if the optional keyword argument *quiet* is ``False``, it checks to make sure the warnings are as expected: each specified filter must match at least one of the warnings raised by the enclosed code or the test fails, and if any warnings are raised that do not match any of the specified filters the test fails. To disable the first of these checks, - set *quiet* to :const:`True`. + set *quiet* to ``True``. If no arguments are specified, it defaults to:: @@ -311,7 +321,7 @@ representing the most recent warning can also be accessed directly through the recorder object (see example below). If no warning has been raised, then any of the attributes that would otherwise be expected on an object - representing a warning will return :const:`None`. + representing a warning will return ``None``. The recorder object also has a :meth:`reset` method, which clears the warnings list. @@ -349,7 +359,7 @@ .. function:: captured_stdout() - This is a context manager that runs the :keyword:`with` statement body using + A context manager that runs the :keyword:`with` statement body using a :class:`StringIO.StringIO` object as sys.stdout. That object can be retrieved using the ``as`` clause of the :keyword:`with` statement. @@ -360,6 +370,50 @@ assert s.getvalue() == "hello" +.. function:: temp_cwd(name='tempcwd', quiet=False, path=None) + + A context manager that temporarily changes the current working + directory (CWD). + + An existing path may be provided as *path*, in which case this function + makes no changes to the file system. + + Otherwise, the new CWD is created in the current directory and it's named + *name*. If *quiet* is ``False`` and it's not possible to create or + change the CWD, an error is raised. If it's ``True``, only a warning + is raised and the original CWD is used. + + +.. function:: temp_umask(umask) + + A context manager that temporarily sets the process umask. + + +.. function:: can_symlink() + + Return ``True`` if the OS supports symbolic links, ``False`` + otherwise. + + +.. function:: skip_unless_symlink() + + A decorator for running tests that require support for symbolic links. + + +.. function:: run_with_locale(catstr, *locales) + + A decorator for running a function in a different locale, correctly + resetting it after it has finished. *catstr* is the locale category as + a string (for example ``"LC_ALL"``). The *locales* passed will be tried + sequentially, and the first valid locale will be used. + + +.. function:: make_bad_fd() + + Create an invalid file descriptor by opening and closing a temporary file, + and returning its descripor. + + .. function:: import_module(name, deprecated=False) This function imports and returns the named module. Unlike a normal @@ -367,7 +421,7 @@ cannot be imported. Module and package deprecation messages are suppressed during this import - if *deprecated* is :const:`True`. + if *deprecated* is ``True``. .. versionadded:: 3.1 @@ -391,7 +445,7 @@ ``sys.modules`` when the fresh import is complete. Module and package deprecation messages are suppressed during this import - if *deprecated* is :const:`True`. + if *deprecated* is ``True``. This function will raise :exc:`unittest.SkipTest` is the named module cannot be imported. @@ -408,6 +462,48 @@ .. versionadded:: 3.1 +.. function:: bind_port(sock, host=HOST) + + Bind the socket to a free port and return the port number. Relies on + ephemeral ports in order to ensure we are using an unbound port. This is + important as many tests may be running simultaneously, especially in a + buildbot environment. This method raises an exception if the + ``sock.family`` is :const:`~socket.AF_INET` and ``sock.type`` is + :const:`~socket.SOCK_STREAM`, and the socket has + :const:`~socket.SO_REUSEADDR` or :const:`~socket.SO_REUSEPORT` set on it. + Tests should never set these socket options for TCP/IP sockets. + The only case for setting these options is testing multicasting via + multiple UDP sockets. + + Additionally, if the :const:`~socket.SO_EXCLUSIVEADDRUSE` socket option is + available (i.e. on Windows), it will be set on the socket. This will + prevent anyone else from binding to our host/port for the duration of the + test. + + +.. function:: find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM) + + Returns an unused port that should be suitable for binding. This is + achieved by creating a temporary socket with the same family and type as + the ``sock`` parameter (default is :const:`~socket.AF_INET`, + :const:`~socket.SOCK_STREAM`), + and binding it to the specified host address (defaults to ``0.0.0.0``) + with the port set to 0, eliciting an unused ephemeral port from the OS. + The temporary socket is then closed and deleted, and the ephemeral port is + returned. + + Either this method or :func:`bind_port` should be used for any tests + where a server socket needs to be bound to a particular port for the + duration of the test. + Which one to use depends on whether the calling code is creating a python + socket, or if an unused port needs to be provided in a constructor + or passed to an external program (i.e. the ``-accept`` argument to + openssl's s_server mode). Always prefer :func:`bind_port` over + :func:`find_unused_port` where possible. Using a hard coded port is + discouraged since it can makes multiple instances of the test impossible to + run simultaneously, which is a problem for buildbots. + + The :mod:`test.support` module defines the following classes: .. class:: TransientResource(exc, **kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 08:30:36 2011 From: python-checkins at python.org (eli.bendersky) Date: Fri, 06 May 2011 08:30:36 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge Message-ID: http://hg.python.org/cpython/rev/c22d5b37f6a4 changeset: 69868:c22d5b37f6a4 parent: 69867:2fd435ac3551 parent: 69866:b122745b4e22 user: Eli Bendersky date: Fri May 06 09:31:02 2011 +0300 summary: merge files: Lib/test/test_logging.py | 48 ++++++++++++++------------- 1 files changed, 25 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3484,29 +3484,31 @@ def test_rollover(self): fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S', backupCount=1) - r = logging.makeLogRecord({'msg': 'testing'}) - fh.emit(r) - self.assertLogFile(self.fn) - time.sleep(1.0) - fh.emit(r) - now = datetime.datetime.now() - prevsec = now - datetime.timedelta(seconds=1) - earlier = now - datetime.timedelta(seconds=2) - fn1 = self.fn + prevsec.strftime(".%Y-%m-%d_%H-%M-%S") - fn2 = self.fn + earlier.strftime(".%Y-%m-%d_%H-%M-%S") - success = os.path.exists(fn1) or os.path.exists(fn2) - if not success: - # print additional diagnostic information - print('Neither %s nor %s exists' % (fn1, fn2), file=sys.stderr) - dirname = os.path.dirname(fn1) - files = os.listdir(dirname) - files = [f for f in files if f.startswith('test_logging-2-')] - print('matching files: %s' % files, file=sys.stderr) - self.assertTrue(success) - for fn in (fn1, fn2): - if os.path.exists(fn): - self.rmfiles.append(fn) - + try: + r = logging.makeLogRecord({'msg': 'testing'}) + fh.emit(r) + self.assertLogFile(self.fn) + time.sleep(1.0) + fh.emit(r) + now = datetime.datetime.now() + prevsec = now - datetime.timedelta(seconds=1) + earlier = now - datetime.timedelta(seconds=2) + fn1 = self.fn + prevsec.strftime(".%Y-%m-%d_%H-%M-%S") + fn2 = self.fn + earlier.strftime(".%Y-%m-%d_%H-%M-%S") + success = os.path.exists(fn1) or os.path.exists(fn2) + if not success: + # print additional diagnostic information + print('Neither %s nor %s exists' % (fn1, fn2), file=sys.stderr) + dirname = os.path.dirname(fn1) + files = os.listdir(dirname) + files = [f for f in files if f.startswith('test_logging-2-')] + print('matching files: %s' % files, file=sys.stderr) + self.assertTrue(success) + for fn in (fn1, fn2): + if os.path.exists(fn): + self.rmfiles.append(fn) + finally: + fh.close() def test_invalid(self): assertRaises = self.assertRaises -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 11:32:03 2011 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 06 May 2011 11:32:03 +0200 Subject: [Python-checkins] cpython (3.1): Fix for issue 10684: Folders get deleted when trying to change case with Message-ID: http://hg.python.org/cpython/rev/26da299ca88e changeset: 69869:26da299ca88e branch: 3.1 parent: 69843:3aa51217492c user: Ronald Oussoren date: Fri May 06 10:23:04 2011 +0200 summary: Fix for issue 10684: Folders get deleted when trying to change case with shutil.move (case insensitive file systems only) files: Lib/shutil.py | 8 +++++++- Lib/test/test_shutil.py | 18 ++++++++++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 29 insertions(+), 1 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -260,12 +260,18 @@ """ real_dst = dst if os.path.isdir(dst): + if _samefile(src, dst): + # We might be on a case insensitive filesystem, + # perform the rename anyway. + os.rename(src, dst) + return + real_dst = os.path.join(dst, _basename(src)) if os.path.exists(real_dst): raise Error("Destination path '%s' already exists" % real_dst) try: os.rename(src, real_dst) - except OSError: + except OSError as exc: if os.path.isdir(src): if _destinsrc(src, dst): raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -522,6 +522,24 @@ self.assertTrue(srcfile._exited_with[0] is None) self.assertTrue(srcfile._raised) + def test_move_dir_caseinsensitive(self): + # Renames a folder to the same name + # but a different case. + + self.src_dir = tempfile.mkdtemp() + dst_dir = os.path.join( + os.path.dirname(self.src_dir), + os.path.basename(self.src_dir).upper()) + self.assertNotEqual(self.src_dir, dst_dir) + + try: + shutil.move(self.src_dir, dst_dir) + self.assertTrue(os.path.isdir(dst_dir)) + finally: + if os.path.exists(dst_dir): + os.rmdir(dst_dir) + + def test_main(): support.run_unittest(TestShutil, TestMove, TestCopyFile) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,10 @@ Library ------- +- Issue #10684: shutil.move used to delete a folder on case insensitive + filesystems when the source and destination name where the same except + for the case. + - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 11:32:03 2011 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 06 May 2011 11:32:03 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/f5aa0e52dd81 changeset: 69870:f5aa0e52dd81 branch: 3.2 parent: 69862:9f58612bc334 parent: 69869:26da299ca88e user: Ronald Oussoren date: Fri May 06 10:57:22 2011 +0200 summary: merge from 3.1 files: Lib/shutil.py | 8 +++++++- Lib/test/test_shutil.py | 18 ++++++++++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 29 insertions(+), 1 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -311,12 +311,18 @@ """ real_dst = dst if os.path.isdir(dst): + if _samefile(src, dst): + # We might be on a case insensitive filesystem, + # perform the rename anyway. + os.rename(src, dst) + return + real_dst = os.path.join(dst, _basename(src)) if os.path.exists(real_dst): raise Error("Destination path '%s' already exists" % real_dst) try: os.rename(src, real_dst) - except OSError: + except OSError as exc: if os.path.isdir(src): if _destinsrc(src, dst): raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -951,6 +951,24 @@ self.assertTrue(srcfile._exited_with[0] is None) self.assertTrue(srcfile._raised) + def test_move_dir_caseinsensitive(self): + # Renames a folder to the same name + # but a different case. + + self.src_dir = tempfile.mkdtemp() + dst_dir = os.path.join( + os.path.dirname(self.src_dir), + os.path.basename(self.src_dir).upper()) + self.assertNotEqual(self.src_dir, dst_dir) + + try: + shutil.move(self.src_dir, dst_dir) + self.assertTrue(os.path.isdir(dst_dir)) + finally: + if os.path.exists(dst_dir): + os.rmdir(dst_dir) + + def test_main(): support.run_unittest(TestShutil, TestMove, TestCopyFile) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -596,6 +596,10 @@ and a non-zero offset, and an attempt to read past the end of file is made (IndexError is raised instead). Patch by Ross Lagerwall. +- Issue #10684: shutil.move used to delete a folder on case insensitive + filesystems when the source and destination name where the same except + for the case. + - 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. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 11:32:04 2011 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 06 May 2011 11:32:04 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/e781292fb65b changeset: 69871:e781292fb65b parent: 69868:c22d5b37f6a4 parent: 69870:f5aa0e52dd81 user: Ronald Oussoren date: Fri May 06 11:17:40 2011 +0200 summary: merge from 3.2 files: Lib/shutil.py | 8 +++++++- Lib/test/test_shutil.py | 18 ++++++++++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 29 insertions(+), 1 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -311,12 +311,18 @@ """ real_dst = dst if os.path.isdir(dst): + if _samefile(src, dst): + # We might be on a case insensitive filesystem, + # perform the rename anyway. + os.rename(src, dst) + return + real_dst = os.path.join(dst, _basename(src)) if os.path.exists(real_dst): raise Error("Destination path '%s' already exists" % real_dst) try: os.rename(src, real_dst) - except OSError: + except OSError as exc: if os.path.isdir(src): if _destinsrc(src, dst): raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -951,6 +951,24 @@ self.assertTrue(srcfile._exited_with[0] is None) self.assertTrue(srcfile._raised) + def test_move_dir_caseinsensitive(self): + # Renames a folder to the same name + # but a different case. + + self.src_dir = tempfile.mkdtemp() + dst_dir = os.path.join( + os.path.dirname(self.src_dir), + os.path.basename(self.src_dir).upper()) + self.assertNotEqual(self.src_dir, dst_dir) + + try: + shutil.move(self.src_dir, dst_dir) + self.assertTrue(os.path.isdir(dst_dir)) + finally: + if os.path.exists(dst_dir): + os.rmdir(dst_dir) + + def test_main(): support.run_unittest(TestShutil, TestMove, TestCopyFile) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,10 @@ Library ------- +- Issue #10684: shutil.move used to delete a folder on case insensitive + filesystems when the source and destination name where the same except + for the case. + - Issue #11647: objects created using contextlib.contextmanager now support more than one call to the function when used as a decorator. Initial patch by Ysj Ray. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 11:32:06 2011 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 06 May 2011 11:32:06 +0200 Subject: [Python-checkins] cpython (2.7): Backport fix for issue #10684 from 3.x Message-ID: http://hg.python.org/cpython/rev/051190230254 changeset: 69872:051190230254 branch: 2.7 parent: 69842:76a2354aa427 user: Ronald Oussoren date: Fri May 06 11:31:33 2011 +0200 summary: Backport fix for issue #10684 from 3.x files: Lib/shutil.py | 6 ++++++ Lib/test/test_shutil.py | 18 ++++++++++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -277,6 +277,12 @@ """ real_dst = dst if os.path.isdir(dst): + if _samefile(src, dst): + # We might be on a case insensitive filesystem, + # perform the rename anyway. + os.rename(src, dst) + return + real_dst = os.path.join(dst, _basename(src)) if os.path.exists(real_dst): raise Error, "Destination path '%s' already exists" % real_dst diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -805,6 +805,24 @@ self.assertTrue(srcfile._exited_with[0] is None) self.assertTrue(srcfile._raised) + def test_move_dir_caseinsensitive(self): + # Renames a folder to the same name + # but a different case. + + self.src_dir = tempfile.mkdtemp() + dst_dir = os.path.join( + os.path.dirname(self.src_dir), + os.path.basename(self.src_dir).upper()) + self.assertNotEqual(self.src_dir, dst_dir) + + try: + shutil.move(self.src_dir, dst_dir) + self.assertTrue(os.path.isdir(dst_dir)) + finally: + if os.path.exists(dst_dir): + os.rmdir(dst_dir) + + def test_main(): test_support.run_unittest(TestShutil, TestMove, TestCopyFile) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -77,6 +77,10 @@ Library ------- +- Issue #10684: shutil.move used to delete a folder on case insensitive + filesystems when the source and destination name where the same except + for the case. + - Issue #11982: fix json.loads('""') to return u'' rather than ''. - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 14:02:49 2011 From: python-checkins at python.org (ezio.melotti) Date: Fri, 06 May 2011 14:02:49 +0200 Subject: [Python-checkins] cpython: Issue #10775: assertRaises, assertRaisesRegex, assertWarns, and Message-ID: http://hg.python.org/cpython/rev/8fc801ca9ea1 changeset: 69873:8fc801ca9ea1 parent: 69871:e781292fb65b user: Ezio Melotti date: Fri May 06 15:01:41 2011 +0300 summary: Issue #10775: assertRaises, assertRaisesRegex, assertWarns, and assertWarnsRegex now accept a keyword argument 'msg' when used as context managers. Initial patch by Winston Ewert. files: Doc/library/unittest.rst | 45 ++++++-- Lib/unittest/case.py | 80 +++++++++------ Lib/unittest/test/test_assertions.py | 73 ++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 4 + 5 files changed, 158 insertions(+), 45 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -860,10 +860,11 @@ | ` | | | +-----------------------------------------+-----------------------------+---------------+ - All the assert methods (except :meth:`assertRaises`, - :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`). + All the assert methods accept a *msg* argument that, if specified, is used + as the error message on failure (see also :data:`longMessage`). + Note that the *msg* keyword argument can be passed to :meth:`assertRaises`, + :meth:`assertRaisesRegex`, :meth:`assertWarns`, :meth:`assertWarnsRegex` + only when they are used as a context manager. .. method:: assertEqual(first, second, msg=None) @@ -957,7 +958,7 @@ +---------------------------------------------------------+--------------------------------------+------------+ .. method:: assertRaises(exception, callable, *args, **kwds) - assertRaises(exception) + assertRaises(exception, msg=None) Test that an exception is raised when *callable* is called with any positional or keyword arguments that are also passed to @@ -966,12 +967,16 @@ To catch any of a group of exceptions, a tuple containing the exception classes may be passed as *exception*. - If only the *exception* argument is given, returns a context manager so - that the code under test can be written inline rather than as a function:: + If only the *exception* and possibly the *msg* arguments are given, + return a context manager so that the code under test can be written + inline rather than as a function:: with self.assertRaises(SomeException): do_something() + When used as a context manager, :meth:`assertRaises` accepts the + additional keyword argument *msg*. + The context manager will store the caught exception object in its :attr:`exception` attribute. This can be useful if the intention is to perform additional checks on the exception raised:: @@ -988,9 +993,12 @@ .. versionchanged:: 3.2 Added the :attr:`exception` attribute. + .. versionchanged:: 3.3 + Added the *msg* keyword argument when used as a context manager. + .. method:: assertRaisesRegex(exception, regex, callable, *args, **kwds) - assertRaisesRegex(exception, regex) + assertRaisesRegex(exception, regex, msg=None) Like :meth:`assertRaises` but also tests that *regex* matches on the string representation of the raised exception. *regex* may be @@ -1007,12 +1015,16 @@ .. versionadded:: 3.1 under the name ``assertRaisesRegexp``. + .. versionchanged:: 3.2 Renamed to :meth:`assertRaisesRegex`. + .. versionchanged:: 3.3 + Added the *msg* keyword argument when used as a context manager. + .. method:: assertWarns(warning, callable, *args, **kwds) - assertWarns(warning) + assertWarns(warning, msg=None) Test that a warning is triggered when *callable* is called with any positional or keyword arguments that are also passed to @@ -1021,12 +1033,16 @@ To catch any of a group of warnings, a tuple containing the warning classes may be passed as *warnings*. - If only the *warning* argument is given, returns a context manager so - that the code under test can be written inline rather than as a function:: + If only the *warning* and possibly the *msg* arguments are given, + returns a context manager so that the code under test can be written + inline rather than as a function:: with self.assertWarns(SomeWarning): do_something() + When used as a context manager, :meth:`assertRaises` accepts the + additional keyword argument *msg*. + The context manager will store the caught warning object in its :attr:`warning` attribute, and the source line which triggered the warnings in the :attr:`filename` and :attr:`lineno` attributes. @@ -1044,9 +1060,12 @@ .. versionadded:: 3.2 + .. versionchanged:: 3.3 + Added the *msg* keyword argument when used as a context manager. + .. method:: assertWarnsRegex(warning, regex, callable, *args, **kwds) - assertWarnsRegex(warning, regex) + assertWarnsRegex(warning, regex, msg=None) Like :meth:`assertWarns` but also tests that *regex* matches on the message of the triggered warning. *regex* may be a regular expression @@ -1064,6 +1083,8 @@ .. versionadded:: 3.2 + .. versionchanged:: 3.3 + Added the *msg* keyword argument when used as a context manager. There are also other methods used to perform more specific checks, such as: diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -104,9 +104,9 @@ class _AssertRaisesBaseContext(object): def __init__(self, expected, test_case, callable_obj=None, - expected_regex=None): + expected_regex=None): self.expected = expected - self.failureException = test_case.failureException + self.test_case = test_case if callable_obj is not None: try: self.obj_name = callable_obj.__name__ @@ -117,6 +117,24 @@ if isinstance(expected_regex, (bytes, str)): expected_regex = re.compile(expected_regex) self.expected_regex = expected_regex + self.msg = None + + def _raiseFailure(self, standardMsg): + msg = self.test_case._formatMessage(self.msg, standardMsg) + raise self.test_case.failureException(msg) + + def handle(self, name, callable_obj, args, kwargs): + """ + If callable_obj is None, assertRaises/Warns is being used as a + context manager, so check for a 'msg' kwarg and return self. + If callable_obj is not None, call it passing args and kwargs. + """ + if callable_obj is None: + self.msg = kwargs.pop('msg', None) + return self + with self: + callable_obj(*args, **kwargs) + class _AssertRaisesContext(_AssertRaisesBaseContext): @@ -132,11 +150,10 @@ except AttributeError: exc_name = str(self.expected) if self.obj_name: - raise self.failureException("{0} not raised by {1}" - .format(exc_name, self.obj_name)) + self._raiseFailure("{} not raised by {}".format(exc_name, + self.obj_name)) else: - raise self.failureException("{0} not raised" - .format(exc_name)) + self._raiseFailure("{} not raised".format(exc_name)) if not issubclass(exc_type, self.expected): # let unexpected exceptions pass through return False @@ -147,8 +164,8 @@ expected_regex = self.expected_regex if not expected_regex.search(str(exc_value)): - raise self.failureException('"%s" does not match "%s"' % - (expected_regex.pattern, str(exc_value))) + self._raiseFailure('"{}" does not match "{}"'.format( + expected_regex.pattern, str(exc_value))) return True @@ -192,14 +209,13 @@ return # 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_regex.pattern, str(first_matching))) + self._raiseFailure('"{}" does not match "{}"'.format( + 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)) + self._raiseFailure("{} not triggered by {}".format(exc_name, + self.obj_name)) else: - raise self.failureException("{0} not triggered" - .format(exc_name)) + self._raiseFailure("{} not triggered".format(exc_name)) class _TypeEqualityDict(object): @@ -547,7 +563,6 @@ except UnicodeDecodeError: return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg)) - def assertRaises(self, excClass, callableObj=None, *args, **kwargs): """Fail unless an exception of class excClass is thrown by callableObj when invoked with arguments args and keyword @@ -562,6 +577,9 @@ with self.assertRaises(SomeException): do_something() + An optional keyword argument 'msg' can be provided when assertRaises + is used as a context object. + The context manager keeps a reference to the exception as the 'exception' attribute. This allows you to inspect the exception after the assertion:: @@ -572,25 +590,25 @@ self.assertEqual(the_exception.error_code, 3) """ context = _AssertRaisesContext(excClass, self, callableObj) - if callableObj is None: - return context - with context: - callableObj(*args, **kwargs) + return context.handle('assertRaises', callableObj, args, kwargs) def assertWarns(self, expected_warning, callable_obj=None, *args, **kwargs): """Fail unless a warning of class warnClass is triggered - by callableObj when invoked with arguments args and keyword + by callable_obj when invoked with arguments args and keyword arguments kwargs. If a different type of warning is triggered, it will not be handled: depending on the other warning filtering rules in effect, it might be silenced, printed out, or raised as an exception. - If called with callableObj omitted or None, will return a + If called with callable_obj omitted or None, will return a context object used like this:: with self.assertWarns(SomeWarning): do_something() + An optional keyword argument 'msg' can be provided when assertWarns + is used as a context object. + The context manager keeps a reference to the first matching warning as the 'warning' attribute; similarly, the 'filename' and 'lineno' attributes give you information about the line @@ -603,10 +621,7 @@ self.assertEqual(the_warning.some_attribute, 147) """ context = _AssertWarnsContext(expected_warning, self, callable_obj) - if callable_obj is None: - return context - with context: - callable_obj(*args, **kwargs) + return context.handle('assertWarns', callable_obj, args, kwargs) def _getAssertEqualityFunc(self, first, second): """Get a detailed comparison function for the types of the two args. @@ -1083,15 +1098,15 @@ expected_regex: Regex (re pattern object or string) expected to be found in error message. callable_obj: Function to be called. + msg: Optional message used in case of failure. Can only be used + when assertRaisesRegex is used as a context manager. args: Extra args. kwargs: Extra kwargs. """ context = _AssertRaisesContext(expected_exception, self, callable_obj, expected_regex) - if callable_obj is None: - return context - with context: - callable_obj(*args, **kwargs) + + return context.handle('assertRaisesRegex', callable_obj, args, kwargs) def assertWarnsRegex(self, expected_warning, expected_regex, callable_obj=None, *args, **kwargs): @@ -1105,15 +1120,14 @@ expected_regex: Regex (re pattern object or string) expected to be found in error message. callable_obj: Function to be called. + msg: Optional message used in case of failure. Can only be used + when assertWarnsRegex is used as a context manager. args: Extra args. kwargs: Extra kwargs. """ context = _AssertWarnsContext(expected_warning, self, callable_obj, expected_regex) - if callable_obj is None: - return context - with context: - callable_obj(*args, **kwargs) + return context.handle('assertWarnsRegex', callable_obj, args, kwargs) def assertRegex(self, text, expected_regex, msg=None): """Fail the test unless the text matches the regular expression.""" diff --git a/Lib/unittest/test/test_assertions.py b/Lib/unittest/test/test_assertions.py --- a/Lib/unittest/test/test_assertions.py +++ b/Lib/unittest/test/test_assertions.py @@ -1,6 +1,7 @@ import datetime import warnings import unittest +from itertools import product class Test_Assertions(unittest.TestCase): @@ -145,6 +146,14 @@ self.testableTrue._formatMessage(one, '\uFFFD') def assertMessages(self, methodName, args, errors): + """ + Check that methodName(*args) raises the correct error messages. + errors should be a list of 4 regex that match the error when: + 1) longMessage = False and no msg passed; + 2) longMessage = False and msg passed; + 3) longMessage = True and no msg passed; + 4) longMessage = True and msg passed; + """ def getMethod(i): useTestableFalse = i < 2 if useTestableFalse: @@ -284,3 +293,67 @@ ["^unexpectedly identical: None$", "^oops$", "^unexpectedly identical: None$", "^unexpectedly identical: None : oops$"]) + + + def assertMessagesCM(self, methodName, args, func, errors): + """ + Check that the correct error messages are raised while executing: + with method(*args): + func() + *errors* should be a list of 4 regex that match the error when: + 1) longMessage = False and no msg passed; + 2) longMessage = False and msg passed; + 3) longMessage = True and no msg passed; + 4) longMessage = True and msg passed; + """ + p = product((self.testableFalse, self.testableTrue), + ({}, {"msg": "oops"})) + for (cls, kwargs), err in zip(p, errors): + method = getattr(cls, methodName) + with self.assertRaisesRegex(cls.failureException, err): + with method(*args, **kwargs) as cm: + func() + + def testAssertRaises(self): + self.assertMessagesCM('assertRaises', (TypeError,), lambda: None, + ['^TypeError not raised$', '^oops$', + '^TypeError not raised$', + '^TypeError not raised : oops$']) + + def testAssertRaisesRegex(self): + # test error not raised + self.assertMessagesCM('assertRaisesRegex', (TypeError, 'unused regex'), + lambda: None, + ['^TypeError not raised$', '^oops$', + '^TypeError not raised$', + '^TypeError not raised : oops$']) + # test error raised but with wrong message + def raise_wrong_message(): + raise TypeError('foo') + self.assertMessagesCM('assertRaisesRegex', (TypeError, 'regex'), + raise_wrong_message, + ['^"regex" does not match "foo"$', '^oops$', + '^"regex" does not match "foo"$', + '^"regex" does not match "foo" : oops$']) + + def testAssertWarns(self): + self.assertMessagesCM('assertWarns', (UserWarning,), lambda: None, + ['^UserWarning not triggered$', '^oops$', + '^UserWarning not triggered$', + '^UserWarning not triggered : oops$']) + + def testAssertWarnsRegex(self): + # test error not raised + self.assertMessagesCM('assertWarnsRegex', (UserWarning, 'unused regex'), + lambda: None, + ['^UserWarning not triggered$', '^oops$', + '^UserWarning not triggered$', + '^UserWarning not triggered : oops$']) + # test warning raised but with wrong message + def raise_wrong_message(): + warnings.warn('foo') + self.assertMessagesCM('assertWarnsRegex', (UserWarning, 'regex'), + raise_wrong_message, + ['^"regex" does not match "foo"$', '^oops$', + '^"regex" does not match "foo"$', + '^"regex" does not match "foo" : oops$']) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -269,6 +269,7 @@ Tim Everett Paul Everitt David Everly +Winston Ewert Greg Ewing Martijn Faassen Clovis Fabricio diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,10 @@ Library ------- +- Issue #10775: assertRaises, assertRaisesRegex, assertWarns, and + assertWarnsRegex now accept a keyword argument 'msg' when used as context + managers. Initial patch by Winston Ewert. + - Issue #10684: shutil.move used to delete a folder on case insensitive filesystems when the source and destination name where the same except for the case. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 15:32:50 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 06 May 2011 15:32:50 +0200 Subject: [Python-checkins] cpython (3.2): Issue #12000: When a SSL certificate has a subjectAltName without any Message-ID: http://hg.python.org/cpython/rev/d4c2a99d1bad changeset: 69874:d4c2a99d1bad branch: 3.2 parent: 69870:f5aa0e52dd81 user: Antoine Pitrou date: Fri May 06 15:19:49 2011 +0200 summary: Issue #12000: When a SSL certificate has a subjectAltName without any dNSName entry, ssl.match_hostname() should use the subject's commonName. Patch by Nicolas Bareil. files: Lib/ssl.py | 5 +++-- Lib/test/test_ssl.py | 18 ++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 4 ++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -122,8 +122,9 @@ if _dnsname_to_pat(value).match(hostname): return dnsnames.append(value) - if not san: - # The subject is only checked when subjectAltName is empty + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName for sub in cert.get('subject', ()): for key, value in sub: # XXX according to RFC 2818, the most specific Common Name diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -277,6 +277,24 @@ (('organizationName', 'Google Inc'),))} fail(cert, 'mail.google.com') + # No DNS entry in subjectAltName but a commonName + cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT', + 'subject': ((('countryName', 'US'),), + (('stateOrProvinceName', 'California'),), + (('localityName', 'Mountain View'),), + (('commonName', 'mail.google.com'),)), + 'subjectAltName': (('othername', 'blabla'), )} + ok(cert, 'mail.google.com') + + # No DNS entry subjectAltName and no commonName + cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT', + 'subject': ((('countryName', 'US'),), + (('stateOrProvinceName', 'California'),), + (('localityName', 'Mountain View'),), + (('organizationName', 'Google Inc'),)), + 'subjectAltName': (('othername', 'blabla'),)} + fail(cert, 'google.com') + # Empty cert / no cert self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com') self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com') diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -49,6 +49,7 @@ Jeff Balogh Matt Bandy Michael J. Barber +Nicolas Bareil Chris Barker Nick Barnes Quentin Barnes diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,10 @@ Library ------- +- Issue #12000: When a SSL certificate has a subjectAltName without any + dNSName entry, ssl.match_hostname() should use the subject's commonName. + Patch by Nicolas Bareil. + - Issue #11647: objects created using contextlib.contextmanager now support more than one call to the function when used as a decorator. Initial patch by Ysj Ray. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 15:32:52 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 06 May 2011 15:32:52 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #12000: When a SSL certificate has a subjectAltName without any Message-ID: http://hg.python.org/cpython/rev/1b37827984ba changeset: 69875:1b37827984ba parent: 69873:8fc801ca9ea1 parent: 69874:d4c2a99d1bad user: Antoine Pitrou date: Fri May 06 15:20:55 2011 +0200 summary: Issue #12000: When a SSL certificate has a subjectAltName without any dNSName entry, ssl.match_hostname() should use the subject's commonName. Patch by Nicolas Bareil. files: Lib/ssl.py | 5 +++-- Lib/test/test_ssl.py | 18 ++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 4 ++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -122,8 +122,9 @@ if _dnsname_to_pat(value).match(hostname): return dnsnames.append(value) - if not san: - # The subject is only checked when subjectAltName is empty + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName for sub in cert.get('subject', ()): for key, value in sub: # XXX according to RFC 2818, the most specific Common Name diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -277,6 +277,24 @@ (('organizationName', 'Google Inc'),))} fail(cert, 'mail.google.com') + # No DNS entry in subjectAltName but a commonName + cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT', + 'subject': ((('countryName', 'US'),), + (('stateOrProvinceName', 'California'),), + (('localityName', 'Mountain View'),), + (('commonName', 'mail.google.com'),)), + 'subjectAltName': (('othername', 'blabla'), )} + ok(cert, 'mail.google.com') + + # No DNS entry subjectAltName and no commonName + cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT', + 'subject': ((('countryName', 'US'),), + (('stateOrProvinceName', 'California'),), + (('localityName', 'Mountain View'),), + (('organizationName', 'Google Inc'),)), + 'subjectAltName': (('othername', 'blabla'),)} + fail(cert, 'google.com') + # Empty cert / no cert self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com') self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com') diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -50,6 +50,7 @@ Jeff Balogh Matt Bandy Michael J. Barber +Nicolas Bareil Chris Barker Nick Barnes Quentin Barnes diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,10 @@ Library ------- +- Issue #12000: When a SSL certificate has a subjectAltName without any + dNSName entry, ssl.match_hostname() should use the subject's commonName. + Patch by Nicolas Bareil. + - Issue #10775: assertRaises, assertRaisesRegex, assertWarns, and assertWarnsRegex now accept a keyword argument 'msg' when used as context managers. Initial patch by Winston Ewert. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 17:11:50 2011 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 06 May 2011 17:11:50 +0200 Subject: [Python-checkins] cpython (3.2): ntpath.samefile fails to detect that "A.TXT" and "a.txt" refer to the same file Message-ID: http://hg.python.org/cpython/rev/011e4bb8b933 changeset: 69876:011e4bb8b933 branch: 3.2 parent: 69874:d4c2a99d1bad user: Ronald Oussoren date: Fri May 06 17:11:07 2011 +0200 summary: ntpath.samefile fails to detect that "A.TXT" and "a.txt" refer to the same file on Windows XP. Noticed while researching a buildbot failure due to a patch for issue #10684. files: Lib/ntpath.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -654,7 +654,7 @@ # Non-Windows operating systems fake this method with an XP # approximation. def _getfinalpathname(f): - return abspath(f) + return normcase(abspath(f)) def samefile(f1, f2): "Test whether two pathnames reference the same actual file" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,9 @@ Library ------- +- ntpath.samefile failed to notice that "a.txt" and "A.TXT" refer to the same + file on Windows XP. As noticed in issue #10684. + - Issue #12000: When a SSL certificate has a subjectAltName without any dNSName entry, ssl.match_hostname() should use the subject's commonName. Patch by Nicolas Bareil. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 17:11:52 2011 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 06 May 2011 17:11:52 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/5fa92a47016c changeset: 69877:5fa92a47016c parent: 69875:1b37827984ba parent: 69876:011e4bb8b933 user: Ronald Oussoren date: Fri May 06 17:11:44 2011 +0200 summary: merge from 3.2 files: Lib/ntpath.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -654,7 +654,7 @@ # Non-Windows operating systems fake this method with an XP # approximation. def _getfinalpathname(f): - return abspath(f) + return normcase(abspath(f)) def samefile(f1, f2): "Test whether two pathnames reference the same actual file" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,9 @@ Library ------- +- ntpath.samefile failed to notice that "a.txt" and "A.TXT" refer to the same + file on Windows XP. As noticed in issue #10684. + - Issue #12000: When a SSL certificate has a subjectAltName without any dNSName entry, ssl.match_hostname() should use the subject's commonName. Patch by Nicolas Bareil. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 18:49:57 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 06 May 2011 18:49:57 +0200 Subject: [Python-checkins] cpython: Issue #8808: The IMAP4_SSL constructor now allows passing an SSLContext Message-ID: http://hg.python.org/cpython/rev/aba7d1f2d2a9 changeset: 69878:aba7d1f2d2a9 user: Antoine Pitrou date: Fri May 06 18:49:52 2011 +0200 summary: Issue #8808: The IMAP4_SSL constructor now allows passing an SSLContext parameter to control parameters of the secure channel. Patch by Sijin Joseph. files: Doc/library/imaplib.rst | 11 ++++- Lib/imaplib.py | 23 +++++++++-- Lib/test/test_imaplib.py | 55 +++++++++++++++++++++++++-- Misc/NEWS | 4 ++ 4 files changed, 83 insertions(+), 10 deletions(-) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -64,14 +64,21 @@ There's also a subclass for secure connections: -.. class:: IMAP4_SSL(host='', port=IMAP4_SSL_PORT, keyfile=None, certfile=None) +.. class:: IMAP4_SSL(host='', port=IMAP4_SSL_PORT, keyfile=None, certfile=None, ssl_context=None) This is a subclass derived from :class:`IMAP4` that connects over an SSL encrypted socket (to use this class you need a socket module that was compiled with SSL support). If *host* is not specified, ``''`` (the local host) is used. If *port* is omitted, the standard IMAP4-over-SSL port (993) is used. *keyfile* and *certfile* are also optional - they can contain a PEM formatted private key - and certificate chain file for the SSL connection. + and certificate chain file for the SSL connection. *ssl_context* parameter is a + :class:`ssl.SSLContext` object which allows bundling SSL configuration + options, certificates and private keys into a single (potentially long-lived) + structure. Note that the *keyfile*/*certfile* parameters are mutually exclusive with *ssl_context*, + a :class:`ValueError` is thrown if *keyfile*/*certfile* is provided along with *ssl_context*. + + .. versionchanged:: 3.3 + *ssl_context* parameter added. The second subclass allows for connections created by a child process: diff --git a/Lib/imaplib.py b/Lib/imaplib.py --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -1177,25 +1177,40 @@ """IMAP4 client class over SSL connection - Instantiate with: IMAP4_SSL([host[, port[, keyfile[, certfile]]]]) + Instantiate with: IMAP4_SSL([host[, port[, keyfile[, certfile[, ssl_context]]]]]) host - host's name (default: localhost); - port - port number (default: standard IMAP4 SSL port). + port - port number (default: standard IMAP4 SSL port); keyfile - PEM formatted file that contains your private key (default: None); certfile - PEM formatted certificate chain file (default: None); + ssl_context - a SSLContext object that contains your certificate chain + and private key (default: None) + Note: if ssl_context is provided, then parameters keyfile or + certfile should not be set otherwise ValueError is thrown. for more documentation see the docstring of the parent class IMAP4. """ - def __init__(self, host = '', port = IMAP4_SSL_PORT, keyfile = None, certfile = None): + def __init__(self, host='', port=IMAP4_SSL_PORT, keyfile=None, certfile=None, ssl_context=None): + if ssl_context is not None and keyfile is not None: + raise ValueError("ssl_context and keyfile arguments are mutually " + "exclusive") + if ssl_context is not None and certfile is not None: + raise ValueError("ssl_context and certfile arguments are mutually " + "exclusive") + self.keyfile = keyfile self.certfile = certfile + self.ssl_context = ssl_context IMAP4.__init__(self, host, port) def _create_socket(self): sock = IMAP4._create_socket(self) - return ssl.wrap_socket(sock, self.keyfile, self.certfile) + if self.ssl_context: + return self.ssl_context.wrap_socket(sock) + else: + return ssl.wrap_socket(sock, self.keyfile, self.certfile) def open(self, host='', port=IMAP4_SSL_PORT): """Setup connection to remote server on "host:port". diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -258,11 +258,58 @@ port = 993 imap_class = IMAP4_SSL + def setUp(self): + pass + + def tearDown(self): + pass + + def create_ssl_context(self): + ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + ssl_context.load_cert_chain(CERTFILE) + return ssl_context + + def check_logincapa(self, server): + try: + for cap in server.capabilities: + self.assertIsInstance(cap, str) + self.assertFalse('LOGINDISABLED' in server.capabilities) + self.assertTrue('AUTH=PLAIN' in server.capabilities) + rs = server.login(self.username, self.password) + self.assertEqual(rs[0], 'OK') + finally: + server.logout() + def test_logincapa(self): - for cap in self.server.capabilities: - self.assertIsInstance(cap, str) - self.assertFalse('LOGINDISABLED' in self.server.capabilities) - self.assertTrue('AUTH=PLAIN' in self.server.capabilities) + with transient_internet(self.host): + _server = self.imap_class(self.host, self.port) + self.check_logincapa(_server) + + def test_logincapa_with_client_certfile(self): + with transient_internet(self.host): + _server = self.imap_class(self.host, self.port, certfile=CERTFILE) + self.check_logincapa(_server) + + def test_logincapa_with_client_ssl_context(self): + with transient_internet(self.host): + _server = self.imap_class(self.host, self.port, ssl_context=self.create_ssl_context()) + self.check_logincapa(_server) + + def test_logout(self): + with transient_internet(self.host): + _server = self.imap_class(self.host, self.port) + rs = _server.logout() + self.assertEqual(rs[0], 'BYE') + + def test_ssl_context_certfile_exclusive(self): + with transient_internet(self.host): + self.assertRaises(ValueError, self.imap_class, self.host, self.port, + certfile=CERTFILE, ssl_context=self.create_ssl_context()) + + def test_ssl_context_keyfile_exclusive(self): + with transient_internet(self.host): + self.assertRaises(ValueError, self.imap_class, self.host, self.port, + keyfile=CERTFILE, ssl_context=self.create_ssl_context()) def test_main(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,10 @@ Library ------- +- Issue #8808: The IMAP4_SSL constructor now allows passing an SSLContext + parameter to control parameters of the secure channel. Patch by Sijin + Joseph. + - ntpath.samefile failed to notice that "a.txt" and "A.TXT" refer to the same file on Windows XP. As noticed in issue #10684. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 19:49:13 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Fri, 06 May 2011 19:49:13 +0200 Subject: [Python-checkins] cpython: Issue #11072: added MLSD command (RFC-3659) support to ftplib. Message-ID: http://hg.python.org/cpython/rev/56bce38b274f changeset: 69879:56bce38b274f user: Giampaolo Rodola' date: Fri May 06 19:49:08 2011 +0200 summary: Issue #11072: added MLSD command (RFC-3659) support to ftplib. files: Doc/library/ftplib.rst | 29 +++++++-- Lib/ftplib.py | 30 +++++++++- Lib/test/test_ftplib.py | 86 ++++++++++++++++++++++++++++- Misc/NEWS | 2 + 4 files changed, 139 insertions(+), 8 deletions(-) diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -254,13 +254,12 @@ Retrieve a file or directory listing in ASCII transfer mode. *cmd* should be an appropriate ``RETR`` command (see :meth:`retrbinary`) or a command such as - ``LIST``, ``NLST`` or ``MLSD`` (usually just the string ``'LIST'``). + ``LIST`` or ``NLST`` (usually just the string ``'LIST'``). ``LIST`` retrieves a list of files and information about those files. - ``NLST`` retrieves a list of file names. On some servers, ``MLSD`` retrieves - a machine readable list of files and information about those files. The - *callback* function is called for each line with a string argument containing - the line with the trailing CRLF stripped. The default *callback* prints the - line to ``sys.stdout``. + ``NLST`` retrieves a list of file names. + The *callback* function is called for each line with a string argument + containing the line with the trailing CRLF stripped. The default *callback* + prints the line to ``sys.stdout``. .. method:: FTP.set_pasv(boolean) @@ -320,6 +319,20 @@ in :meth:`transfercmd`. +.. method:: FTP.mlsd(path="", facts=[]) + + List a directory in a standardized format by using MLSD command + (:rfc:`3659`). If *path* is omitted the current directory is assumed. + *facts* is a list of strings representing the type of information desired + (e.g. *["type", "size", "perm"]*). Return a generator object yielding a + tuple of two elements for every file found in path. First element is the + file name, the second one is a dictionary including a variable number of + "facts" depending on the server and whether *facts* argument has been + provided. + + .. versionadded:: 3.3 + + .. method:: FTP.nlst(argument[, ...]) Return a list of file names as returned by the ``NLST`` command. The @@ -327,6 +340,8 @@ directory). Multiple arguments can be used to pass non-standard options to the ``NLST`` command. + .. deprecated:: 3.3 use :meth:`mlsd` instead + .. method:: FTP.dir(argument[, ...]) @@ -337,6 +352,8 @@ as a *callback* function as for :meth:`retrlines`; the default prints to ``sys.stdout``. This method returns ``None``. + .. deprecated:: 3.3 use :meth:`mlsd` instead + .. method:: FTP.rename(fromname, toname) diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -426,7 +426,7 @@ """Retrieve data in line mode. A new port is created for you. Args: - cmd: A RETR, LIST, NLST, or MLSD command. + cmd: A RETR, LIST, or NLST command. callback: An optional single parameter callable that is called for each line with the trailing CRLF stripped. [default: print_line()] @@ -527,6 +527,34 @@ cmd = cmd + (' ' + arg) self.retrlines(cmd, func) + def mlsd(self, path="", facts=[]): + '''List a directory in a standardized format by using MLSD + command (RFC-3659). If path is omitted the current directory + is assumed. "facts" is a list of strings representing the type + of information desired (e.g. ["type", "size", "perm"]). + + Return a generator object yielding a tuple of two elements + for every file found in path. + First element is the file name, the second one is a dictionary + including a variable number of "facts" depending on the server + and whether "facts" argument has been provided. + ''' + if facts: + self.sendcmd("OPTS MLST " + ";".join(facts) + ";") + if path: + cmd = "MLSD %s" % path + else: + cmd = "MLSD" + lines = [] + self.retrlines(cmd, lines.append) + for line in lines: + facts_found, _, name = line.rstrip(CRLF).partition(' ') + entry = {} + for fact in facts_found[:-1].split(";"): + key, _, value = fact.partition("=") + entry[key.lower()] = value + yield (name, entry) + def rename(self, fromname, toname): '''Rename a file.''' resp = self.sendcmd('RNFR ' + fromname) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -22,10 +22,25 @@ threading = support.import_module('threading') # the dummy data returned by server over the data channel when -# RETR, LIST and NLST commands are issued +# RETR, LIST, NLST, MLSD commands are issued RETR_DATA = 'abcde12345\r\n' * 1000 LIST_DATA = 'foo\r\nbar\r\n' NLST_DATA = 'foo\r\nbar\r\n' +MLSD_DATA = ("type=cdir;perm=el;unique==keVO1+ZF4; test\r\n" + "type=pdir;perm=e;unique==keVO1+d?3; ..\r\n" + "type=OS.unix=slink:/foobar;perm=;unique==keVO1+4G4; foobar\r\n" + "type=OS.unix=chr-13/29;perm=;unique==keVO1+5G4; device\r\n" + "type=OS.unix=blk-11/108;perm=;unique==keVO1+6G4; block\r\n" + "type=file;perm=awr;unique==keVO1+8G4; writable\r\n" + "type=dir;perm=cpmel;unique==keVO1+7G4; promiscuous\r\n" + "type=dir;perm=;unique==keVO1+1t2; no-exec\r\n" + "type=file;perm=r;unique==keVO1+EG4; two words\r\n" + "type=file;perm=r;unique==keVO1+IH4; leading space\r\n" + "type=file;perm=r;unique==keVO1+1G4; file1\r\n" + "type=dir;perm=cpmel;unique==keVO1+7G4; incoming\r\n" + "type=file;perm=r;unique==keVO1+1G4; file2\r\n" + "type=file;perm=r;unique==keVO1+1G4; file3\r\n" + "type=file;perm=r;unique==keVO1+1G4; file4\r\n") class DummyDTPHandler(asynchat.async_chat): @@ -49,6 +64,11 @@ self.dtp_conn_closed = True def push(self, what): + if self.baseclass.next_data is not None: + what = self.baseclass.next_data + self.baseclass.next_data = None + if not what: + return self.close_when_done() super(DummyDTPHandler, self).push(what.encode('ascii')) def handle_error(self): @@ -67,6 +87,7 @@ self.last_received_cmd = None self.last_received_data = '' self.next_response = '' + self.next_data = None self.rest = None self.push('220 welcome') @@ -208,6 +229,14 @@ self.dtp.push(NLST_DATA) self.dtp.close_when_done() + def cmd_opts(self, arg): + self.push('200 opts ok') + + def cmd_mlsd(self, arg): + self.push('125 mlsd ok') + self.dtp.push(MLSD_DATA) + self.dtp.close_when_done() + class DummyFTPServer(asyncore.dispatcher, threading.Thread): @@ -550,6 +579,61 @@ self.client.dir(lambda x: l.append(x)) self.assertEqual(''.join(l), LIST_DATA.replace('\r\n', '')) + def test_mlsd(self): + list(self.client.mlsd()) + list(self.client.mlsd(path='/')) + list(self.client.mlsd(path='/', facts=['size', 'type'])) + + ls = list(self.client.mlsd()) + for name, facts in ls: + self.assertTrue(name) + self.assertTrue('type' in facts) + self.assertTrue('perm' in facts) + self.assertTrue('unique' in facts) + + def set_data(data): + self.server.handler_instance.next_data = data + + def test_entry(line, type=None, perm=None, unique=None, name=None): + type = 'type' if type is None else type + perm = 'perm' if perm is None else perm + unique = 'unique' if unique is None else unique + name = 'name' if name is None else name + set_data(line) + _name, facts = next(self.client.mlsd()) + self.assertEqual(_name, name) + self.assertEqual(facts['type'], type) + self.assertEqual(facts['perm'], perm) + self.assertEqual(facts['unique'], unique) + + # plain + test_entry('type=type;perm=perm;unique=unique; name\r\n') + # "=" in fact value + test_entry('type=ty=pe;perm=perm;unique=unique; name\r\n', type="ty=pe") + test_entry('type==type;perm=perm;unique=unique; name\r\n', type="=type") + test_entry('type=t=y=pe;perm=perm;unique=unique; name\r\n', type="t=y=pe") + test_entry('type=====;perm=perm;unique=unique; name\r\n', type="====") + # spaces in name + test_entry('type=type;perm=perm;unique=unique; na me\r\n', name="na me") + test_entry('type=type;perm=perm;unique=unique; name \r\n', name="name ") + test_entry('type=type;perm=perm;unique=unique; name\r\n', name=" name") + test_entry('type=type;perm=perm;unique=unique; n am e\r\n', name="n am e") + # ";" in name + test_entry('type=type;perm=perm;unique=unique; na;me\r\n', name="na;me") + test_entry('type=type;perm=perm;unique=unique; ;name\r\n', name=";name") + test_entry('type=type;perm=perm;unique=unique; ;name;\r\n', name=";name;") + test_entry('type=type;perm=perm;unique=unique; ;;;;\r\n', name=";;;;") + # case sensitiveness + set_data('Type=type;TyPe=perm;UNIQUE=unique; name\r\n') + _name, facts = next(self.client.mlsd()) + [self.assertTrue(x.islower()) for x in facts.keys()] + # no data (directory empty) + set_data('') + self.assertRaises(StopIteration, next, self.client.mlsd()) + set_data('') + for x in self.client.mlsd(): + self.fail("unexpected data %s" % data) + def test_makeport(self): with self.client.makeport(): # IPv4 is in use, just make sure send_eprt has not been used diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,8 @@ Library ------- +- Issue #11072: added MLSD command (RFC-3659) support to ftplib. + - Issue #8808: The IMAP4_SSL constructor now allows passing an SSLContext parameter to control parameters of the secure channel. Patch by Sijin Joseph. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 6 20:06:18 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 06 May 2011 20:06:18 +0200 Subject: [Python-checkins] cpython: Refined rollover test for slow test machines. Message-ID: http://hg.python.org/cpython/rev/5661480f7763 changeset: 69880:5661480f7763 user: Vinay Sajip date: Fri May 06 19:06:00 2011 +0100 summary: Refined rollover test for slow test machines. files: Lib/test/test_logging.py | 31 ++++++++++++++------------- 1 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3490,23 +3490,24 @@ self.assertLogFile(self.fn) time.sleep(1.0) fh.emit(r) + # At this point, we should have a recent rotated file which we + # can test for the existence of. However, in practice, on some + # machines which run really slowly, we don't know how far back + # in time to go to look for the log file. So, we go back a fair + # bit, and stop as soon as we see a rotated file. In theory this + # could of course still fail, but the chances are lower. + found = False now = datetime.datetime.now() - prevsec = now - datetime.timedelta(seconds=1) - earlier = now - datetime.timedelta(seconds=2) - fn1 = self.fn + prevsec.strftime(".%Y-%m-%d_%H-%M-%S") - fn2 = self.fn + earlier.strftime(".%Y-%m-%d_%H-%M-%S") - success = os.path.exists(fn1) or os.path.exists(fn2) - if not success: - # print additional diagnostic information - print('Neither %s nor %s exists' % (fn1, fn2), file=sys.stderr) - dirname = os.path.dirname(fn1) - files = os.listdir(dirname) - files = [f for f in files if f.startswith('test_logging-2-')] - print('matching files: %s' % files, file=sys.stderr) - self.assertTrue(success) - for fn in (fn1, fn2): - if os.path.exists(fn): + GO_BACK = 2 * 60 # seconds + for secs in range(1, GO_BACK): + prev = now - datetime.timedelta(seconds=secs) + fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S") + found = os.path.exists(fn) + if found: self.rmfiles.append(fn) + break + msg = 'No rotated files found, went back %d seconds' % GO_BACK + self.assertTrue(found, msg=msg) finally: fh.close() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 00:30:55 2011 From: python-checkins at python.org (barry.warsaw) Date: Sat, 7 May 2011 00:30:55 +0200 (CEST) Subject: [Python-checkins] r88829 - in python/branches/release26-maint: Doc/README.txt Doc/copyright.rst Doc/license.rst Include/patchlevel.h LICENSE Lib/distutils/__init__.py Lib/idlelib/idlever.py Lib/pydoc_topics.py Misc/NEWS Misc/RPM/python-2.6.spec PC/python_nt.rc Python/getcopyright.c README Message-ID: <3QR79W62bmz7LjR@mail.python.org> Author: barry.warsaw Date: Sat May 7 00:30:55 2011 New Revision: 88829 Log: The usual, for Python 2.6.7rc1. Modified: python/branches/release26-maint/Doc/README.txt python/branches/release26-maint/Doc/copyright.rst python/branches/release26-maint/Doc/license.rst python/branches/release26-maint/Include/patchlevel.h python/branches/release26-maint/LICENSE python/branches/release26-maint/Lib/distutils/__init__.py python/branches/release26-maint/Lib/idlelib/idlever.py python/branches/release26-maint/Lib/pydoc_topics.py python/branches/release26-maint/Misc/NEWS python/branches/release26-maint/Misc/RPM/python-2.6.spec python/branches/release26-maint/PC/python_nt.rc python/branches/release26-maint/Python/getcopyright.c python/branches/release26-maint/README Modified: python/branches/release26-maint/Doc/README.txt ============================================================================== --- python/branches/release26-maint/Doc/README.txt (original) +++ python/branches/release26-maint/Doc/README.txt Sat May 7 00:30:55 2011 @@ -127,7 +127,7 @@ as long as you don't change or remove the copyright notice: ---------------------------------------------------------------------- -Copyright (c) 2000-2008 Python Software Foundation. +Copyright (c) 2000-2011 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. Modified: python/branches/release26-maint/Doc/copyright.rst ============================================================================== --- python/branches/release26-maint/Doc/copyright.rst (original) +++ python/branches/release26-maint/Doc/copyright.rst Sat May 7 00:30:55 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/release26-maint/Doc/license.rst ============================================================================== --- python/branches/release26-maint/Doc/license.rst (original) +++ python/branches/release26-maint/Doc/license.rst Sat May 7 00:30:55 2011 @@ -104,6 +104,10 @@ +----------------+--------------+-----------+------------+-----------------+ | 2.6.5 | 2.6.4 | 2010 | PSF | yes | +----------------+--------------+-----------+------------+-----------------+ +| 2.6.6 | 2.6.5 | 2010 | PSF | yes | ++----------------+--------------+-----------+------------+-----------------+ +| 2.6.7 | 2.6.6 | 2011 | PSF | yes | ++----------------+--------------+-----------+------------+-----------------+ .. note:: Modified: python/branches/release26-maint/Include/patchlevel.h ============================================================================== --- python/branches/release26-maint/Include/patchlevel.h (original) +++ python/branches/release26-maint/Include/patchlevel.h Sat May 7 00:30:55 2011 @@ -22,12 +22,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 2 #define PY_MINOR_VERSION 6 -#define PY_MICRO_VERSION 6 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 +#define PY_MICRO_VERSION 7 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "2.6.6+" +#define PY_VERSION "2.6.7rc1" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository) */ Modified: python/branches/release26-maint/LICENSE ============================================================================== --- python/branches/release26-maint/LICENSE (original) +++ python/branches/release26-maint/LICENSE Sat May 7 00:30:55 2011 @@ -63,6 +63,8 @@ 2.6.3 2.6.2 2009 PSF yes 2.6.4 2.6.3 2009 PSF yes 2.6.5 2.6.4 2010 PSF yes + 2.6.6 2.6.5 2010 PSF yes + 2.6.7 2.6.6 2011 PSF yes Footnotes: Modified: python/branches/release26-maint/Lib/distutils/__init__.py ============================================================================== --- python/branches/release26-maint/Lib/distutils/__init__.py (original) +++ python/branches/release26-maint/Lib/distutils/__init__.py Sat May 7 00:30:55 2011 @@ -22,5 +22,5 @@ # #--start constants-- -__version__ = "2.6.6" +__version__ = "2.6.7rc1" #--end constants-- Modified: python/branches/release26-maint/Lib/idlelib/idlever.py ============================================================================== --- python/branches/release26-maint/Lib/idlelib/idlever.py (original) +++ python/branches/release26-maint/Lib/idlelib/idlever.py Sat May 7 00:30:55 2011 @@ -1 +1 @@ -IDLE_VERSION = "2.6.6" +IDLE_VERSION = "2.6.7rc1" Modified: python/branches/release26-maint/Lib/pydoc_topics.py ============================================================================== --- python/branches/release26-maint/Lib/pydoc_topics.py (original) +++ python/branches/release26-maint/Lib/pydoc_topics.py Sat May 7 00:30:55 2011 @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Mon Aug 23 19:33:46 2010 +# Autogenerated by Sphinx on Fri May 6 18:02:17 2011 topics = {'assert': u'\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': u'\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\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 is recursively defined as\nfollows.\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\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`` statement in the\n current code block: the name is bound to the object in the current\n local namespace.\n\n * Otherwise: the name is bound to the object in the current global\n namespace.\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 a plain integer. If it is negative, the\n sequence\'s length is added to it. The resulting value must be a\n nonnegative integer less than the sequence\'s length, and the\n sequence is asked to assign the assigned object to its item with\n that index. If the index is out of range, ``IndexError`` is raised\n (assignment to a subscripted sequence cannot add new items to a\n 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* 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 (small) integers. If either\n bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the 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\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': u'\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', Modified: python/branches/release26-maint/Misc/NEWS ============================================================================== --- python/branches/release26-maint/Misc/NEWS (original) +++ python/branches/release26-maint/Misc/NEWS Sat May 7 00:30:55 2011 @@ -4,10 +4,10 @@ (editors: check NEWS.help for information about editing NEWS using ReST.) -What's New in Python 2.6.7? -=========================== +What's New in Python 2.6.7 rc 1? +================================ -*Release date: XXXX-XX-XX* +*Release date: 2011-05-06* *NOTE: Python 2.6 is in security-fix-only mode. No non-security bug fixes are allowed. Python 2.6.7 and beyond will be source only releases.* @@ -22,6 +22,7 @@ - Issue #9129: smtpd.py is vulnerable to DoS attacks deriving from missing error handling when accepting a new connection. + What's New in Python 2.6.6? =========================== Modified: python/branches/release26-maint/Misc/RPM/python-2.6.spec ============================================================================== --- python/branches/release26-maint/Misc/RPM/python-2.6.spec (original) +++ python/branches/release26-maint/Misc/RPM/python-2.6.spec Sat May 7 00:30:55 2011 @@ -39,8 +39,8 @@ %define name python #--start constants-- -%define version 2.6.6 -%define libver 2.6 +%define version 2.6.7rc1 +%define libvers 2.6 #--end constants-- %define release 1pydotorg %define __prefix /usr Modified: python/branches/release26-maint/PC/python_nt.rc ============================================================================== --- python/branches/release26-maint/PC/python_nt.rc (original) +++ python/branches/release26-maint/PC/python_nt.rc Sat May 7 00:30:55 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/release26-maint/Python/getcopyright.c ============================================================================== --- python/branches/release26-maint/Python/getcopyright.c (original) +++ python/branches/release26-maint/Python/getcopyright.c Sat May 7 00:30:55 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/release26-maint/README ============================================================================== --- python/branches/release26-maint/README (original) +++ python/branches/release26-maint/README Sat May 7 00:30:55 2011 @@ -1,7 +1,7 @@ -This is Python version 2.6.6 -============================ +This is Python version 2.6.7rc1 +=============================== -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 May 7 00:31:34 2011 From: python-checkins at python.org (barry.warsaw) Date: Sat, 7 May 2011 00:31:34 +0200 (CEST) Subject: [Python-checkins] r88830 - python/tags/r267rc1 Message-ID: <3QR7BG3ZJkz7LjR@mail.python.org> Author: barry.warsaw Date: Sat May 7 00:31:34 2011 New Revision: 88830 Log: Tagging 2.6.7rc1 Added: python/tags/r267rc1/ - copied from r88829, /python/branches/release26-maint/ From python-checkins at python.org Sat May 7 04:27:22 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 07 May 2011 04:27:22 +0200 Subject: [Python-checkins] cpython (2.7): #11999: sync based on comparing mtimes, not mtime to system clock Message-ID: http://hg.python.org/cpython/rev/a0147a1f1776 changeset: 69881:a0147a1f1776 branch: 2.7 parent: 69872:051190230254 user: R David Murray date: Fri May 06 21:56:22 2011 -0400 summary: #11999: sync based on comparing mtimes, not mtime to system clock files: Lib/mailbox.py | 76 ++++++++++++++------------- Lib/test/test_mailbox.py | 29 +++++----- Misc/NEWS | 4 + 3 files changed, 58 insertions(+), 51 deletions(-) diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -234,19 +234,24 @@ def __init__(self, dirname, factory=rfc822.Message, create=True): """Initialize a Maildir instance.""" Mailbox.__init__(self, dirname, factory, create) + self._paths = { + 'tmp': os.path.join(self._path, 'tmp'), + 'new': os.path.join(self._path, 'new'), + 'cur': os.path.join(self._path, 'cur'), + } if not os.path.exists(self._path): if create: os.mkdir(self._path, 0700) - os.mkdir(os.path.join(self._path, 'tmp'), 0700) - os.mkdir(os.path.join(self._path, 'new'), 0700) - os.mkdir(os.path.join(self._path, 'cur'), 0700) + for path in self._paths.values(): + os.mkdir(path, 0o700) else: raise NoSuchMailboxError(self._path) self._toc = {} - self._last_read = None # Records last time we read cur/new - # NOTE: we manually invalidate _last_read each time we do any - # modifications ourselves, otherwise we might get tripped up by - # bogus mtime behaviour on some systems (see issue #6896). + self._toc_mtimes = {} + for subdir in ('cur', 'new'): + self._toc_mtimes[subdir] = os.path.getmtime(self._paths[subdir]) + self._last_read = time.time() # Records last time we read cur/new + self._skewfactor = 0.1 # Adjust if os/fs clocks are skewing def add(self, message): """Add message and return assigned key.""" @@ -283,15 +288,11 @@ raise if isinstance(message, MaildirMessage): os.utime(dest, (os.path.getatime(dest), message.get_date())) - # Invalidate cached toc - self._last_read = None return uniq def remove(self, key): """Remove the keyed message; raise KeyError if it doesn't exist.""" os.remove(os.path.join(self._path, self._lookup(key))) - # Invalidate cached toc (only on success) - self._last_read = None def discard(self, key): """If the keyed message exists, remove it.""" @@ -326,8 +327,6 @@ if isinstance(message, MaildirMessage): os.utime(new_path, (os.path.getatime(new_path), message.get_date())) - # Invalidate cached toc - self._last_read = None def get_message(self, key): """Return a Message representation or raise a KeyError.""" @@ -383,8 +382,8 @@ def flush(self): """Write any pending changes to disk.""" # Maildir changes are always written immediately, so there's nothing - # to do except invalidate our cached toc. - self._last_read = None + # to do. + pass def lock(self): """Lock the mailbox.""" @@ -482,36 +481,39 @@ def _refresh(self): """Update table of contents mapping.""" - if self._last_read is not None: - for subdir in ('new', 'cur'): - mtime = os.path.getmtime(os.path.join(self._path, subdir)) - if mtime > self._last_read: - break - else: + # If it has been less than two seconds since the last _refresh() call, + # we have to unconditionally re-read the mailbox just in case it has + # been modified, because os.path.mtime() has a 2 sec resolution in the + # most common worst case (FAT) and a 1 sec resolution typically. This + # results in a few unnecessary re-reads when _refresh() is called + # multiple times in that interval, but once the clock ticks over, we + # will only re-read as needed. Because the filesystem might be being + # served by an independent system with its own clock, we record and + # compare with the mtimes from the filesystem. Because the other + # system's clock might be skewing relative to our clock, we add an + # extra delta to our wait. The default is one tenth second, but is an + # instance variable and so can be adjusted if dealing with a + # particularly skewed or irregular system. + if time.time() - self._last_read > 2 + self._skewfactor: + refresh = False + for subdir in self._toc_mtimes: + mtime = os.path.getmtime(self._paths[subdir]) + if mtime > self._toc_mtimes[subdir]: + refresh = True + self._toc_mtimes[subdir] = mtime + if not refresh: return - - # We record the current time - 1sec so that, if _refresh() is called - # again in the same second, we will always re-read the mailbox - # just in case it's been modified. (os.path.mtime() only has - # 1sec resolution.) This results in a few unnecessary re-reads - # when _refresh() is called multiple times in the same second, - # but once the clock ticks over, we will only re-read as needed. - now = time.time() - 1 - + # Refresh toc self._toc = {} - def update_dir (subdir): - path = os.path.join(self._path, subdir) + for subdir in self._toc_mtimes: + path = self._paths[subdir] for entry in os.listdir(path): p = os.path.join(path, entry) if os.path.isdir(p): continue uniq = entry.split(self.colon)[0] self._toc[uniq] = os.path.join(subdir, entry) - - update_dir('new') - update_dir('cur') - - self._last_read = now + self._last_read = time.time() def _lookup(self, key): """Use TOC to return subpath for given key, or raise a KeyError.""" diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -751,27 +751,28 @@ self.assertFalse((perms & 0111)) # Execute bits should all be off. def test_reread(self): - # Wait for 2 seconds - time.sleep(2) - # Initially, the mailbox has not been read and the time is null. - assert getattr(self._box, '_last_read', None) is None + # Put the last modified times more than two seconds into the past + # (because mtime may have only a two second granularity). + for subdir in ('cur', 'new'): + os.utime(os.path.join(self._box._path, subdir), + (time.time()-5,)*2) - # Refresh mailbox; the times should now be set to something. - self._box._refresh() - assert getattr(self._box, '_last_read', None) is not None + # Because mtime has a two second granularity in worst case (FAT), a + # refresh is done unconditionally if called for within + # two-second-plus-a-bit of the last one, just in case the mbox has + # changed; so now we have to wait for that interval to expire. + time.sleep(2.01 + self._box._skewfactor) - # Try calling _refresh() again; the modification times shouldn't have - # changed, so the mailbox should not be re-reading. Re-reading causes - # the ._toc attribute to be assigned a new dictionary object, so - # we'll check that the ._toc attribute isn't a different object. + # Re-reading causes the ._toc attribute to be assigned a new dictionary + # object, so we'll check that the ._toc attribute isn't a different + # object. orig_toc = self._box._toc def refreshed(): return self._box._toc is not orig_toc - time.sleep(1) # Wait 1sec to ensure time.time()'s value changes self._box._refresh() - assert not refreshed() + self.assertFalse(refreshed()) # Now, write something into cur and remove it. This changes # the mtime and should cause a re-read. @@ -780,7 +781,7 @@ f.close() os.unlink(filename) self._box._refresh() - assert refreshed() + self.assertTrue(refreshed()) class _TestMboxMMDF(TestMailbox): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -77,6 +77,10 @@ Library ------- +- Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to + detect mtime changes by comparing to the system clock instead of to the + previous value of the mtime. + - Issue #10684: shutil.move used to delete a folder on case insensitive filesystems when the source and destination name where the same except for the case. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 04:27:25 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 07 May 2011 04:27:25 +0200 Subject: [Python-checkins] cpython (3.1): #11999: sync based on comparing mtimes, not mtime to system clock Message-ID: http://hg.python.org/cpython/rev/252451fef13f changeset: 69882:252451fef13f branch: 3.1 parent: 69869:26da299ca88e user: R David Murray date: Fri May 06 22:07:19 2011 -0400 summary: #11999: sync based on comparing mtimes, not mtime to system clock files: Lib/mailbox.py | 76 ++++++++++++++------------- Lib/test/test_mailbox.py | 23 +++---- Misc/NEWS | 4 + 3 files changed, 54 insertions(+), 49 deletions(-) diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -224,19 +224,24 @@ def __init__(self, dirname, factory=None, create=True): """Initialize a Maildir instance.""" Mailbox.__init__(self, dirname, factory, create) + self._paths = { + 'tmp': os.path.join(self._path, 'tmp'), + 'new': os.path.join(self._path, 'new'), + 'cur': os.path.join(self._path, 'cur'), + } if not os.path.exists(self._path): if create: os.mkdir(self._path, 0o700) - os.mkdir(os.path.join(self._path, 'tmp'), 0o700) - os.mkdir(os.path.join(self._path, 'new'), 0o700) - os.mkdir(os.path.join(self._path, 'cur'), 0o700) + for path in self._paths.values(): + os.mkdir(path, 0o700) else: raise NoSuchMailboxError(self._path) self._toc = {} - self._last_read = None # Records last time we read cur/new - # NOTE: we manually invalidate _last_read each time we do any - # modifications ourselves, otherwise we might get tripped up by - # bogus mtime behaviour on some systems (see issue #6896). + self._toc_mtimes = {} + for subdir in ('cur', 'new'): + self._toc_mtimes[subdir] = os.path.getmtime(self._paths[subdir]) + self._last_read = time.time() # Records last time we read cur/new + self._skewfactor = 0.1 # Adjust if os/fs clocks are skewing def add(self, message): """Add message and return assigned key.""" @@ -270,15 +275,11 @@ raise if isinstance(message, MaildirMessage): os.utime(dest, (os.path.getatime(dest), message.get_date())) - # Invalidate cached toc - self._last_read = None return uniq def remove(self, key): """Remove the keyed message; raise KeyError if it doesn't exist.""" os.remove(os.path.join(self._path, self._lookup(key))) - # Invalidate cached toc (only on success) - self._last_read = None def discard(self, key): """If the keyed message exists, remove it.""" @@ -313,8 +314,6 @@ if isinstance(message, MaildirMessage): os.utime(new_path, (os.path.getatime(new_path), message.get_date())) - # Invalidate cached toc - self._last_read = None def get_message(self, key): """Return a Message representation or raise a KeyError.""" @@ -370,8 +369,8 @@ def flush(self): """Write any pending changes to disk.""" # Maildir changes are always written immediately, so there's nothing - # to do except invalidate our cached toc. - self._last_read = None + # to do. + pass def lock(self): """Lock the mailbox.""" @@ -469,34 +468,39 @@ def _refresh(self): """Update table of contents mapping.""" - new_mtime = os.path.getmtime(os.path.join(self._path, 'new')) - cur_mtime = os.path.getmtime(os.path.join(self._path, 'cur')) - - if (self._last_read is not None and - new_mtime <= self._last_read and cur_mtime <= self._last_read): - return - + # If it has been less than two seconds since the last _refresh() call, + # we have to unconditionally re-read the mailbox just in case it has + # been modified, because os.path.mtime() has a 2 sec resolution in the + # most common worst case (FAT) and a 1 sec resolution typically. This + # results in a few unnecessary re-reads when _refresh() is called + # multiple times in that interval, but once the clock ticks over, we + # will only re-read as needed. Because the filesystem might be being + # served by an independent system with its own clock, we record and + # compare with the mtimes from the filesystem. Because the other + # system's clock might be skewing relative to our clock, we add an + # extra delta to our wait. The default is one tenth second, but is an + # instance variable and so can be adjusted if dealing with a + # particularly skewed or irregular system. + if time.time() - self._last_read > 2 + self._skewfactor: + refresh = False + for subdir in self._toc_mtimes: + mtime = os.path.getmtime(self._paths[subdir]) + if mtime > self._toc_mtimes[subdir]: + refresh = True + self._toc_mtimes[subdir] = mtime + if not refresh: + return + # Refresh toc self._toc = {} - def update_dir (subdir): - path = os.path.join(self._path, subdir) + for subdir in self._toc_mtimes: + path = self._paths[subdir] for entry in os.listdir(path): p = os.path.join(path, entry) if os.path.isdir(p): continue uniq = entry.split(self.colon)[0] self._toc[uniq] = os.path.join(subdir, entry) - - update_dir('new') - update_dir('cur') - - # We record the current time - 1sec so that, if _refresh() is called - # again in the same second, we will always re-read the mailbox - # just in case it's been modified. (os.path.mtime() only has - # 1sec resolution.) This results in a few unnecessary re-reads - # when _refresh() is called multiple times in the same second, - # but once the clock ticks over, we will only re-read as needed. - now = int(time.time() - 1) - self._last_read = time.time() - 1 + self._last_read = time.time() def _lookup(self, key): """Use TOC to return subpath for given key, or raise a KeyError.""" diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -742,21 +742,18 @@ def test_reread(self): - # Initially, the mailbox has not been read and the time is null. - assert getattr(self._box, '_last_read', None) is None - - # Refresh mailbox; the times should now be set to something. - self._box._refresh() - assert getattr(self._box, '_last_read', None) is not None - - # Put the last modified times more than one second into the past - # (because mtime has a one second granularity, a refresh is done - # unconditionally if called for within the same second, just in case - # the mbox has changed). + # Put the last modified times more than two seconds into the past + # (because mtime may have a two second granularity) for subdir in ('cur', 'new'): os.utime(os.path.join(self._box._path, subdir), (time.time()-5,)*2) + # Because mtime has a two second granularity in worst case (FAT), a + # refresh is done unconditionally if called for within + # two-second-plus-a-bit of the last one, just in case the mbox has + # changed; so now we have to wait for that interval to expire. + time.sleep(2.01 + self._box._skewfactor) + # Re-reading causes the ._toc attribute to be assigned a new dictionary # object, so we'll check that the ._toc attribute isn't a different # object. @@ -765,7 +762,7 @@ return self._box._toc is not orig_toc self._box._refresh() - assert not refreshed() + self.assertFalse(refreshed()) # Now, write something into cur and remove it. This changes # the mtime and should cause a re-read. @@ -774,7 +771,7 @@ f.close() os.unlink(filename) self._box._refresh() - assert refreshed() + self.assertTrue(refreshed()) class _TestMboxMMDF(TestMailbox): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,10 @@ Library ------- +- Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to + detect mtime changes by comparing to the system clock instead of to the + previous value of the mtime. + - Issue #10684: shutil.move used to delete a folder on case insensitive filesystems when the source and destination name where the same except for the case. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 04:27:28 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 07 May 2011 04:27:28 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11999: sync based on comparing mtimes, not mtime to system clock Message-ID: http://hg.python.org/cpython/rev/6907c43d1ee7 changeset: 69883:6907c43d1ee7 branch: 3.2 parent: 69876:011e4bb8b933 parent: 69882:252451fef13f user: R David Murray date: Fri May 06 22:20:34 2011 -0400 summary: #11999: sync based on comparing mtimes, not mtime to system clock files: Lib/mailbox.py | 76 ++++++++++++++------------- Lib/test/test_mailbox.py | 23 +++---- Misc/NEWS | 4 + 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -258,19 +258,24 @@ def __init__(self, dirname, factory=None, create=True): """Initialize a Maildir instance.""" Mailbox.__init__(self, dirname, factory, create) + self._paths = { + 'tmp': os.path.join(self._path, 'tmp'), + 'new': os.path.join(self._path, 'new'), + 'cur': os.path.join(self._path, 'cur'), + } if not os.path.exists(self._path): if create: os.mkdir(self._path, 0o700) - os.mkdir(os.path.join(self._path, 'tmp'), 0o700) - os.mkdir(os.path.join(self._path, 'new'), 0o700) - os.mkdir(os.path.join(self._path, 'cur'), 0o700) + for path in self._paths.values(): + os.mkdir(path, 0o700) else: raise NoSuchMailboxError(self._path) self._toc = {} - self._last_read = None # Records last time we read cur/new - # NOTE: we manually invalidate _last_read each time we do any - # modifications ourselves, otherwise we might get tripped up by - # bogus mtime behaviour on some systems (see issue #6896). + self._toc_mtimes = {} + for subdir in ('cur', 'new'): + self._toc_mtimes[subdir] = os.path.getmtime(self._paths[subdir]) + self._last_read = time.time() # Records last time we read cur/new + self._skewfactor = 0.1 # Adjust if os/fs clocks are skewing def add(self, message): """Add message and return assigned key.""" @@ -307,15 +312,11 @@ raise if isinstance(message, MaildirMessage): os.utime(dest, (os.path.getatime(dest), message.get_date())) - # Invalidate cached toc - self._last_read = None return uniq def remove(self, key): """Remove the keyed message; raise KeyError if it doesn't exist.""" os.remove(os.path.join(self._path, self._lookup(key))) - # Invalidate cached toc (only on success) - self._last_read = None def discard(self, key): """If the keyed message exists, remove it.""" @@ -350,8 +351,6 @@ if isinstance(message, MaildirMessage): os.utime(new_path, (os.path.getatime(new_path), message.get_date())) - # Invalidate cached toc - self._last_read = None def get_message(self, key): """Return a Message representation or raise a KeyError.""" @@ -407,8 +406,8 @@ def flush(self): """Write any pending changes to disk.""" # Maildir changes are always written immediately, so there's nothing - # to do except invalidate our cached toc. - self._last_read = None + # to do. + pass def lock(self): """Lock the mailbox.""" @@ -506,36 +505,39 @@ def _refresh(self): """Update table of contents mapping.""" - if self._last_read is not None: - for subdir in ('new', 'cur'): - mtime = os.path.getmtime(os.path.join(self._path, subdir)) - if mtime > self._last_read: - break - else: + # If it has been less than two seconds since the last _refresh() call, + # we have to unconditionally re-read the mailbox just in case it has + # been modified, because os.path.mtime() has a 2 sec resolution in the + # most common worst case (FAT) and a 1 sec resolution typically. This + # results in a few unnecessary re-reads when _refresh() is called + # multiple times in that interval, but once the clock ticks over, we + # will only re-read as needed. Because the filesystem might be being + # served by an independent system with its own clock, we record and + # compare with the mtimes from the filesystem. Because the other + # system's clock might be skewing relative to our clock, we add an + # extra delta to our wait. The default is one tenth second, but is an + # instance variable and so can be adjusted if dealing with a + # particularly skewed or irregular system. + if time.time() - self._last_read > 2 + self._skewfactor: + refresh = False + for subdir in self._toc_mtimes: + mtime = os.path.getmtime(self._paths[subdir]) + if mtime > self._toc_mtimes[subdir]: + refresh = True + self._toc_mtimes[subdir] = mtime + if not refresh: return - - # We record the current time - 1sec so that, if _refresh() is called - # again in the same second, we will always re-read the mailbox - # just in case it's been modified. (os.path.mtime() only has - # 1sec resolution.) This results in a few unnecessary re-reads - # when _refresh() is called multiple times in the same second, - # but once the clock ticks over, we will only re-read as needed. - now = time.time() - 1 - + # Refresh toc self._toc = {} - def update_dir (subdir): - path = os.path.join(self._path, subdir) + for subdir in self._toc_mtimes: + path = self._paths[subdir] for entry in os.listdir(path): p = os.path.join(path, entry) if os.path.isdir(p): continue uniq = entry.split(self.colon)[0] self._toc[uniq] = os.path.join(subdir, entry) - - update_dir('new') - update_dir('cur') - - self._last_read = now + self._last_read = time.time() def _lookup(self, key): """Use TOC to return subpath for given key, or raise a KeyError.""" diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -870,21 +870,18 @@ def test_reread(self): - # Initially, the mailbox has not been read and the time is null. - assert getattr(self._box, '_last_read', None) is None - - # Refresh mailbox; the times should now be set to something. - self._box._refresh() - assert getattr(self._box, '_last_read', None) is not None - - # Put the last modified times more than one second into the past - # (because mtime has a one second granularity, a refresh is done - # unconditionally if called for within the same second, just in case - # the mbox has changed). + # Put the last modified times more than two seconds into the past + # (because mtime may have a two second granularity) for subdir in ('cur', 'new'): os.utime(os.path.join(self._box._path, subdir), (time.time()-5,)*2) + # Because mtime has a two second granularity in worst case (FAT), a + # refresh is done unconditionally if called for within + # two-second-plus-a-bit of the last one, just in case the mbox has + # changed; so now we have to wait for that interval to expire. + time.sleep(2.01 + self._box._skewfactor) + # Re-reading causes the ._toc attribute to be assigned a new dictionary # object, so we'll check that the ._toc attribute isn't a different # object. @@ -893,7 +890,7 @@ return self._box._toc is not orig_toc self._box._refresh() - assert not refreshed() + self.assertFalse(refreshed()) # Now, write something into cur and remove it. This changes # the mtime and should cause a re-read. @@ -902,7 +899,7 @@ f.close() os.unlink(filename) self._box._refresh() - assert refreshed() + self.assertTrue(refreshed()) class _TestMboxMMDF(TestMailbox): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,10 @@ Library ------- +- Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to + detect mtime changes by comparing to the system clock instead of to the + previous value of the mtime. + - ntpath.samefile failed to notice that "a.txt" and "A.TXT" refer to the same file on Windows XP. As noticed in issue #10684. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 04:27:30 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 07 May 2011 04:27:30 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11999: sync based on comparing mtimes, not mtime to system clock Message-ID: http://hg.python.org/cpython/rev/214a34b26e1b changeset: 69884:214a34b26e1b parent: 69880:5661480f7763 parent: 69883:6907c43d1ee7 user: R David Murray date: Fri May 06 22:26:27 2011 -0400 summary: #11999: sync based on comparing mtimes, not mtime to system clock files: Lib/mailbox.py | 76 ++++++++++++++------------- Lib/test/test_mailbox.py | 23 +++---- Misc/NEWS | 4 + 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -258,19 +258,24 @@ def __init__(self, dirname, factory=None, create=True): """Initialize a Maildir instance.""" Mailbox.__init__(self, dirname, factory, create) + self._paths = { + 'tmp': os.path.join(self._path, 'tmp'), + 'new': os.path.join(self._path, 'new'), + 'cur': os.path.join(self._path, 'cur'), + } if not os.path.exists(self._path): if create: os.mkdir(self._path, 0o700) - os.mkdir(os.path.join(self._path, 'tmp'), 0o700) - os.mkdir(os.path.join(self._path, 'new'), 0o700) - os.mkdir(os.path.join(self._path, 'cur'), 0o700) + for path in self._paths.values(): + os.mkdir(path, 0o700) else: raise NoSuchMailboxError(self._path) self._toc = {} - self._last_read = None # Records last time we read cur/new - # NOTE: we manually invalidate _last_read each time we do any - # modifications ourselves, otherwise we might get tripped up by - # bogus mtime behaviour on some systems (see issue #6896). + self._toc_mtimes = {} + for subdir in ('cur', 'new'): + self._toc_mtimes[subdir] = os.path.getmtime(self._paths[subdir]) + self._last_read = time.time() # Records last time we read cur/new + self._skewfactor = 0.1 # Adjust if os/fs clocks are skewing def add(self, message): """Add message and return assigned key.""" @@ -307,15 +312,11 @@ raise if isinstance(message, MaildirMessage): os.utime(dest, (os.path.getatime(dest), message.get_date())) - # Invalidate cached toc - self._last_read = None return uniq def remove(self, key): """Remove the keyed message; raise KeyError if it doesn't exist.""" os.remove(os.path.join(self._path, self._lookup(key))) - # Invalidate cached toc (only on success) - self._last_read = None def discard(self, key): """If the keyed message exists, remove it.""" @@ -350,8 +351,6 @@ if isinstance(message, MaildirMessage): os.utime(new_path, (os.path.getatime(new_path), message.get_date())) - # Invalidate cached toc - self._last_read = None def get_message(self, key): """Return a Message representation or raise a KeyError.""" @@ -407,8 +406,8 @@ def flush(self): """Write any pending changes to disk.""" # Maildir changes are always written immediately, so there's nothing - # to do except invalidate our cached toc. - self._last_read = None + # to do. + pass def lock(self): """Lock the mailbox.""" @@ -506,36 +505,39 @@ def _refresh(self): """Update table of contents mapping.""" - if self._last_read is not None: - for subdir in ('new', 'cur'): - mtime = os.path.getmtime(os.path.join(self._path, subdir)) - if mtime > self._last_read: - break - else: + # If it has been less than two seconds since the last _refresh() call, + # we have to unconditionally re-read the mailbox just in case it has + # been modified, because os.path.mtime() has a 2 sec resolution in the + # most common worst case (FAT) and a 1 sec resolution typically. This + # results in a few unnecessary re-reads when _refresh() is called + # multiple times in that interval, but once the clock ticks over, we + # will only re-read as needed. Because the filesystem might be being + # served by an independent system with its own clock, we record and + # compare with the mtimes from the filesystem. Because the other + # system's clock might be skewing relative to our clock, we add an + # extra delta to our wait. The default is one tenth second, but is an + # instance variable and so can be adjusted if dealing with a + # particularly skewed or irregular system. + if time.time() - self._last_read > 2 + self._skewfactor: + refresh = False + for subdir in self._toc_mtimes: + mtime = os.path.getmtime(self._paths[subdir]) + if mtime > self._toc_mtimes[subdir]: + refresh = True + self._toc_mtimes[subdir] = mtime + if not refresh: return - - # We record the current time - 1sec so that, if _refresh() is called - # again in the same second, we will always re-read the mailbox - # just in case it's been modified. (os.path.mtime() only has - # 1sec resolution.) This results in a few unnecessary re-reads - # when _refresh() is called multiple times in the same second, - # but once the clock ticks over, we will only re-read as needed. - now = time.time() - 1 - + # Refresh toc self._toc = {} - def update_dir (subdir): - path = os.path.join(self._path, subdir) + for subdir in self._toc_mtimes: + path = self._paths[subdir] for entry in os.listdir(path): p = os.path.join(path, entry) if os.path.isdir(p): continue uniq = entry.split(self.colon)[0] self._toc[uniq] = os.path.join(subdir, entry) - - update_dir('new') - update_dir('cur') - - self._last_read = now + self._last_read = time.time() def _lookup(self, key): """Use TOC to return subpath for given key, or raise a KeyError.""" diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -870,21 +870,18 @@ def test_reread(self): - # Initially, the mailbox has not been read and the time is null. - assert getattr(self._box, '_last_read', None) is None - - # Refresh mailbox; the times should now be set to something. - self._box._refresh() - assert getattr(self._box, '_last_read', None) is not None - - # Put the last modified times more than one second into the past - # (because mtime has a one second granularity, a refresh is done - # unconditionally if called for within the same second, just in case - # the mbox has changed). + # Put the last modified times more than two seconds into the past + # (because mtime may have a two second granularity) for subdir in ('cur', 'new'): os.utime(os.path.join(self._box._path, subdir), (time.time()-5,)*2) + # Because mtime has a two second granularity in worst case (FAT), a + # refresh is done unconditionally if called for within + # two-second-plus-a-bit of the last one, just in case the mbox has + # changed; so now we have to wait for that interval to expire. + time.sleep(2.01 + self._box._skewfactor) + # Re-reading causes the ._toc attribute to be assigned a new dictionary # object, so we'll check that the ._toc attribute isn't a different # object. @@ -893,7 +890,7 @@ return self._box._toc is not orig_toc self._box._refresh() - assert not refreshed() + self.assertFalse(refreshed()) # Now, write something into cur and remove it. This changes # the mtime and should cause a re-read. @@ -902,7 +899,7 @@ f.close() os.unlink(filename) self._box._refresh() - assert refreshed() + self.assertTrue(refreshed()) class _TestMboxMMDF(TestMailbox): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,10 @@ Library ------- +- Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to + detect mtime changes by comparing to the system clock instead of to the + previous value of the mtime. + - Issue #11072: added MLSD command (RFC-3659) support to ftplib. - Issue #8808: The IMAP4_SSL constructor now allows passing an SSLContext -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat May 7 05:03:24 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 07 May 2011 05:03:24 +0200 Subject: [Python-checkins] Daily reference leaks (5661480f7763): sum=0 Message-ID: results for 5661480f7763 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogzoIA_C', '-x'] From python-checkins at python.org Sat May 7 09:59:11 2011 From: python-checkins at python.org (ronald.oussoren) Date: Sat, 07 May 2011 09:59:11 +0200 Subject: [Python-checkins] cpython: Closes Issue 11916: Add a number of MacOSX specific definitions to the errno Message-ID: http://hg.python.org/cpython/rev/2f978b4c02ad changeset: 69885:2f978b4c02ad user: Ronald Oussoren date: Sat May 07 09:59:03 2011 +0200 summary: Closes Issue 11916: Add a number of MacOSX specific definitions to the errno module. Patch by Pierre Carrier. files: Misc/ACKS | 1 + Misc/NEWS | 3 + Modules/errnomodule.c | 55 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 0 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -989,3 +989,4 @@ Tarek Ziad? Peter ?strand Torsten Becker +Pierre Carrier diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,9 @@ Library ------- +- Issue 11916: Add a number of MacOSX specific definitions to the errno module. + Patch by Pierre Carrier. + - Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to detect mtime changes by comparing to the system clock instead of to the previous value of the mtime. diff --git a/Modules/errnomodule.c b/Modules/errnomodule.c --- a/Modules/errnomodule.c +++ b/Modules/errnomodule.c @@ -84,6 +84,8 @@ * The names and comments are borrowed from linux/include/errno.h, * which should be pretty all-inclusive. However, the Solaris specific * names and comments are borrowed from sys/errno.h in Solaris. + * MacOSX specific names and comments are borrowed from sys/errno.h in + * MacOSX. */ #ifdef ENODEV @@ -848,6 +850,59 @@ inscode(d, ds, de, "ENOTACTIVE", ENOTACTIVE, "Facility is not active"); #endif + /* MacOSX specific errnos */ +#ifdef EAUTH + inscode(d, ds, de, "EAUTH", EAUTH, "Authentication error"); +#endif +#ifdef EBADARCH + inscode(d, ds, de, "EBADARCH", EBADARCH, "Bad CPU type in executable"); +#endif +#ifdef EBADEXEC + inscode(d, ds, de, "EBADEXEC", EBADEXEC, "Bad executable (or shared library)"); +#endif +#ifdef EBADMACHO + inscode(d, ds, de, "EBADMACHO", EBADMACHO, "Malformed Mach-o file"); +#endif +#ifdef EBADRPC + inscode(d, ds, de, "EBADRPC", EBADRPC, "RPC struct is bad"); +#endif +#ifdef EDEVERR + inscode(d, ds, de, "EDEVERR", EDEVERR, "Device error"); +#endif +#ifdef EFTYPE + inscode(d, ds, de, "EFTYPE", EFTYPE, "Inappropriate file type or format"); +#endif +#ifdef ENEEDAUTH + inscode(d, ds, de, "ENEEDAUTH", ENEEDAUTH, "Need authenticator"); +#endif +#ifdef ENOATTR + inscode(d, ds, de, "ENOATTR", ENOATTR, "Attribute not found"); +#endif +#ifdef ENOPOLICY + inscode(d, ds, de, "ENOPOLICY", ENOPOLICY, "Policy not found"); +#endif +#ifdef EPROCLIM + inscode(d, ds, de, "EPROCLIM", EPROCLIM, "Too many processes"); +#endif +#ifdef EPROCUNAVAIL + inscode(d, ds, de, "EPROCUNAVAIL", EPROCUNAVAIL, "Bad procedure for program"); +#endif +#ifdef EPROGMISMATCH + inscode(d, ds, de, "EPROGMISMATCH", EPROGMISMATCH, "Program version wrong"); +#endif +#ifdef EPROGUNAVAIL + inscode(d, ds, de, "EPROGUNAVAIL", EPROGUNAVAIL, "RPC prog. not avail"); +#endif +#ifdef EPWROFF + inscode(d, ds, de, "EPWROFF", EPWROFF, "Device power is off"); +#endif +#ifdef ERPCMISMATCH + inscode(d, ds, de, "ERPCMISMATCH", ERPCMISMATCH, "RPC version wrong"); +#endif +#ifdef ESHLIBVERS + inscode(d, ds, de, "ESHLIBVERS", ESHLIBVERS, "Shared library version mismatch"); +#endif + Py_DECREF(de); return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 11:42:42 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 11:42:42 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11277: Remove useless test from test_zlib. Message-ID: http://hg.python.org/cpython/rev/201dcfc56e86 changeset: 69886:201dcfc56e86 branch: 2.7 parent: 69881:a0147a1f1776 user: Nadeem Vawda date: Sat May 07 11:28:03 2011 +0200 summary: Issue #11277: Remove useless test from test_zlib. files: Lib/test/test_zlib.py | 42 ------------------------------- 1 files changed, 0 insertions(+), 42 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -72,47 +72,6 @@ zlib.crc32('spam', (2**31))) -# Issue #11277 - check that inputs of 2 GB (or 1 GB on 32 bits system) are -# handled correctly. Be aware of issues #1202. We cannot test a buffer of 4 GB -# or more (#8650, #8651 and #10276), because the zlib stores the buffer size -# into an int. -class ChecksumBigBufferTestCase(unittest.TestCase): - if sys.maxsize > _4G: - # (64 bits system) crc32() and adler32() stores the buffer size into an - # int, the maximum filesize is INT_MAX (0x7FFFFFFF) - filesize = 0x7FFFFFFF - else: - # (32 bits system) On a 32 bits OS, a process cannot usually address - # more than 2 GB, so test only 1 GB - filesize = _1G - - @unittest.skipUnless(mmap, "mmap() is not available.") - def test_big_buffer(self): - if sys.platform[:3] == 'win' or sys.platform == 'darwin': - requires('largefile', - 'test requires %s bytes and a long time to run' % - str(self.filesize)) - try: - with open(TESTFN, "wb+") as f: - f.seek(self.filesize-4) - f.write("asdf") - f.flush() - m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) - try: - if sys.maxsize > _4G: - self.assertEqual(zlib.crc32(m), 0x709418e7) - self.assertEqual(zlib.adler32(m), -2072837729) - else: - self.assertEqual(zlib.crc32(m), 722071057) - self.assertEqual(zlib.adler32(m), -1002962529) - finally: - m.close() - except (IOError, OverflowError): - raise unittest.SkipTest("filesystem doesn't have largefile support") - finally: - unlink(TESTFN) - - class ExceptionTestCase(unittest.TestCase): # make sure we generate some expected errors def test_badlevel(self): @@ -595,7 +554,6 @@ def test_main(): run_unittest( ChecksumTestCase, - ChecksumBigBufferTestCase, ExceptionTestCase, CompressTestCase, CompressObjectTestCase -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 12:21:39 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 07 May 2011 12:21:39 +0200 Subject: [Python-checkins] cpython: faulthandler: save/restore errno in the two signal handlers Message-ID: http://hg.python.org/cpython/rev/bae531098e68 changeset: 69887:bae531098e68 parent: 69885:2f978b4c02ad user: Victor Stinner date: Sat May 07 12:20:11 2011 +0200 summary: faulthandler: save/restore errno in the two signal handlers files: Modules/faulthandler.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -238,6 +238,7 @@ unsigned int i; fault_handler_t *handler = NULL; PyThreadState *tstate; + int save_errno = errno; if (!fatal_error.enabled) return; @@ -285,6 +286,7 @@ _Py_DumpTraceback(fd, tstate); } + errno = save_errno; #ifdef MS_WINDOWS if (signum == SIGSEGV) { /* don't call explictly the previous handler for SIGSEGV in this signal @@ -593,6 +595,7 @@ { user_signal_t *user; PyThreadState *tstate; + int save_errno = errno; user = &user_signals[signum]; if (!user->enabled) @@ -614,6 +617,7 @@ return; _Py_DumpTraceback(user->fd, tstate); } + errno = save_errno; } static int -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 12:43:10 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 07 May 2011 12:43:10 +0200 Subject: [Python-checkins] cpython: faulthandler: dump all threads by default Message-ID: http://hg.python.org/cpython/rev/8752a81ada2d changeset: 69888:8752a81ada2d user: Victor Stinner date: Sat May 07 12:43:00 2011 +0200 summary: faulthandler: dump all threads by default * Set the default value of all_threads arguments to True * Py_FatalError() dumps all threads, instead of only the current thread Dump only the current thread is not reliable. In some cases, Python is unable to retrieve the state of the current thread and so is unable to dump the traceback. faulthandler keeps a reference to the interpreter and so is always able to dump the traceback of all threads. files: Doc/library/faulthandler.rst | 21 +++++++++++---------- Lib/test/test_faulthandler.py | 12 ++++++------ Modules/faulthandler.c | 12 ++++++------ Python/pythonrun.c | 2 +- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Doc/library/faulthandler.rst b/Doc/library/faulthandler.rst --- a/Doc/library/faulthandler.rst +++ b/Doc/library/faulthandler.rst @@ -36,21 +36,22 @@ Dump the traceback ------------------ -.. function:: dump_traceback(file=sys.stderr, all_threads=False) +.. function:: dump_traceback(file=sys.stderr, all_threads=True) - Dump the traceback of the current thread, or of all threads if *all_threads* - is ``True``, into *file*. + Dump the traceback of all threads, or of the current thread if *all_threads* + is ``False``, into *file*. Fault handler state ------------------- -.. function:: enable(file=sys.stderr, all_threads=False) +.. function:: enable(file=sys.stderr, all_threads=True) Enable the fault handler: install handlers for :const:`SIGSEGV`, :const:`SIGFPE`, :const:`SIGABRT`, :const:`SIGBUS` and :const:`SIGILL` - signals to dump the Python traceback. It dumps the traceback of the current - thread, or all threads if *all_threads* is ``True``, into *file*. + signals to dump the Python traceback. It dumps the traceback of the all + threads, or of the current thread if *all_threads* is ``False``, into + *file*. .. function:: disable() @@ -86,11 +87,11 @@ Dump the traceback on a user signal ----------------------------------- -.. function:: register(signum, file=sys.stderr, all_threads=False) +.. function:: register(signum, file=sys.stderr, all_threads=True) Register a user signal: install a handler for the *signum* signal to dump - the traceback of the current thread, or of all threads if *all_threads* is - ``True``, into *file*. + the traceback of all threads, or of the current thread if *all_threads* is + ``False``, into *file*. Not available on Windows. @@ -123,7 +124,7 @@ >>> ctypes.string_at(0) Fatal Python error: Segmentation fault - Traceback (most recent call first): + Current thread 0x00007fb899f39700: File "/home/python/cpython/Lib/ctypes/__init__.py", line 486 in string_at File "", line 1 in Segmentation fault diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -75,7 +75,7 @@ return output.splitlines(), exitcode def check_fatal_error(self, code, line_number, name_regex, - filename=None, all_threads=False, other_regex=None): + filename=None, all_threads=True, other_regex=None): """ Check that the fault handler for fatal errors is enabled and check the traceback from the child process output. @@ -204,15 +204,15 @@ '(?:Segmentation fault|Bus error)', filename=filename) - def test_enable_threads(self): + def test_enable_single_thread(self): self.check_fatal_error(""" import faulthandler -faulthandler.enable(all_threads=True) +faulthandler.enable(all_threads=False) faulthandler._read_null() """.strip(), 3, '(?:Segmentation fault|Bus error)', - all_threads=True) + all_threads=False) def test_disable(self): code = """ @@ -252,9 +252,9 @@ def funcB(): if {has_filename}: with open({filename}, "wb") as fp: - faulthandler.dump_traceback(fp) + faulthandler.dump_traceback(fp, all_threads=False) else: - faulthandler.dump_traceback() + faulthandler.dump_traceback(all_threads=False) def funcA(): funcB() diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -186,7 +186,7 @@ { static char *kwlist[] = {"file", "all_threads", NULL}; PyObject *file = NULL; - int all_threads = 0; + int all_threads = 1; PyThreadState *tstate; const char *errmsg; int fd; @@ -306,7 +306,7 @@ { static char *kwlist[] = {"file", "all_threads", NULL}; PyObject *file = NULL; - int all_threads = 0; + int all_threads = 1; unsigned int i; fault_handler_t *handler; #ifdef HAVE_SIGACTION @@ -648,7 +648,7 @@ static char *kwlist[] = {"signum", "file", "all_threads", NULL}; int signum; PyObject *file = NULL; - int all_threads = 0; + int all_threads = 1; int fd; user_signal_t *user; _Py_sighandler_t previous; @@ -916,7 +916,7 @@ static PyMethodDef module_methods[] = { {"enable", (PyCFunction)faulthandler_enable, METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("enable(file=sys.stderr, all_threads=False): " + PyDoc_STR("enable(file=sys.stderr, all_threads=True): " "enable the fault handler")}, {"disable", (PyCFunction)faulthandler_disable_py, METH_NOARGS, PyDoc_STR("disable(): disable the fault handler")}, @@ -924,7 +924,7 @@ PyDoc_STR("is_enabled()->bool: check if the handler is enabled")}, {"dump_traceback", (PyCFunction)faulthandler_dump_traceback_py, METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("dump_traceback(file=sys.stderr, all_threads=False): " + PyDoc_STR("dump_traceback(file=sys.stderr, all_threads=True): " "dump the traceback of the current thread, or of all threads " "if all_threads is True, into file")}, #ifdef FAULTHANDLER_LATER @@ -943,7 +943,7 @@ #ifdef FAULTHANDLER_USER {"register", (PyCFunction)faulthandler_register, METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("register(signum, file=sys.stderr, all_threads=False): " + PyDoc_STR("register(signum, file=sys.stderr, all_threads=True): " "register an handler for the signal 'signum': dump the " "traceback of the current thread, or of all threads if " "all_threads is True, into file")}, diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -2144,7 +2144,7 @@ if (tstate != NULL) { fputc('\n', stderr); fflush(stderr); - _Py_DumpTraceback(fd, tstate); + _Py_DumpTracebackThreads(fd, tstate->interp, tstate); } _PyFaulthandler_Fini(); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 12:46:08 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 07 May 2011 12:46:08 +0200 Subject: [Python-checkins] cpython: _PyImport_LoadDynamicModule() encodes the module name explicitly to ASCII Message-ID: http://hg.python.org/cpython/rev/eb003c3d1770 changeset: 69889:eb003c3d1770 user: Victor Stinner date: Sat May 07 12:46:05 2011 +0200 summary: _PyImport_LoadDynamicModule() encodes the module name explicitly to ASCII The name must be encodable to ASCII because dynamic module must have a function called "PyInit_NAME", they are written in C, and the C language doesn't accept non-ASCII identifiers. files: Python/importdl.c | 40 +++++++++++++++++++++------------- 1 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Python/importdl.c b/Python/importdl.c --- a/Python/importdl.c +++ b/Python/importdl.c @@ -20,31 +20,36 @@ const char *pathname, FILE *fp); #endif -/* name should be ASCII only because the C language doesn't accept non-ASCII - identifiers, and dynamic modules are written in C. */ - PyObject * _PyImport_LoadDynamicModule(PyObject *name, PyObject *path, FILE *fp) { - PyObject *m; + PyObject *m = NULL; #ifndef MS_WINDOWS PyObject *pathbytes; #endif + PyObject *nameascii; char *namestr, *lastdot, *shortname, *packagecontext, *oldcontext; dl_funcptr p0; PyObject* (*p)(void); struct PyModuleDef *def; - namestr = _PyUnicode_AsString(name); - if (namestr == NULL) - return NULL; - m = _PyImport_FindExtensionObject(name, path); if (m != NULL) { Py_INCREF(m); return m; } + /* name must be encodable to ASCII because dynamic module must have a + function called "PyInit_NAME", they are written in C, and the C language + doesn't accept non-ASCII identifiers. */ + nameascii = PyUnicode_AsEncodedString(name, "ascii", NULL); + if (nameascii == NULL) + return NULL; + + namestr = PyBytes_AS_STRING(nameascii); + if (namestr == NULL) + goto error; + lastdot = strrchr(namestr, '.'); if (lastdot == NULL) { packagecontext = NULL; @@ -60,34 +65,33 @@ #else pathbytes = PyUnicode_EncodeFSDefault(path); if (pathbytes == NULL) - return NULL; + goto error; p0 = _PyImport_GetDynLoadFunc(shortname, PyBytes_AS_STRING(pathbytes), fp); Py_DECREF(pathbytes); #endif p = (PyObject*(*)(void))p0; if (PyErr_Occurred()) - return NULL; + goto error; if (p == NULL) { PyErr_Format(PyExc_ImportError, "dynamic module does not define init function" " (PyInit_%s)", shortname); - return NULL; + goto error; } oldcontext = _Py_PackageContext; _Py_PackageContext = packagecontext; m = (*p)(); _Py_PackageContext = oldcontext; if (m == NULL) - return NULL; + goto error; if (PyErr_Occurred()) { - Py_DECREF(m); PyErr_Format(PyExc_SystemError, "initialization of %s raised unreported exception", shortname); - return NULL; + goto error; } /* Remember pointer to module init function. */ @@ -101,12 +105,18 @@ Py_INCREF(path); if (_PyImport_FixupExtensionObject(m, name, path) < 0) - return NULL; + goto error; if (Py_VerboseFlag) PySys_FormatStderr( "import %U # dynamically loaded from %R\n", name, path); + Py_DECREF(nameascii); return m; + +error: + Py_DECREF(nameascii); + Py_XDECREF(m); + return NULL; } #endif /* HAVE_DYNAMIC_LOADING */ -- Repository URL: http://hg.python.org/cpython From nnorwitz at gmail.com Sat May 7 12:48:54 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Sat, 7 May 2011 06:48:54 -0400 Subject: [Python-checkins] Python Regression Test Failures refleak (1) Message-ID: <20110507104854.GA2308@kbk-i386-bb.dyndns.org> More important issues: ---------------------- test_bz2 leaked [-77, 0, 0] references, sum=-77 Less important issues: ---------------------- From python-checkins at python.org Sat May 7 13:12:41 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 13:12:41 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11277: Add tests for mmap crash when using large sparse files on OS X. Message-ID: http://hg.python.org/cpython/rev/d5d4f2967879 changeset: 69890:d5d4f2967879 branch: 3.1 parent: 69882:252451fef13f user: Nadeem Vawda date: Sat May 07 13:01:50 2011 +0200 summary: Issue #11277: Add tests for mmap crash when using large sparse files on OS X. Also, reduce code duplication in LargeMmapTests. Original patch by Steffen Daode Nurpmeso. files: Lib/test/test_mmap.py | 60 +++++++++++++++++------------- 1 files changed, 34 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -1,4 +1,5 @@ -from test.support import TESTFN, run_unittest, import_module, unlink, requires +from test.support import (TESTFN, run_unittest, import_module, unlink, + requires, _2G, _4G) import unittest import os, re, itertools, socket, sys @@ -653,28 +654,20 @@ def tearDown(self): unlink(TESTFN) - def _working_largefile(self): - # Only run if the current filesystem supports large files. - f = open(TESTFN, 'wb', buffering=0) - try: - f.seek(0x80000001) - f.write(b'x') - f.flush() - except (IOError, OverflowError): - raise unittest.SkipTest("filesystem does not have largefile support") - finally: - f.close() - unlink(TESTFN) - - def test_large_offset(self): + def _create_test_file(self, num_zeroes, tail): if sys.platform[:3] == 'win' or sys.platform == 'darwin': requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) - self._working_largefile() with open(TESTFN, 'wb') as f: - f.seek(0x14FFFFFFF) - f.write(b" ") + try: + f.seek(num_zeroes) + f.write(tail) + f.flush() + except (IOError, OverflowError): + raise unittest.SkipTest("filesystem does not have largefile support") + def test_large_offset(self): + self._create_test_file(0x14FFFFFFF, b" ") with open(TESTFN, 'rb') as f: m = mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ) try: @@ -683,14 +676,7 @@ m.close() def test_large_filesize(self): - if sys.platform[:3] == 'win' or sys.platform == 'darwin': - requires('largefile', - 'test requires %s bytes and a long time to run' % str(0x180000000)) - self._working_largefile() - with open(TESTFN, 'wb') as f: - f.seek(0x17FFFFFFF) - f.write(b" ") - + self._create_test_file(0x17FFFFFFF, b" ") with open(TESTFN, 'rb') as f: m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ) try: @@ -698,6 +684,28 @@ finally: m.close() + # Issue 11277: mmap() with large (~4GB) sparse files crashes on OS X. + + def _test_around_boundary(self, boundary): + tail = b' DEARdear ' + start = boundary - len(tail) // 2 + end = start + len(tail) + self._create_test_file(start, tail) + with open(TESTFN, 'rb') as f: + m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) + try: + self.assertEqual(m[start:end], tail) + finally: + m.close() + + @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") + def test_around_2GB(self): + self._test_around_boundary(_2G) + + @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") + def test_around_4GB(self): + self._test_around_boundary(_4G) + def test_main(): run_unittest(MmapTests, LargeMmapTests) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 13:12:42 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 13:12:42 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: #11277: Add tests for mmap crash when using large sparse files on OS X. Message-ID: http://hg.python.org/cpython/rev/e447a68742e7 changeset: 69891:e447a68742e7 branch: 3.2 parent: 69883:6907c43d1ee7 parent: 69890:d5d4f2967879 user: Nadeem Vawda date: Sat May 07 13:08:54 2011 +0200 summary: Merge: #11277: Add tests for mmap crash when using large sparse files on OS X. Also, reduce code duplication in LargeMmapTests. Original patch by Steffen Daode Nurpmeso. files: Lib/test/test_mmap.py | 57 ++++++++++++++++-------------- 1 files changed, 31 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -1,4 +1,5 @@ -from test.support import TESTFN, run_unittest, import_module, unlink, requires +from test.support import (TESTFN, run_unittest, import_module, unlink, + requires, _2G, _4G) import unittest import os import re @@ -662,45 +663,49 @@ def tearDown(self): unlink(TESTFN) - def _working_largefile(self): - # Only run if the current filesystem supports large files. - f = open(TESTFN, 'wb', buffering=0) - try: - f.seek(0x80000001) - f.write(b'x') - f.flush() - except (IOError, OverflowError): - raise unittest.SkipTest("filesystem does not have largefile support") - finally: - f.close() - unlink(TESTFN) - - def test_large_offset(self): + def _create_test_file(self, num_zeroes, tail): if sys.platform[:3] == 'win' or sys.platform == 'darwin': requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) - self._working_largefile() with open(TESTFN, 'wb') as f: - f.seek(0x14FFFFFFF) - f.write(b" ") + try: + f.seek(num_zeroes) + f.write(tail) + f.flush() + except (IOError, OverflowError): + raise unittest.SkipTest("filesystem does not have largefile support") + def test_large_offset(self): + self._create_test_file(0x14FFFFFFF, b" ") with open(TESTFN, 'rb') as f: with mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ) as m: self.assertEqual(m[0xFFFFFFF], 32) def test_large_filesize(self): - if sys.platform[:3] == 'win' or sys.platform == 'darwin': - requires('largefile', - 'test requires %s bytes and a long time to run' % str(0x180000000)) - self._working_largefile() - with open(TESTFN, 'wb') as f: - f.seek(0x17FFFFFFF) - f.write(b" ") - + self._create_test_file(0x17FFFFFFF, b" ") with open(TESTFN, 'rb') as f: with mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ) as m: self.assertEqual(m.size(), 0x180000000) + # Issue 11277: mmap() with large (~4GB) sparse files crashes on OS X. + + def _test_around_boundary(self, boundary): + tail = b' DEARdear ' + start = boundary - len(tail) // 2 + end = start + len(tail) + self._create_test_file(start, tail) + with open(TESTFN, 'rb') as f: + with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m: + self.assertEqual(m[start:end], tail) + + @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") + def test_around_2GB(self): + self._test_around_boundary(_2G) + + @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") + def test_around_4GB(self): + self._test_around_boundary(_4G) + def test_main(): run_unittest(MmapTests, LargeMmapTests) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 13:12:45 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 13:12:45 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: #11277: Add tests for mmap crash when using large sparse files on OS X. Message-ID: http://hg.python.org/cpython/rev/bc13badf10a1 changeset: 69892:bc13badf10a1 parent: 69889:eb003c3d1770 parent: 69891:e447a68742e7 user: Nadeem Vawda date: Sat May 07 13:11:59 2011 +0200 summary: Merge: #11277: Add tests for mmap crash when using large sparse files on OS X. Also, reduce code duplication in LargeMmapTests. Original patch by Steffen Daode Nurpmeso. files: Lib/test/test_mmap.py | 57 ++++++++++++++++-------------- 1 files changed, 31 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -1,4 +1,5 @@ -from test.support import TESTFN, run_unittest, import_module, unlink, requires +from test.support import (TESTFN, run_unittest, import_module, unlink, + requires, _2G, _4G) import unittest import os import re @@ -662,45 +663,49 @@ def tearDown(self): unlink(TESTFN) - def _working_largefile(self): - # Only run if the current filesystem supports large files. - f = open(TESTFN, 'wb', buffering=0) - try: - f.seek(0x80000001) - f.write(b'x') - f.flush() - except (IOError, OverflowError): - raise unittest.SkipTest("filesystem does not have largefile support") - finally: - f.close() - unlink(TESTFN) - - def test_large_offset(self): + def _create_test_file(self, num_zeroes, tail): if sys.platform[:3] == 'win' or sys.platform == 'darwin': requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) - self._working_largefile() with open(TESTFN, 'wb') as f: - f.seek(0x14FFFFFFF) - f.write(b" ") + try: + f.seek(num_zeroes) + f.write(tail) + f.flush() + except (IOError, OverflowError): + raise unittest.SkipTest("filesystem does not have largefile support") + def test_large_offset(self): + self._create_test_file(0x14FFFFFFF, b" ") with open(TESTFN, 'rb') as f: with mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ) as m: self.assertEqual(m[0xFFFFFFF], 32) def test_large_filesize(self): - if sys.platform[:3] == 'win' or sys.platform == 'darwin': - requires('largefile', - 'test requires %s bytes and a long time to run' % str(0x180000000)) - self._working_largefile() - with open(TESTFN, 'wb') as f: - f.seek(0x17FFFFFFF) - f.write(b" ") - + self._create_test_file(0x17FFFFFFF, b" ") with open(TESTFN, 'rb') as f: with mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ) as m: self.assertEqual(m.size(), 0x180000000) + # Issue 11277: mmap() with large (~4GB) sparse files crashes on OS X. + + def _test_around_boundary(self, boundary): + tail = b' DEARdear ' + start = boundary - len(tail) // 2 + end = start + len(tail) + self._create_test_file(start, tail) + with open(TESTFN, 'rb') as f: + with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m: + self.assertEqual(m[start:end], tail) + + @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") + def test_around_2GB(self): + self._test_around_boundary(_2G) + + @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") + def test_around_4GB(self): + self._test_around_boundary(_4G) + def test_main(): run_unittest(MmapTests, LargeMmapTests) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 13:17:51 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 13:17:51 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11277: Add tests for mmap crash when using large sparse files on OS X. Message-ID: http://hg.python.org/cpython/rev/8d27d2b22394 changeset: 69893:8d27d2b22394 branch: 2.7 parent: 69886:201dcfc56e86 user: Nadeem Vawda date: Sat May 07 13:17:16 2011 +0200 summary: Issue #11277: Add tests for mmap crash when using large sparse files on OS X. Also, reduce code duplication in LargeMmapTests. Original patch by Steffen Daode Nurpmeso. files: Lib/test/test_mmap.py | 60 +++++++++++++++++------------- 1 files changed, 34 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -1,4 +1,5 @@ -from test.test_support import TESTFN, run_unittest, import_module, unlink, requires +from test.test_support import (TESTFN, run_unittest, import_module, unlink, + requires, _2G, _4G) import unittest import os, re, itertools, socket, sys @@ -644,28 +645,20 @@ def tearDown(self): unlink(TESTFN) - def _working_largefile(self): - # Only run if the current filesystem supports large files. - f = open(TESTFN, 'wb', buffering=0) - try: - f.seek(0x80000001) - f.write(b'x') - f.flush() - except (IOError, OverflowError): - raise unittest.SkipTest("filesystem does not have largefile support") - finally: - f.close() - unlink(TESTFN) - - def test_large_offset(self): + def _create_test_file(self, num_zeroes, tail): if sys.platform[:3] == 'win' or sys.platform == 'darwin': requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) - self._working_largefile() with open(TESTFN, 'wb') as f: - f.seek(0x14FFFFFFF) - f.write(b" ") + try: + f.seek(num_zeroes) + f.write(tail) + f.flush() + except (IOError, OverflowError): + raise unittest.SkipTest("filesystem does not have largefile support") + def test_large_offset(self): + self._create_test_file(0x14FFFFFFF, b" ") with open(TESTFN, 'rb') as f: m = mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ) try: @@ -674,14 +667,7 @@ m.close() def test_large_filesize(self): - if sys.platform[:3] == 'win' or sys.platform == 'darwin': - requires('largefile', - 'test requires %s bytes and a long time to run' % str(0x180000000)) - self._working_largefile() - with open(TESTFN, 'wb') as f: - f.seek(0x17FFFFFFF) - f.write(b" ") - + self._create_test_file(0x17FFFFFFF, b" ") with open(TESTFN, 'rb') as f: m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ) try: @@ -689,6 +675,28 @@ finally: m.close() + # Issue 11277: mmap() with large (~4GB) sparse files crashes on OS X. + + def _test_around_boundary(self, boundary): + tail = b' DEARdear ' + start = boundary - len(tail) // 2 + end = start + len(tail) + self._create_test_file(start, tail) + with open(TESTFN, 'rb') as f: + m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) + try: + self.assertEqual(m[start:end], tail) + finally: + m.close() + + @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") + def test_around_2GB(self): + self._test_around_boundary(_2G) + + @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") + def test_around_4GB(self): + self._test_around_boundary(_4G) + def test_main(): run_unittest(MmapTests, LargeMmapTests) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:19:21 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 14:19:21 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11277: Fix tests - crash will not trigger if the file is closed and Message-ID: http://hg.python.org/cpython/rev/9b9f0de19684 changeset: 69894:9b9f0de19684 branch: 2.7 user: Nadeem Vawda date: Sat May 07 14:12:12 2011 +0200 summary: Issue #11277: Fix tests - crash will not trigger if the file is closed and reopened. files: Lib/test/test_mmap.py | 26 ++++++++++++-------------- 1 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -645,21 +645,21 @@ def tearDown(self): unlink(TESTFN) - def _create_test_file(self, num_zeroes, tail): + def _make_test_file(self, num_zeroes, tail): if sys.platform[:3] == 'win' or sys.platform == 'darwin': requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) - with open(TESTFN, 'wb') as f: - try: - f.seek(num_zeroes) - f.write(tail) - f.flush() - except (IOError, OverflowError): - raise unittest.SkipTest("filesystem does not have largefile support") + f = open(TESTFN, 'w+b') + try: + f.seek(num_zeroes) + f.write(tail) + f.flush() + except (IOError, OverflowError): + raise unittest.SkipTest("filesystem does not have largefile support") + return f def test_large_offset(self): - self._create_test_file(0x14FFFFFFF, b" ") - with open(TESTFN, 'rb') as f: + with self._make_test_file(0x14FFFFFFF, b" ") as f: m = mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ) try: self.assertEqual(m[0xFFFFFFF], b" ") @@ -667,8 +667,7 @@ m.close() def test_large_filesize(self): - self._create_test_file(0x17FFFFFFF, b" ") - with open(TESTFN, 'rb') as f: + with self._make_test_file(0x17FFFFFFF, b" ") as f: m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ) try: self.assertEqual(m.size(), 0x180000000) @@ -681,8 +680,7 @@ tail = b' DEARdear ' start = boundary - len(tail) // 2 end = start + len(tail) - self._create_test_file(start, tail) - with open(TESTFN, 'rb') as f: + with self._make_test_file(start, tail) as f: m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) try: self.assertEqual(m[start:end], tail) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:19:22 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 14:19:22 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11277: Fix tests - crash will not trigger if the file is closed and Message-ID: http://hg.python.org/cpython/rev/b112c72f8c01 changeset: 69895:b112c72f8c01 branch: 3.1 parent: 69890:d5d4f2967879 user: Nadeem Vawda date: Sat May 07 14:14:53 2011 +0200 summary: Issue #11277: Fix tests - crash will not trigger if the file is closed and reopened. files: Lib/test/test_mmap.py | 26 ++++++++++++-------------- 1 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -654,21 +654,21 @@ def tearDown(self): unlink(TESTFN) - def _create_test_file(self, num_zeroes, tail): + def _make_test_file(self, num_zeroes, tail): if sys.platform[:3] == 'win' or sys.platform == 'darwin': requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) - with open(TESTFN, 'wb') as f: - try: - f.seek(num_zeroes) - f.write(tail) - f.flush() - except (IOError, OverflowError): - raise unittest.SkipTest("filesystem does not have largefile support") + f = open(TESTFN, 'w+b') + try: + f.seek(num_zeroes) + f.write(tail) + f.flush() + except (IOError, OverflowError): + raise unittest.SkipTest("filesystem does not have largefile support") + return f def test_large_offset(self): - self._create_test_file(0x14FFFFFFF, b" ") - with open(TESTFN, 'rb') as f: + with self._make_test_file(0x14FFFFFFF, b" ") as f: m = mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ) try: self.assertEqual(m[0xFFFFFFF], 32) @@ -676,8 +676,7 @@ m.close() def test_large_filesize(self): - self._create_test_file(0x17FFFFFFF, b" ") - with open(TESTFN, 'rb') as f: + with self._make_test_file(0x17FFFFFFF, b" ") as f: m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ) try: self.assertEqual(m.size(), 0x180000000) @@ -690,8 +689,7 @@ tail = b' DEARdear ' start = boundary - len(tail) // 2 end = start + len(tail) - self._create_test_file(start, tail) - with open(TESTFN, 'rb') as f: + with self._make_test_file(start, tail) as f: m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) try: self.assertEqual(m[start:end], tail) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:19:23 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 14:19:23 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: #11277: Fix tests - crash will not trigger if the file is closed and Message-ID: http://hg.python.org/cpython/rev/a9da17fcb564 changeset: 69896:a9da17fcb564 branch: 3.2 parent: 69891:e447a68742e7 parent: 69895:b112c72f8c01 user: Nadeem Vawda date: Sat May 07 14:16:50 2011 +0200 summary: Merge: #11277: Fix tests - crash will not trigger if the file is closed and reopened. files: Lib/test/test_mmap.py | 26 ++++++++++++-------------- 1 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -663,27 +663,26 @@ def tearDown(self): unlink(TESTFN) - def _create_test_file(self, num_zeroes, tail): + def _make_test_file(self, num_zeroes, tail): if sys.platform[:3] == 'win' or sys.platform == 'darwin': requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) - with open(TESTFN, 'wb') as f: - try: - f.seek(num_zeroes) - f.write(tail) - f.flush() - except (IOError, OverflowError): - raise unittest.SkipTest("filesystem does not have largefile support") + f = open(TESTFN, 'w+b') + try: + f.seek(num_zeroes) + f.write(tail) + f.flush() + except (IOError, OverflowError): + raise unittest.SkipTest("filesystem does not have largefile support") + return f def test_large_offset(self): - self._create_test_file(0x14FFFFFFF, b" ") - with open(TESTFN, 'rb') as f: + with self._make_test_file(0x14FFFFFFF, b" ") as f: with mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ) as m: self.assertEqual(m[0xFFFFFFF], 32) def test_large_filesize(self): - self._create_test_file(0x17FFFFFFF, b" ") - with open(TESTFN, 'rb') as f: + with self._make_test_file(0x17FFFFFFF, b" ") as f: with mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ) as m: self.assertEqual(m.size(), 0x180000000) @@ -693,8 +692,7 @@ tail = b' DEARdear ' start = boundary - len(tail) // 2 end = start + len(tail) - self._create_test_file(start, tail) - with open(TESTFN, 'rb') as f: + with self._make_test_file(start, tail) as f: with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m: self.assertEqual(m[start:end], tail) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:19:30 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 14:19:30 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: #11277: Fix tests - crash will not trigger if the file is closed and Message-ID: http://hg.python.org/cpython/rev/b3a94906c4a0 changeset: 69897:b3a94906c4a0 parent: 69892:bc13badf10a1 parent: 69896:a9da17fcb564 user: Nadeem Vawda date: Sat May 07 14:17:27 2011 +0200 summary: Merge: #11277: Fix tests - crash will not trigger if the file is closed and reopened. files: Lib/test/test_mmap.py | 26 ++++++++++++-------------- 1 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -663,27 +663,26 @@ def tearDown(self): unlink(TESTFN) - def _create_test_file(self, num_zeroes, tail): + def _make_test_file(self, num_zeroes, tail): if sys.platform[:3] == 'win' or sys.platform == 'darwin': requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) - with open(TESTFN, 'wb') as f: - try: - f.seek(num_zeroes) - f.write(tail) - f.flush() - except (IOError, OverflowError): - raise unittest.SkipTest("filesystem does not have largefile support") + f = open(TESTFN, 'w+b') + try: + f.seek(num_zeroes) + f.write(tail) + f.flush() + except (IOError, OverflowError): + raise unittest.SkipTest("filesystem does not have largefile support") + return f def test_large_offset(self): - self._create_test_file(0x14FFFFFFF, b" ") - with open(TESTFN, 'rb') as f: + with self._make_test_file(0x14FFFFFFF, b" ") as f: with mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ) as m: self.assertEqual(m[0xFFFFFFF], 32) def test_large_filesize(self): - self._create_test_file(0x17FFFFFFF, b" ") - with open(TESTFN, 'rb') as f: + with self._make_test_file(0x17FFFFFFF, b" ") as f: with mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ) as m: self.assertEqual(m.size(), 0x180000000) @@ -693,8 +692,7 @@ tail = b' DEARdear ' start = boundary - len(tail) // 2 end = start + len(tail) - self._create_test_file(start, tail) - with open(TESTFN, 'rb') as f: + with self._make_test_file(start, tail) as f: with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m: self.assertEqual(m[start:end], tail) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:38:18 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 14:38:18 +0200 Subject: [Python-checkins] cpython (2.7): Fix potential resource leak in test_mmap. Message-ID: http://hg.python.org/cpython/rev/c066dd9dfc65 changeset: 69898:c066dd9dfc65 branch: 2.7 parent: 69894:9b9f0de19684 user: Nadeem Vawda date: Sat May 07 14:34:22 2011 +0200 summary: Fix potential resource leak in test_mmap. files: Lib/test/test_mmap.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -655,6 +655,7 @@ f.write(tail) f.flush() except (IOError, OverflowError): + f.close() raise unittest.SkipTest("filesystem does not have largefile support") return f -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:38:19 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 14:38:19 +0200 Subject: [Python-checkins] cpython (3.1): Fix potential resource leak in test_mmap. Message-ID: http://hg.python.org/cpython/rev/c32b3aceeb84 changeset: 69899:c32b3aceeb84 branch: 3.1 parent: 69895:b112c72f8c01 user: Nadeem Vawda date: Sat May 07 14:35:05 2011 +0200 summary: Fix potential resource leak in test_mmap. files: Lib/test/test_mmap.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -664,6 +664,7 @@ f.write(tail) f.flush() except (IOError, OverflowError): + f.close() raise unittest.SkipTest("filesystem does not have largefile support") return f -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:38:22 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 14:38:22 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: Fix potential resource leak in test_mmap. Message-ID: http://hg.python.org/cpython/rev/26bee6e91c1e changeset: 69900:26bee6e91c1e branch: 3.2 parent: 69896:a9da17fcb564 parent: 69899:c32b3aceeb84 user: Nadeem Vawda date: Sat May 07 14:35:36 2011 +0200 summary: Merge: Fix potential resource leak in test_mmap. files: Lib/test/test_mmap.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -673,6 +673,7 @@ f.write(tail) f.flush() except (IOError, OverflowError): + f.close() raise unittest.SkipTest("filesystem does not have largefile support") return f -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:38:23 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 07 May 2011 14:38:23 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: Fix potential resource leak in test_mmap. Message-ID: http://hg.python.org/cpython/rev/56594a13614d changeset: 69901:56594a13614d parent: 69897:b3a94906c4a0 parent: 69900:26bee6e91c1e user: Nadeem Vawda date: Sat May 07 14:36:14 2011 +0200 summary: Merge: Fix potential resource leak in test_mmap. files: Lib/test/test_mmap.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -673,6 +673,7 @@ f.write(tail) f.flush() except (IOError, OverflowError): + f.close() raise unittest.SkipTest("filesystem does not have largefile support") return f -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:45:02 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 07 May 2011 14:45:02 +0200 Subject: [Python-checkins] cpython: Close socket on connection failure. Message-ID: http://hg.python.org/cpython/rev/dd478725660a changeset: 69902:dd478725660a parent: 69897:b3a94906c4a0 user: Vinay Sajip date: Sat May 07 13:44:11 2011 +0100 summary: Close socket on connection failure. files: Lib/logging/handlers.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -469,6 +469,9 @@ self.retryTime = None # next time, no delay before trying except socket.error: #Creation failed, so set the retry time and return. + if self.sock is not None: + self.sock.close() + self.sock = None if self.retryTime is None: self.retryPeriod = self.retryStart else: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 14:45:02 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 07 May 2011 14:45:02 +0200 Subject: [Python-checkins] cpython (merge default -> default): Merge. Message-ID: http://hg.python.org/cpython/rev/5cde01c8003c changeset: 69903:5cde01c8003c parent: 69902:dd478725660a parent: 69901:56594a13614d user: Vinay Sajip date: Sat May 07 13:44:50 2011 +0100 summary: Merge. files: Lib/test/test_mmap.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -673,6 +673,7 @@ f.write(tail) f.flush() except (IOError, OverflowError): + f.close() raise unittest.SkipTest("filesystem does not have largefile support") return f -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 16:07:03 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 07 May 2011 16:07:03 +0200 Subject: [Python-checkins] cpython: #11072- applying http://bugs.python.org/review/11072/show suggestions Message-ID: http://hg.python.org/cpython/rev/153bd8fc22c7 changeset: 69904:153bd8fc22c7 user: Giampaolo Rodola' date: Sat May 07 16:06:59 2011 +0200 summary: #11072- applying http://bugs.python.org/review/11072/show suggestions files: Doc/library/ftplib.rst | 16 ++++++++-------- Lib/test/test_ftplib.py | 11 +++++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -322,13 +322,13 @@ .. method:: FTP.mlsd(path="", facts=[]) List a directory in a standardized format by using MLSD command - (:rfc:`3659`). If *path* is omitted the current directory is assumed. + (:rfc:`3659`). If *path* is omitted the current directory is assumed. *facts* is a list of strings representing the type of information desired - (e.g. *["type", "size", "perm"]*). Return a generator object yielding a - tuple of two elements for every file found in path. First element is the - file name, the second one is a dictionary including a variable number of - "facts" depending on the server and whether *facts* argument has been - provided. + (e.g. ``["type", "size", "perm"]``). Return a generator object yielding a + tuple of two elements for every file found in path. First element is the + file name, the second one is a dictionary containing facts about the file + name. Content of this dictionary might be limited by the *facts* argument + but server is not guaranteed to return all requested facts. .. versionadded:: 3.3 @@ -340,7 +340,7 @@ directory). Multiple arguments can be used to pass non-standard options to the ``NLST`` command. - .. deprecated:: 3.3 use :meth:`mlsd` instead + .. deprecated:: 3.3 use :meth:`mlsd` instead. .. method:: FTP.dir(argument[, ...]) @@ -352,7 +352,7 @@ as a *callback* function as for :meth:`retrlines`; the default prints to ``sys.stdout``. This method returns ``None``. - .. deprecated:: 3.3 use :meth:`mlsd` instead + .. deprecated:: 3.3 use :meth:`mlsd` instead. .. method:: FTP.rename(fromname, toname) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -586,10 +586,12 @@ ls = list(self.client.mlsd()) for name, facts in ls: + self.assertIsInstance(name, str) + self.assertIsInstance(facts, dict) self.assertTrue(name) - self.assertTrue('type' in facts) - self.assertTrue('perm' in facts) - self.assertTrue('unique' in facts) + self.assertIn('type', facts) + self.assertIn('perm', facts) + self.assertIn('unique', facts) def set_data(data): self.server.handler_instance.next_data = data @@ -626,7 +628,8 @@ # case sensitiveness set_data('Type=type;TyPe=perm;UNIQUE=unique; name\r\n') _name, facts = next(self.client.mlsd()) - [self.assertTrue(x.islower()) for x in facts.keys()] + for x in facts: + self.assertTrue(x.islower()) # no data (directory empty) set_data('') self.assertRaises(StopIteration, next, self.client.mlsd()) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 16:55:55 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 07 May 2011 16:55:55 +0200 Subject: [Python-checkins] cpython: Changed where socket close is called on connection failure. Message-ID: http://hg.python.org/cpython/rev/038bb7ac7c4e changeset: 69905:038bb7ac7c4e user: Vinay Sajip date: Sat May 07 15:55:47 2011 +0100 summary: Changed where socket close is called on connection failure. files: Lib/logging/handlers.py | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -446,8 +446,12 @@ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if hasattr(s, 'settimeout'): s.settimeout(timeout) - s.connect((self.host, self.port)) - return s + try: + s.connect((self.host, self.port)) + return s + except socket.error: + s.close() + raise def createSocket(self): """ @@ -469,9 +473,6 @@ self.retryTime = None # next time, no delay before trying except socket.error: #Creation failed, so set the retry time and return. - if self.sock is not None: - self.sock.close() - self.sock = None if self.retryTime is None: self.retryPeriod = self.retryStart else: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 17:08:41 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 07 May 2011 17:08:41 +0200 Subject: [Python-checkins] cpython: test_ftplib.py: change client default timeout from 10 to 2. Hanging for 10 Message-ID: http://hg.python.org/cpython/rev/d2a41b2ae432 changeset: 69906:d2a41b2ae432 parent: 69904:153bd8fc22c7 user: Giampaolo Rodola' date: Sat May 07 17:02:21 2011 +0200 summary: test_ftplib.py: change client default timeout from 10 to 2. Hanging for 10 seconds is way too much when we expect a server response which never comes in. files: Lib/test/test_ftplib.py | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -123,7 +123,7 @@ addr = list(map(int, arg.split(','))) ip = '%d.%d.%d.%d' %tuple(addr[:4]) port = (addr[4] * 256) + addr[5] - s = socket.create_connection((ip, port), timeout=10) + s = socket.create_connection((ip, port), timeout=2) self.dtp = self.dtp_handler(s, baseclass=self) self.push('200 active data connection established') @@ -141,7 +141,7 @@ def cmd_eprt(self, arg): af, ip, port = arg.split(arg[0])[1:-1] port = int(port) - s = socket.create_connection((ip, port), timeout=10) + s = socket.create_connection((ip, port), timeout=2) self.dtp = self.dtp_handler(s, baseclass=self) self.push('200 active data connection established') @@ -440,7 +440,7 @@ def setUp(self): self.server = DummyFTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP(timeout=10) + self.client = ftplib.FTP(timeout=2) self.client.connect(self.server.host, self.server.port) def tearDown(self): @@ -663,7 +663,7 @@ return True # base test - with ftplib.FTP(timeout=10) as self.client: + with ftplib.FTP(timeout=2) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.assertTrue(is_client_connected()) @@ -671,7 +671,7 @@ self.assertFalse(is_client_connected()) # QUIT sent inside the with block - with ftplib.FTP(timeout=10) as self.client: + with ftplib.FTP(timeout=2) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.client.quit() @@ -681,7 +681,7 @@ # force a wrong response code to be sent on QUIT: error_perm # is expected and the connection is supposed to be closed try: - with ftplib.FTP(timeout=10) as self.client: + with ftplib.FTP(timeout=2) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.server.handler_instance.next_response = '550 error on quit' @@ -779,7 +779,7 @@ def setUp(self): self.server = DummyTLS_FTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP_TLS(timeout=10) + self.client = ftplib.FTP_TLS(timeout=2) self.client.connect(self.server.host, self.server.port) # enable TLS self.client.auth() @@ -792,7 +792,7 @@ def setUp(self): self.server = DummyTLS_FTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP_TLS(timeout=10) + self.client = ftplib.FTP_TLS(timeout=2) self.client.connect(self.server.host, self.server.port) def tearDown(self): @@ -852,7 +852,7 @@ self.assertRaises(ValueError, ftplib.FTP_TLS, certfile=CERTFILE, keyfile=CERTFILE, context=ctx) - self.client = ftplib.FTP_TLS(context=ctx, timeout=10) + self.client = ftplib.FTP_TLS(context=ctx, timeout=2) self.client.connect(self.server.host, self.server.port) self.assertNotIsInstance(self.client.sock, ssl.SSLSocket) self.client.auth() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 17:08:42 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 07 May 2011 17:08:42 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge heads Message-ID: http://hg.python.org/cpython/rev/5b1627b75fc7 changeset: 69907:5b1627b75fc7 parent: 69906:d2a41b2ae432 parent: 69905:038bb7ac7c4e user: Giampaolo Rodola' date: Sat May 07 17:08:04 2011 +0200 summary: merge heads files: Lib/logging/handlers.py | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -446,8 +446,12 @@ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if hasattr(s, 'settimeout'): s.settimeout(timeout) - s.connect((self.host, self.port)) - return s + try: + s.connect((self.host, self.port)) + return s + except socket.error: + s.close() + raise def createSocket(self): """ @@ -469,9 +473,6 @@ self.retryTime = None # next time, no delay before trying except socket.error: #Creation failed, so set the retry time and return. - if self.sock is not None: - self.sock.close() - self.sock = None if self.retryTime is None: self.retryPeriod = self.retryStart else: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 17:08:43 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 07 May 2011 17:08:43 +0200 Subject: [Python-checkins] cpython: test_ftplib.py: change client default timeout from 10 to 2. Hanging for 10 Message-ID: http://hg.python.org/cpython/rev/9688977ef567 changeset: 69908:9688977ef567 user: Giampaolo Rodola' date: Sat May 07 17:08:34 2011 +0200 summary: test_ftplib.py: change client default timeout from 10 to 2. Hanging for 10 seconds is way too much when we expect a server response which never comes in. files: Lib/test/test_ftplib.py | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -123,7 +123,7 @@ addr = list(map(int, arg.split(','))) ip = '%d.%d.%d.%d' %tuple(addr[:4]) port = (addr[4] * 256) + addr[5] - s = socket.create_connection((ip, port), timeout=2) + s = socket.create_connection((ip, port), timeout=10) self.dtp = self.dtp_handler(s, baseclass=self) self.push('200 active data connection established') @@ -141,7 +141,7 @@ def cmd_eprt(self, arg): af, ip, port = arg.split(arg[0])[1:-1] port = int(port) - s = socket.create_connection((ip, port), timeout=2) + s = socket.create_connection((ip, port), timeout=10) self.dtp = self.dtp_handler(s, baseclass=self) self.push('200 active data connection established') @@ -440,7 +440,7 @@ def setUp(self): self.server = DummyFTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP(timeout=2) + self.client = ftplib.FTP(timeout=10) self.client.connect(self.server.host, self.server.port) def tearDown(self): @@ -663,7 +663,7 @@ return True # base test - with ftplib.FTP(timeout=2) as self.client: + with ftplib.FTP(timeout=10) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.assertTrue(is_client_connected()) @@ -671,7 +671,7 @@ self.assertFalse(is_client_connected()) # QUIT sent inside the with block - with ftplib.FTP(timeout=2) as self.client: + with ftplib.FTP(timeout=10) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.client.quit() @@ -681,7 +681,7 @@ # force a wrong response code to be sent on QUIT: error_perm # is expected and the connection is supposed to be closed try: - with ftplib.FTP(timeout=2) as self.client: + with ftplib.FTP(timeout=10) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.server.handler_instance.next_response = '550 error on quit' @@ -779,7 +779,7 @@ def setUp(self): self.server = DummyTLS_FTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP_TLS(timeout=2) + self.client = ftplib.FTP_TLS(timeout=10) self.client.connect(self.server.host, self.server.port) # enable TLS self.client.auth() @@ -792,7 +792,7 @@ def setUp(self): self.server = DummyTLS_FTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP_TLS(timeout=2) + self.client = ftplib.FTP_TLS(timeout=10) self.client.connect(self.server.host, self.server.port) def tearDown(self): @@ -852,7 +852,7 @@ self.assertRaises(ValueError, ftplib.FTP_TLS, certfile=CERTFILE, keyfile=CERTFILE, context=ctx) - self.client = ftplib.FTP_TLS(context=ctx, timeout=2) + self.client = ftplib.FTP_TLS(context=ctx, timeout=10) self.client.connect(self.server.host, self.server.port) self.assertNotIsInstance(self.client.sock, ssl.SSLSocket) self.client.auth() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 17:29:24 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 07 May 2011 17:29:24 +0200 Subject: [Python-checkins] cpython (2.7): #12017: Fix segfault in json.loads() while decoding highly-nested objects using Message-ID: http://hg.python.org/cpython/rev/6fa20e360e5e changeset: 69909:6fa20e360e5e branch: 2.7 parent: 69898:c066dd9dfc65 user: Ezio Melotti date: Sat May 07 17:40:23 2011 +0300 summary: #12017: Fix segfault in json.loads() while decoding highly-nested objects using the C accelerations. files: Lib/json/tests/test_recursion.py | 19 ++++++++++++ Misc/NEWS | 3 ++ Modules/_json.c | 30 +++++++++++++++++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/Lib/json/tests/test_recursion.py b/Lib/json/tests/test_recursion.py --- a/Lib/json/tests/test_recursion.py +++ b/Lib/json/tests/test_recursion.py @@ -65,3 +65,22 @@ pass else: self.fail("didn't raise ValueError on default recursion") + + + def test_highly_nested_objects(self): + # test that loading highly-nested objects doesn't segfault when C + # accelerations are used. See #12017 + # str + with self.assertRaises(RuntimeError): + json.loads('{"a":' * 100000 + '1' + '}' * 100000) + with self.assertRaises(RuntimeError): + json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) + with self.assertRaises(RuntimeError): + json.loads('[' * 100000 + '1' + ']' * 100000) + # unicode + with self.assertRaises(RuntimeError): + json.loads(u'{"a":' * 100000 + u'1' + u'}' * 100000) + with self.assertRaises(RuntimeError): + json.loads(u'{"a":' * 100000 + u'[1]' + u'}' * 100000) + with self.assertRaises(RuntimeError): + json.loads(u'[' * 100000 + u'1' + u']' * 100000) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -358,6 +358,9 @@ Extension Modules ----------------- +- Issue #12017: Fix segfault in json.loads() while decoding highly-nested + objects using the C accelerations. + - Issue #1838: Prevent segfault in ctypes, when _as_parameter_ on a class is set to an instance of the class. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1488,6 +1488,7 @@ Returns a new PyObject representation of the term. */ + PyObject *res; char *str = PyString_AS_STRING(pystr); Py_ssize_t length = PyString_GET_SIZE(pystr); if (idx >= length) { @@ -1503,10 +1504,20 @@ next_idx_ptr); case '{': /* object */ - return _parse_object_str(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON object " + "from a byte string")) + return NULL; + res = _parse_object_str(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case '[': /* array */ - return _parse_array_str(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON array " + "from a byte string")) + return NULL; + res = _parse_array_str(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case 'n': /* null */ if ((idx + 3 < length) && str[idx + 1] == 'u' && str[idx + 2] == 'l' && str[idx + 3] == 'l') { @@ -1564,6 +1575,7 @@ Returns a new PyObject representation of the term. */ + PyObject *res; Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr); Py_ssize_t length = PyUnicode_GET_SIZE(pystr); if (idx >= length) { @@ -1578,10 +1590,20 @@ next_idx_ptr); case '{': /* object */ - return _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON object " + "from a unicode string")) + return NULL; + res = _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case '[': /* array */ - return _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON array " + "from a unicode string")) + return NULL; + res = _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case 'n': /* null */ if ((idx + 3 < length) && str[idx + 1] == 'u' && str[idx + 2] == 'l' && str[idx + 3] == 'l') { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 17:29:27 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 07 May 2011 17:29:27 +0200 Subject: [Python-checkins] cpython (3.1): #12017: Fix segfault in json.loads() while decoding highly-nested objects using Message-ID: http://hg.python.org/cpython/rev/61164d09337e changeset: 69910:61164d09337e branch: 3.1 parent: 69899:c32b3aceeb84 user: Ezio Melotti date: Sat May 07 17:58:09 2011 +0300 summary: #12017: Fix segfault in json.loads() while decoding highly-nested objects using the C accelerations. files: Lib/json/tests/test_recursion.py | 12 ++++++++++++ Misc/NEWS | 3 +++ Modules/_json.c | 15 +++++++++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Lib/json/tests/test_recursion.py b/Lib/json/tests/test_recursion.py --- a/Lib/json/tests/test_recursion.py +++ b/Lib/json/tests/test_recursion.py @@ -65,3 +65,15 @@ pass else: self.fail("didn't raise ValueError on default recursion") + + + def test_highly_nested_objects(self): + # test that loading highly-nested objects doesn't segfault when C + # accelerations are used. See #12017 + with self.assertRaises(RuntimeError): + json.loads('{"a":' * 100000 + '1' + '}' * 100000) + with self.assertRaises(RuntimeError): + json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) + with self.assertRaises(RuntimeError): + json.loads('[' * 100000 + '1' + ']' * 100000) + diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -314,6 +314,9 @@ Extensions ---------- +- Issue #12017: Fix segfault in json.loads() while decoding highly-nested + objects using the C accelerations. + - Issue #1838: Prevent segfault in ctypes, when _as_parameter_ on a class is set to an instance of the class. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -899,6 +899,7 @@ Returns a new PyObject representation of the term. */ + PyObject *res; Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr); Py_ssize_t length = PyUnicode_GET_SIZE(pystr); if (idx >= length) { @@ -913,10 +914,20 @@ next_idx_ptr); case '{': /* object */ - return _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON object " + "from a unicode string")) + return NULL; + res = _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case '[': /* array */ - return _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON array " + "from a unicode string")) + return NULL; + res = _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case 'n': /* null */ if ((idx + 3 < length) && str[idx + 1] == 'u' && str[idx + 2] == 'l' && str[idx + 3] == 'l') { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 17:29:30 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 07 May 2011 17:29:30 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #12017: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/db97968379dd changeset: 69911:db97968379dd branch: 3.2 parent: 69900:26bee6e91c1e parent: 69910:61164d09337e user: Ezio Melotti date: Sat May 07 18:15:34 2011 +0300 summary: #12017: merge with 3.1. files: Lib/test/json_tests/test_recursion.py | 12 ++++++++++++ Misc/NEWS | 6 +++++- Modules/_json.c | 15 +++++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Lib/test/json_tests/test_recursion.py b/Lib/test/json_tests/test_recursion.py --- a/Lib/test/json_tests/test_recursion.py +++ b/Lib/test/json_tests/test_recursion.py @@ -65,3 +65,15 @@ pass else: self.fail("didn't raise ValueError on default recursion") + + + def test_highly_nested_objects(self): + # test that loading highly-nested objects doesn't segfault when C + # accelerations are used. See #12017 + with self.assertRaises(RuntimeError): + json.loads('{"a":' * 100000 + '1' + '}' * 100000) + with self.assertRaises(RuntimeError): + json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) + with self.assertRaises(RuntimeError): + json.loads('[' * 100000 + '1' + ']' * 100000) + diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -324,8 +324,11 @@ - Issue #11179: Make ccbench work under Python 3.1 and 2.7 again. -Extensions ----------- +Extension Modules +----------------- + +- Issue #12017: Fix segfault in json.loads() while decoding highly-nested + objects using the C accelerations. - Issue #1838: Prevent segfault in ctypes, when _as_parameter_ on a class is set to an instance of the class. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -927,6 +927,7 @@ Returns a new PyObject representation of the term. */ + PyObject *res; Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr); Py_ssize_t length = PyUnicode_GET_SIZE(pystr); if (idx >= length) { @@ -941,10 +942,20 @@ next_idx_ptr); case '{': /* object */ - return _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON object " + "from a unicode string")) + return NULL; + res = _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case '[': /* array */ - return _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON array " + "from a unicode string")) + return NULL; + res = _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case 'n': /* null */ if ((idx + 3 < length) && str[idx + 1] == 'u' && str[idx + 2] == 'l' && str[idx + 3] == 'l') { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 17:29:34 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 07 May 2011 17:29:34 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #12017: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/389620c9e609 changeset: 69912:389620c9e609 parent: 69908:9688977ef567 parent: 69911:db97968379dd user: Ezio Melotti date: Sat May 07 18:29:14 2011 +0300 summary: #12017: merge with 3.2. files: Lib/test/json_tests/test_recursion.py | 11 +++++++++++ Misc/NEWS | 6 +++++- Modules/_json.c | 15 +++++++++++++-- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/Lib/test/json_tests/test_recursion.py b/Lib/test/json_tests/test_recursion.py --- a/Lib/test/json_tests/test_recursion.py +++ b/Lib/test/json_tests/test_recursion.py @@ -65,3 +65,14 @@ pass else: self.fail("didn't raise ValueError on default recursion") + + + def test_highly_nested_objects(self): + # test that loading highly-nested objects doesn't segfault when C + # accelerations are used. See #12017 + with self.assertRaises(RuntimeError): + json.loads('{"a":' * 100000 + '1' + '}' * 100000) + with self.assertRaises(RuntimeError): + json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) + with self.assertRaises(RuntimeError): + json.loads('[' * 100000 + '1' + ']' * 100000) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -580,8 +580,11 @@ - Issue #11179: Make ccbench work under Python 3.1 and 2.7 again. -Extensions ----------- +Extension Modules +----------------- + +- Issue #12017: Fix segfault in json.loads() while decoding highly-nested + objects using the C accelerations. - Issue #1838: Prevent segfault in ctypes, when _as_parameter_ on a class is set to an instance of the class. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -943,6 +943,7 @@ Returns a new PyObject representation of the term. */ + PyObject *res; Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr); Py_ssize_t length = PyUnicode_GET_SIZE(pystr); if (idx >= length) { @@ -957,10 +958,20 @@ next_idx_ptr); case '{': /* object */ - return _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON object " + "from a unicode string")) + return NULL; + res = _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case '[': /* array */ - return _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr); + if (Py_EnterRecursiveCall(" while decoding a JSON array " + "from a unicode string")) + return NULL; + res = _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr); + Py_LeaveRecursiveCall(); + return res; case 'n': /* null */ if ((idx + 3 < length) && str[idx + 1] == 'u' && str[idx + 2] == 'l' && str[idx + 3] == 'l') { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 18:01:29 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 07 May 2011 18:01:29 +0200 Subject: [Python-checkins] cpython: Closed resource leak in SysLogHandler. Message-ID: http://hg.python.org/cpython/rev/ff55dfb40984 changeset: 69913:ff55dfb40984 user: Vinay Sajip date: Sat May 07 17:01:22 2011 +0100 summary: Closed resource leak in SysLogHandler. files: Lib/logging/handlers.py | 3 +- Lib/test/test_logging.py | 56 +++++++++++++-------------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -756,8 +756,7 @@ """ Closes the socket. """ - if self.unixsocket: - self.socket.close() + self.socket.close() logging.Handler.close(self) def mapPriority(self, levelName): diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3484,41 +3484,39 @@ def test_rollover(self): fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S', backupCount=1) - try: - r = logging.makeLogRecord({'msg': 'testing'}) - fh.emit(r) - self.assertLogFile(self.fn) - time.sleep(1.0) - fh.emit(r) - # At this point, we should have a recent rotated file which we - # can test for the existence of. However, in practice, on some - # machines which run really slowly, we don't know how far back - # in time to go to look for the log file. So, we go back a fair - # bit, and stop as soon as we see a rotated file. In theory this - # could of course still fail, but the chances are lower. - found = False - now = datetime.datetime.now() - GO_BACK = 2 * 60 # seconds - for secs in range(1, GO_BACK): - prev = now - datetime.timedelta(seconds=secs) - fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S") - found = os.path.exists(fn) - if found: - self.rmfiles.append(fn) - break - msg = 'No rotated files found, went back %d seconds' % GO_BACK - self.assertTrue(found, msg=msg) - finally: - fh.close() + r = logging.makeLogRecord({'msg': 'testing'}) + fh.emit(r) + self.assertLogFile(self.fn) + time.sleep(1.0) + fh.emit(r) + fh.close() + # At this point, we should have a recent rotated file which we + # can test for the existence of. However, in practice, on some + # machines which run really slowly, we don't know how far back + # in time to go to look for the log file. So, we go back a fair + # bit, and stop as soon as we see a rotated file. In theory this + # could of course still fail, but the chances are lower. + found = False + now = datetime.datetime.now() + GO_BACK = 2 * 60 # seconds + for secs in range(1, GO_BACK): + prev = now - datetime.timedelta(seconds=secs) + fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S") + found = os.path.exists(fn) + if found: + self.rmfiles.append(fn) + break + msg = 'No rotated files found, went back %d seconds' % GO_BACK + self.assertTrue(found, msg=msg) def test_invalid(self): assertRaises = self.assertRaises assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler, - self.fn, 'X') + self.fn, 'X', delay=True) assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler, - self.fn, 'W') + self.fn, 'W', delay=True) assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler, - self.fn, 'W7') + self.fn, 'W7', delay=True) def secs(**kw): return datetime.timedelta(**kw) // datetime.timedelta(seconds=1) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 18:47:38 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 07 May 2011 18:47:38 +0200 Subject: [Python-checkins] cpython: reverting 9688977ef567 committed by accident Message-ID: http://hg.python.org/cpython/rev/73637c966f43 changeset: 69914:73637c966f43 user: Giampaolo Rodola' date: Sat May 07 18:47:31 2011 +0200 summary: reverting 9688977ef567 committed by accident files: Lib/test/test_ftplib.py | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -123,7 +123,7 @@ addr = list(map(int, arg.split(','))) ip = '%d.%d.%d.%d' %tuple(addr[:4]) port = (addr[4] * 256) + addr[5] - s = socket.create_connection((ip, port), timeout=10) + s = socket.create_connection((ip, port), timeout=2) self.dtp = self.dtp_handler(s, baseclass=self) self.push('200 active data connection established') @@ -141,7 +141,7 @@ def cmd_eprt(self, arg): af, ip, port = arg.split(arg[0])[1:-1] port = int(port) - s = socket.create_connection((ip, port), timeout=10) + s = socket.create_connection((ip, port), timeout=2) self.dtp = self.dtp_handler(s, baseclass=self) self.push('200 active data connection established') @@ -440,7 +440,7 @@ def setUp(self): self.server = DummyFTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP(timeout=10) + self.client = ftplib.FTP(timeout=2) self.client.connect(self.server.host, self.server.port) def tearDown(self): @@ -663,7 +663,7 @@ return True # base test - with ftplib.FTP(timeout=10) as self.client: + with ftplib.FTP(timeout=2) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.assertTrue(is_client_connected()) @@ -671,7 +671,7 @@ self.assertFalse(is_client_connected()) # QUIT sent inside the with block - with ftplib.FTP(timeout=10) as self.client: + with ftplib.FTP(timeout=2) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.client.quit() @@ -681,7 +681,7 @@ # force a wrong response code to be sent on QUIT: error_perm # is expected and the connection is supposed to be closed try: - with ftplib.FTP(timeout=10) as self.client: + with ftplib.FTP(timeout=2) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.server.handler_instance.next_response = '550 error on quit' @@ -779,7 +779,7 @@ def setUp(self): self.server = DummyTLS_FTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP_TLS(timeout=10) + self.client = ftplib.FTP_TLS(timeout=2) self.client.connect(self.server.host, self.server.port) # enable TLS self.client.auth() @@ -792,7 +792,7 @@ def setUp(self): self.server = DummyTLS_FTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP_TLS(timeout=10) + self.client = ftplib.FTP_TLS(timeout=2) self.client.connect(self.server.host, self.server.port) def tearDown(self): @@ -852,7 +852,7 @@ self.assertRaises(ValueError, ftplib.FTP_TLS, certfile=CERTFILE, keyfile=CERTFILE, context=ctx) - self.client = ftplib.FTP_TLS(context=ctx, timeout=10) + self.client = ftplib.FTP_TLS(context=ctx, timeout=2) self.client.connect(self.server.host, self.server.port) self.assertNotIsInstance(self.client.sock, ssl.SSLSocket) self.client.auth() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 18:51:57 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 07 May 2011 18:51:57 +0200 Subject: [Python-checkins] cpython (2.7): #10169: Fix argument parsing in socket.sendto() to avoid error masking. Message-ID: http://hg.python.org/cpython/rev/7c3a20b5943a changeset: 69915:7c3a20b5943a branch: 2.7 parent: 69909:6fa20e360e5e user: Ezio Melotti date: Sat May 07 19:21:22 2011 +0300 summary: #10169: Fix argument parsing in socket.sendto() to avoid error masking. files: Lib/test/test_socket.py | 39 +++++++++++++++++++++++++++++ Misc/NEWS | 2 + Modules/socketmodule.c | 20 +++++++++++--- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -274,6 +274,45 @@ self.assertRaises(socket.error, raise_gaierror, "Error raising socket exception.") + def testSendtoErrors(self): + # Testing that sendto doens't masks failures. See #10169. + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.addCleanup(s.close) + s.bind(('', 0)) + sockname = s.getsockname() + # 2 args + with self.assertRaises(UnicodeEncodeError): + s.sendto(u'\u2620', sockname) + with self.assertRaises(TypeError) as cm: + s.sendto(5j, sockname) + self.assertIn('not complex', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto('foo', None) + self.assertIn('not NoneType', str(cm.exception)) + # 3 args + with self.assertRaises(UnicodeEncodeError): + s.sendto(u'\u2620', 0, sockname) + with self.assertRaises(TypeError) as cm: + s.sendto(5j, 0, sockname) + self.assertIn('not complex', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto('foo', 0, None) + self.assertIn('not NoneType', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto('foo', 'bar', sockname) + self.assertIn('an integer is required', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto('foo', None, None) + self.assertIn('an integer is required', str(cm.exception)) + # wrong number of args + with self.assertRaises(TypeError) as cm: + s.sendto('foo') + self.assertIn('(1 given)', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto('foo', 0, sockname, 4) + self.assertIn('(4 given)', str(cm.exception)) + + def testCrucialConstants(self): # Testing for mission critical constants socket.AF_INET diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -358,6 +358,8 @@ Extension Modules ----------------- +- Issue #10169: Fix argument parsing in socket.sendto() to avoid error masking. + - Issue #12017: Fix segfault in json.loads() while decoding highly-nested objects using the C accelerations. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2826,14 +2826,24 @@ Py_ssize_t len; sock_addr_t addrbuf; int addrlen, n = -1, flags, timeout; + int arglen; flags = 0; - if (!PyArg_ParseTuple(args, "s*O:sendto", &pbuf, &addro)) { - PyErr_Clear(); - if (!PyArg_ParseTuple(args, "s*iO:sendto", - &pbuf, &flags, &addro)) - return NULL; + arglen = PyTuple_Size(args); + switch(arglen) { + case 2: + PyArg_ParseTuple(args, "s*O:sendto", &pbuf, &addro); + break; + case 3: + PyArg_ParseTuple(args, "s*iO:sendto", &pbuf, &flags, &addro); + break; + default: + PyErr_Format(PyExc_TypeError, "sendto() takes 2 or 3" + " arguments (%d given)", arglen); } + if (PyErr_Occurred()) + return NULL; + buf = pbuf.buf; len = pbuf.len; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 18:51:58 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 07 May 2011 18:51:58 +0200 Subject: [Python-checkins] cpython (3.1): #5421: add tests. Message-ID: http://hg.python.org/cpython/rev/9222c9d747c1 changeset: 69916:9222c9d747c1 branch: 3.1 parent: 69910:61164d09337e user: Ezio Melotti date: Sat May 07 19:47:48 2011 +0300 summary: #5421: add tests. files: Lib/test/test_socket.py | 30 +++++++++++++++++++++++++++++ 1 files changed, 30 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -274,6 +274,36 @@ self.assertRaises(socket.error, raise_gaierror, "Error raising socket exception.") + def testSendtoErrors(self): + # Testing that sendto doens't masks failures. See #10169. + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.addCleanup(s.close) + s.bind(('', 0)) + sockname = s.getsockname() + # 2 args + with self.assertRaises(TypeError): + s.sendto('\u2620', sockname) + with self.assertRaises(TypeError): + s.sendto(5j, sockname) + with self.assertRaises(TypeError): + s.sendto(b'foo', None) + # 3 args + with self.assertRaises(TypeError): + s.sendto('\u2620', 0, sockname) + with self.assertRaises(TypeError): + s.sendto(5j, 0, sockname) + with self.assertRaises(TypeError): + s.sendto(b'foo', 0, None) + with self.assertRaises(TypeError): + s.sendto(b'foo', 'bar', sockname) + with self.assertRaises(TypeError): + s.sendto(b'foo', None, None) + # wrong number of args + with self.assertRaises(TypeError): + s.sendto(b'foo') + with self.assertRaises(TypeError): + s.sendto(b'foo', 0, sockname, 4) + def testCrucialConstants(self): # Testing for mission critical constants socket.AF_INET -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 18:51:59 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 07 May 2011 18:51:59 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #5421: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/4b3352b49483 changeset: 69917:4b3352b49483 branch: 3.2 parent: 69911:db97968379dd parent: 69916:9222c9d747c1 user: Ezio Melotti date: Sat May 07 19:50:28 2011 +0300 summary: #5421: merge with 3.1. files: Lib/test/test_socket.py | 44 +++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -295,6 +295,50 @@ self.assertRaises(socket.error, raise_gaierror, "Error raising socket exception.") + def testSendtoErrors(self): + # Testing that sendto doens't masks failures. See #10169. + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.addCleanup(s.close) + s.bind(('', 0)) + sockname = s.getsockname() + # 2 args + with self.assertRaises(TypeError) as cm: + s.sendto('\u2620', sockname) + self.assertEqual(str(cm.exception), + "'str' does not support the buffer interface") + with self.assertRaises(TypeError) as cm: + s.sendto(5j, sockname) + self.assertEqual(str(cm.exception), + "'complex' does not support the buffer interface") + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', None) + self.assertIn('not NoneType',str(cm.exception)) + # 3 args + with self.assertRaises(TypeError) as cm: + s.sendto('\u2620', 0, sockname) + self.assertEqual(str(cm.exception), + "'str' does not support the buffer interface") + with self.assertRaises(TypeError) as cm: + s.sendto(5j, 0, sockname) + self.assertEqual(str(cm.exception), + "'complex' does not support the buffer interface") + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', 0, None) + self.assertIn('not NoneType', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', 'bar', sockname) + self.assertIn('an integer is required', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', None, None) + self.assertIn('an integer is required', str(cm.exception)) + # wrong number of args + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo') + self.assertIn('(1 given)', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', 0, sockname, 4) + self.assertIn('(4 given)', str(cm.exception)) + def testCrucialConstants(self): # Testing for mission critical constants socket.AF_INET -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 18:52:00 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 07 May 2011 18:52:00 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #5421: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/20273f2195ba changeset: 69918:20273f2195ba parent: 69914:73637c966f43 parent: 69917:4b3352b49483 user: Ezio Melotti date: Sat May 07 19:51:47 2011 +0300 summary: #5421: merge with 3.2. files: Lib/test/test_socket.py | 44 +++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -283,6 +283,50 @@ self.assertRaises(socket.error, raise_gaierror, "Error raising socket exception.") + def testSendtoErrors(self): + # Testing that sendto doens't masks failures. See #10169. + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.addCleanup(s.close) + s.bind(('', 0)) + sockname = s.getsockname() + # 2 args + with self.assertRaises(TypeError) as cm: + s.sendto('\u2620', sockname) + self.assertEqual(str(cm.exception), + "'str' does not support the buffer interface") + with self.assertRaises(TypeError) as cm: + s.sendto(5j, sockname) + self.assertEqual(str(cm.exception), + "'complex' does not support the buffer interface") + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', None) + self.assertIn('not NoneType',str(cm.exception)) + # 3 args + with self.assertRaises(TypeError) as cm: + s.sendto('\u2620', 0, sockname) + self.assertEqual(str(cm.exception), + "'str' does not support the buffer interface") + with self.assertRaises(TypeError) as cm: + s.sendto(5j, 0, sockname) + self.assertEqual(str(cm.exception), + "'complex' does not support the buffer interface") + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', 0, None) + self.assertIn('not NoneType', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', 'bar', sockname) + self.assertIn('an integer is required', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', None, None) + self.assertIn('an integer is required', str(cm.exception)) + # wrong number of args + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo') + self.assertIn('(1 given)', str(cm.exception)) + with self.assertRaises(TypeError) as cm: + s.sendto(b'foo', 0, sockname, 4) + self.assertIn('(4 given)', str(cm.exception)) + def testCrucialConstants(self): # Testing for mission critical constants socket.AF_INET -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:35:48 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 07 May 2011 19:35:48 +0200 Subject: [Python-checkins] cpython (3.1): #12002 - ftplib's abort() method raises TypeError Message-ID: http://hg.python.org/cpython/rev/31220cd936d2 changeset: 69919:31220cd936d2 branch: 3.1 parent: 68306:12f0da000dc4 user: Giampaolo Rodola' date: Sat May 07 19:03:47 2011 +0200 summary: #12002 - ftplib's abort() method raises TypeError files: Lib/ftplib.py | 3 ++- Lib/test/test_ftplib.py | 8 ++++++++ Misc/NEWS | 2 ++ 3 files changed, 12 insertions(+), 1 deletions(-) diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -232,12 +232,13 @@ This does not follow the procedure from the RFC to send Telnet IP and Synch; that doesn't seem to work with the servers I've tried. Instead, just send the ABOR command as OOB data.''' - line = 'ABOR' + CRLF + line = b'ABOR' + B_CRLF if self.debugging > 1: print('*put urgent*', self.sanitize(line)) self.sock.sendall(line, MSG_OOB) resp = self.getmultiline() if resp[:3] not in ('426', '225', '226'): raise error_proto(resp) + return resp def sendcmd(self, cmd): '''Send a command and return the response.''' diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -42,6 +42,8 @@ def __init__(self, conn): asynchat.async_chat.__init__(self, conn) + # tells the socket to handle urgent data inline (ABOR command) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_OOBINLINE, 1) self.set_terminator(b"\r\n") self.in_buffer = [] self.dtp = None @@ -158,6 +160,9 @@ self.push('221 quit ok') self.close() + def cmd_abor(self, arg): + self.push('226 abor ok') + def cmd_stor(self, arg): self.push('125 stor ok') @@ -312,6 +317,9 @@ # Ensure the connection gets closed; sock attribute should be None self.assertEqual(self.client.sock, None) + def test_abort(self): + self.client.abort() + def test_retrbinary(self): def callback(data): received.append(data.decode('ascii')) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,8 @@ Library ------- +- Issue #12002: ftplib's abort() method raises TypeError. + - Issue #11391: Writing to a mmap object created with ``mmap.PROT_READ|mmap.PROT_EXEC`` would segfault instead of raising a TypeError. Patch by Charles-Fran?ois Natali. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:35:49 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 07 May 2011 19:35:49 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge with 3.1 Message-ID: http://hg.python.org/cpython/rev/de411da2dbdb changeset: 69920:de411da2dbdb branch: 3.2 parent: 69917:4b3352b49483 parent: 69919:31220cd936d2 user: Giampaolo Rodola' date: Sat May 07 19:09:34 2011 +0200 summary: merge with 3.1 files: Lib/ftplib.py | 12 +++++++++++- Lib/test/test_ftplib.py | 8 ++++++++ Misc/NEWS | 2 ++ 3 files changed, 21 insertions(+), 1 deletions(-) diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -241,12 +241,13 @@ This does not follow the procedure from the RFC to send Telnet IP and Synch; that doesn't seem to work with the servers I've tried. Instead, just send the ABOR command as OOB data.''' - line = 'ABOR' + CRLF + line = b'ABOR' + B_CRLF if self.debugging > 1: print('*put urgent*', self.sanitize(line)) self.sock.sendall(line, MSG_OOB) resp = self.getmultiline() if resp[:3] not in {'426', '225', '226'}: raise error_proto(resp) + return resp def sendcmd(self, cmd): '''Send a command and return the response.''' @@ -781,6 +782,15 @@ conn.close() return self.voidresp() + def abort(self): + # overridden as we can't pass MSG_OOB flag to sendall() + line = b'ABOR' + B_CRLF + self.sock.sendall(line) + resp = self.getmultiline() + if resp[:3] not in {'426', '225', '226'}: + raise error_proto(resp) + return resp + __all__.append('FTP_TLS') all_errors = (Error, IOError, EOFError, ssl.SSLError) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -61,6 +61,8 @@ def __init__(self, conn): asynchat.async_chat.__init__(self, conn) + # tells the socket to handle urgent data inline (ABOR command) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_OOBINLINE, 1) self.set_terminator(b"\r\n") self.in_buffer = [] self.dtp = None @@ -181,6 +183,9 @@ self.push('221 quit ok') self.close() + def cmd_abor(self, arg): + self.push('226 abor ok') + def cmd_stor(self, arg): self.push('125 stor ok') @@ -491,6 +496,9 @@ # Ensure the connection gets closed; sock attribute should be None self.assertEqual(self.client.sock, None) + def test_abort(self): + self.client.abort() + def test_retrbinary(self): def callback(data): received.append(data.decode('ascii')) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,8 @@ Library ------- +- Issue #12002: ftplib's abort() method raises TypeError. + - Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to detect mtime changes by comparing to the system clock instead of to the previous value of the mtime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:35:50 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 07 May 2011 19:35:50 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge with 3.2 Message-ID: http://hg.python.org/cpython/rev/8521c06a828a changeset: 69921:8521c06a828a parent: 69918:20273f2195ba parent: 69920:de411da2dbdb user: Giampaolo Rodola' date: Sat May 07 19:11:06 2011 +0200 summary: merge with 3.2 files: Lib/ftplib.py | 12 +++++++++++- Lib/test/test_ftplib.py | 8 ++++++++ Misc/NEWS | 2 ++ 3 files changed, 21 insertions(+), 1 deletions(-) diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -247,12 +247,13 @@ This does not follow the procedure from the RFC to send Telnet IP and Synch; that doesn't seem to work with the servers I've tried. Instead, just send the ABOR command as OOB data.''' - line = 'ABOR' + CRLF + line = b'ABOR' + B_CRLF if self.debugging > 1: print('*put urgent*', self.sanitize(line)) self.sock.sendall(line, MSG_OOB) resp = self.getmultiline() if resp[:3] not in {'426', '225', '226'}: raise error_proto(resp) + return resp def sendcmd(self, cmd): '''Send a command and return the response.''' @@ -816,6 +817,15 @@ conn.close() return self.voidresp() + def abort(self): + # overridden as we can't pass MSG_OOB flag to sendall() + line = b'ABOR' + B_CRLF + self.sock.sendall(line) + resp = self.getmultiline() + if resp[:3] not in {'426', '225', '226'}: + raise error_proto(resp) + return resp + __all__.append('FTP_TLS') all_errors = (Error, IOError, EOFError, ssl.SSLError) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -81,6 +81,8 @@ def __init__(self, conn): asynchat.async_chat.__init__(self, conn) + # tells the socket to handle urgent data inline (ABOR command) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_OOBINLINE, 1) self.set_terminator(b"\r\n") self.in_buffer = [] self.dtp = None @@ -202,6 +204,9 @@ self.push('221 quit ok') self.close() + def cmd_abor(self, arg): + self.push('226 abor ok') + def cmd_stor(self, arg): self.push('125 stor ok') @@ -520,6 +525,9 @@ # Ensure the connection gets closed; sock attribute should be None self.assertEqual(self.client.sock, None) + def test_abort(self): + self.client.abort() + def test_retrbinary(self): def callback(data): received.append(data.decode('ascii')) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,8 @@ Library ------- +- Issue #12002: ftplib's abort() method raises TypeError. + - Issue 11916: Add a number of MacOSX specific definitions to the errno module. Patch by Pierre Carrier. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:35:51 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 07 May 2011 19:35:51 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): merge Message-ID: http://hg.python.org/cpython/rev/ae992fc99e91 changeset: 69922:ae992fc99e91 branch: 3.1 parent: 69916:9222c9d747c1 parent: 69919:31220cd936d2 user: Giampaolo Rodola' date: Sat May 07 19:35:36 2011 +0200 summary: merge files: Lib/ftplib.py | 3 ++- Lib/test/test_ftplib.py | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -232,12 +232,13 @@ This does not follow the procedure from the RFC to send Telnet IP and Synch; that doesn't seem to work with the servers I've tried. Instead, just send the ABOR command as OOB data.''' - line = 'ABOR' + CRLF + line = b'ABOR' + B_CRLF if self.debugging > 1: print('*put urgent*', self.sanitize(line)) self.sock.sendall(line, MSG_OOB) resp = self.getmultiline() if resp[:3] not in ('426', '225', '226'): raise error_proto(resp) + return resp def sendcmd(self, cmd): '''Send a command and return the response.''' diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -42,6 +42,8 @@ def __init__(self, conn): asynchat.async_chat.__init__(self, conn) + # tells the socket to handle urgent data inline (ABOR command) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_OOBINLINE, 1) self.set_terminator(b"\r\n") self.in_buffer = [] self.dtp = None @@ -158,6 +160,9 @@ self.push('221 quit ok') self.close() + def cmd_abor(self, arg): + self.push('226 abor ok') + def cmd_stor(self, arg): self.push('125 stor ok') @@ -312,6 +317,9 @@ # Ensure the connection gets closed; sock attribute should be None self.assertEqual(self.client.sock, None) + def test_abort(self): + self.client.abort() + def test_retrbinary(self): def callback(data): received.append(data.decode('ascii')) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:48:50 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 07 May 2011 19:48:50 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Message-ID: http://hg.python.org/cpython/rev/20e9d3e49689 changeset: 69923:20e9d3e49689 branch: 3.1 parent: 69916:9222c9d747c1 user: Antoine Pitrou date: Sat May 07 19:39:37 2011 +0200 summary: Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Kasun Herath. files: Lib/smtplib.py | 6 ++++-- Lib/test/test_smtpnet.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -219,6 +219,7 @@ ehlo_msg = "ehlo" ehlo_resp = None does_esmtp = 0 + default_port = SMTP_PORT def __init__(self, host='', port=0, local_hostname=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): @@ -234,7 +235,6 @@ """ self.timeout = timeout self.esmtp_features = {} - self.default_port = SMTP_PORT if host: (code, msg) = self.connect(host, port) if code != 220: @@ -749,13 +749,15 @@ are also optional - they can contain a PEM formatted private key and certificate chain file for the SSL connection. """ + + default_port = SMTP_SSL_PORT + def __init__(self, host='', port=0, local_hostname=None, keyfile=None, certfile=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): self.keyfile = keyfile self.certfile = certfile SMTP.__init__(self, host, port, local_hostname, timeout) - self.default_port = SMTP_SSL_PORT def _get_socket(self, host, port, timeout): if self.debuglevel > 0: print('connect:', (host, port), file=stderr) diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -17,6 +17,13 @@ server.ehlo() server.quit() + def test_connect_default_port(self): + support.get_attribute(smtplib, 'SMTP_SSL') + with support.transient_internet(self.testServer): + server = smtplib.SMTP_SSL(self.testServer) + server.ehlo() + server.quit() + def test_main(): support.run_unittest(SmtpSSLTest) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -335,6 +335,7 @@ Lance Finn Helsten Jonathan Hendry James Henstridge +Kasun Herath Chris Herborth Ivan Herman J?rgen Hermann diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,9 @@ Library ------- +- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch + by Kasun Herath. + - Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to detect mtime changes by comparing to the system clock instead of to the previous value of the mtime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:48:51 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 07 May 2011 19:48:51 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: Issue #11927: SMTP_SSL now uses port 465 by default as documented. Message-ID: http://hg.python.org/cpython/rev/209744660b92 changeset: 69924:209744660b92 branch: 3.2 parent: 69917:4b3352b49483 parent: 69923:20e9d3e49689 user: Antoine Pitrou date: Sat May 07 19:41:33 2011 +0200 summary: Merge: Issue #11927: SMTP_SSL now uses port 465 by default as documented. files: Lib/smtplib.py | 6 ++++-- Lib/test/test_smtpnet.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -231,6 +231,7 @@ ehlo_msg = "ehlo" ehlo_resp = None does_esmtp = 0 + default_port = SMTP_PORT def __init__(self, host='', port=0, local_hostname=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): @@ -246,7 +247,6 @@ """ self.timeout = timeout self.esmtp_features = {} - self.default_port = SMTP_PORT if host: (code, msg) = self.connect(host, port) if code != 220: @@ -804,13 +804,15 @@ are also optional - they can contain a PEM formatted private key and certificate chain file for the SSL connection. """ + + default_port = SMTP_SSL_PORT + def __init__(self, host='', port=0, local_hostname=None, keyfile=None, certfile=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): self.keyfile = keyfile self.certfile = certfile SMTP.__init__(self, host, port, local_hostname, timeout) - self.default_port = SMTP_SSL_PORT def _get_socket(self, host, port, timeout): if self.debuglevel > 0: diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -17,6 +17,13 @@ server.ehlo() server.quit() + def test_connect_default_port(self): + support.get_attribute(smtplib, 'SMTP_SSL') + with support.transient_internet(self.testServer): + server = smtplib.SMTP_SSL(self.testServer) + server.ehlo() + server.quit() + def test_main(): support.run_unittest(SmtpSSLTest) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -366,6 +366,7 @@ Lance Finn Helsten Jonathan Hendry James Henstridge +Kasun Herath Chris Herborth Ivan Herman J?rgen Hermann diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,9 @@ Library ------- +- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch + by Kasun Herath. + - Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to detect mtime changes by comparing to the system clock instead of to the previous value of the mtime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:48:52 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 07 May 2011 19:48:52 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: Issue #11927: SMTP_SSL now uses port 465 by default as documented. Message-ID: http://hg.python.org/cpython/rev/e708a57de190 changeset: 69925:e708a57de190 parent: 69918:20273f2195ba parent: 69924:209744660b92 user: Antoine Pitrou date: Sat May 07 19:42:39 2011 +0200 summary: Merge: Issue #11927: SMTP_SSL now uses port 465 by default as documented. files: Lib/smtplib.py | 6 ++++-- Lib/test/test_smtpnet.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -231,6 +231,7 @@ ehlo_msg = "ehlo" ehlo_resp = None does_esmtp = 0 + default_port = SMTP_PORT def __init__(self, host='', port=0, local_hostname=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): @@ -246,7 +247,6 @@ """ self.timeout = timeout self.esmtp_features = {} - self.default_port = SMTP_PORT if host: (code, msg) = self.connect(host, port) if code != 220: @@ -817,13 +817,15 @@ are also optional - they can contain a PEM formatted private key and certificate chain file for the SSL connection. """ + + default_port = SMTP_SSL_PORT + def __init__(self, host='', port=0, local_hostname=None, keyfile=None, certfile=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): self.keyfile = keyfile self.certfile = certfile SMTP.__init__(self, host, port, local_hostname, timeout) - self.default_port = SMTP_SSL_PORT def _get_socket(self, host, port, timeout): if self.debuglevel > 0: diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -17,6 +17,13 @@ server.ehlo() server.quit() + def test_connect_default_port(self): + support.get_attribute(smtplib, 'SMTP_SSL') + with support.transient_internet(self.testServer): + server = smtplib.SMTP_SSL(self.testServer) + server.ehlo() + server.quit() + def test_main(): support.run_unittest(SmtpSSLTest) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -371,6 +371,7 @@ Lance Finn Helsten Jonathan Hendry James Henstridge +Kasun Herath Chris Herborth Ivan Herman J?rgen Hermann diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,9 @@ Library ------- +- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch + by Kasun Herath. + - Issue 11916: Add a number of MacOSX specific definitions to the errno module. Patch by Pierre Carrier. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:48:53 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 07 May 2011 19:48:53 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): Merge Message-ID: http://hg.python.org/cpython/rev/7884783c9145 changeset: 69926:7884783c9145 branch: 3.1 parent: 69923:20e9d3e49689 parent: 69922:ae992fc99e91 user: Antoine Pitrou date: Sat May 07 19:45:34 2011 +0200 summary: Merge files: Lib/ftplib.py | 3 ++- Lib/test/test_ftplib.py | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -232,12 +232,13 @@ This does not follow the procedure from the RFC to send Telnet IP and Synch; that doesn't seem to work with the servers I've tried. Instead, just send the ABOR command as OOB data.''' - line = 'ABOR' + CRLF + line = b'ABOR' + B_CRLF if self.debugging > 1: print('*put urgent*', self.sanitize(line)) self.sock.sendall(line, MSG_OOB) resp = self.getmultiline() if resp[:3] not in ('426', '225', '226'): raise error_proto(resp) + return resp def sendcmd(self, cmd): '''Send a command and return the response.''' diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -42,6 +42,8 @@ def __init__(self, conn): asynchat.async_chat.__init__(self, conn) + # tells the socket to handle urgent data inline (ABOR command) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_OOBINLINE, 1) self.set_terminator(b"\r\n") self.in_buffer = [] self.dtp = None @@ -158,6 +160,9 @@ self.push('221 quit ok') self.close() + def cmd_abor(self, arg): + self.push('226 abor ok') + def cmd_stor(self, arg): self.push('125 stor ok') @@ -312,6 +317,9 @@ # Ensure the connection gets closed; sock attribute should be None self.assertEqual(self.client.sock, None) + def test_abort(self): + self.client.abort() + def test_retrbinary(self): def callback(data): received.append(data.decode('ascii')) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:48:56 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 07 May 2011 19:48:56 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): Merge Message-ID: http://hg.python.org/cpython/rev/a1158371956e changeset: 69927:a1158371956e branch: 3.2 parent: 69920:de411da2dbdb parent: 69924:209744660b92 user: Antoine Pitrou date: Sat May 07 19:47:24 2011 +0200 summary: Merge files: Lib/smtplib.py | 6 ++++-- Lib/test/test_smtpnet.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -231,6 +231,7 @@ ehlo_msg = "ehlo" ehlo_resp = None does_esmtp = 0 + default_port = SMTP_PORT def __init__(self, host='', port=0, local_hostname=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): @@ -246,7 +247,6 @@ """ self.timeout = timeout self.esmtp_features = {} - self.default_port = SMTP_PORT if host: (code, msg) = self.connect(host, port) if code != 220: @@ -804,13 +804,15 @@ are also optional - they can contain a PEM formatted private key and certificate chain file for the SSL connection. """ + + default_port = SMTP_SSL_PORT + def __init__(self, host='', port=0, local_hostname=None, keyfile=None, certfile=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): self.keyfile = keyfile self.certfile = certfile SMTP.__init__(self, host, port, local_hostname, timeout) - self.default_port = SMTP_SSL_PORT def _get_socket(self, host, port, timeout): if self.debuglevel > 0: diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -17,6 +17,13 @@ server.ehlo() server.quit() + def test_connect_default_port(self): + support.get_attribute(smtplib, 'SMTP_SSL') + with support.transient_internet(self.testServer): + server = smtplib.SMTP_SSL(self.testServer) + server.ehlo() + server.quit() + def test_main(): support.run_unittest(SmtpSSLTest) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -366,6 +366,7 @@ Lance Finn Helsten Jonathan Hendry James Henstridge +Kasun Herath Chris Herborth Ivan Herman J?rgen Hermann diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,9 @@ Library ------- +- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch + by Kasun Herath. + - Issue #12002: ftplib's abort() method raises TypeError. - Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:48:58 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 07 May 2011 19:48:58 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge Message-ID: http://hg.python.org/cpython/rev/e3f807d52272 changeset: 69928:e3f807d52272 branch: 3.2 parent: 69927:a1158371956e parent: 69926:7884783c9145 user: Antoine Pitrou date: Sat May 07 19:47:47 2011 +0200 summary: Merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:49:00 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 07 May 2011 19:49:00 +0200 Subject: [Python-checkins] cpython (merge default -> default): Merge Message-ID: http://hg.python.org/cpython/rev/40fa46249611 changeset: 69929:40fa46249611 parent: 69925:e708a57de190 parent: 69921:8521c06a828a user: Antoine Pitrou date: Sat May 07 19:48:18 2011 +0200 summary: Merge files: Lib/ftplib.py | 12 +++++++++++- Lib/test/test_ftplib.py | 8 ++++++++ Misc/NEWS | 2 ++ 3 files changed, 21 insertions(+), 1 deletions(-) diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -247,12 +247,13 @@ This does not follow the procedure from the RFC to send Telnet IP and Synch; that doesn't seem to work with the servers I've tried. Instead, just send the ABOR command as OOB data.''' - line = 'ABOR' + CRLF + line = b'ABOR' + B_CRLF if self.debugging > 1: print('*put urgent*', self.sanitize(line)) self.sock.sendall(line, MSG_OOB) resp = self.getmultiline() if resp[:3] not in {'426', '225', '226'}: raise error_proto(resp) + return resp def sendcmd(self, cmd): '''Send a command and return the response.''' @@ -816,6 +817,15 @@ conn.close() return self.voidresp() + def abort(self): + # overridden as we can't pass MSG_OOB flag to sendall() + line = b'ABOR' + B_CRLF + self.sock.sendall(line) + resp = self.getmultiline() + if resp[:3] not in {'426', '225', '226'}: + raise error_proto(resp) + return resp + __all__.append('FTP_TLS') all_errors = (Error, IOError, EOFError, ssl.SSLError) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -81,6 +81,8 @@ def __init__(self, conn): asynchat.async_chat.__init__(self, conn) + # tells the socket to handle urgent data inline (ABOR command) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_OOBINLINE, 1) self.set_terminator(b"\r\n") self.in_buffer = [] self.dtp = None @@ -202,6 +204,9 @@ self.push('221 quit ok') self.close() + def cmd_abor(self, arg): + self.push('226 abor ok') + def cmd_stor(self, arg): self.push('125 stor ok') @@ -520,6 +525,9 @@ # Ensure the connection gets closed; sock attribute should be None self.assertEqual(self.client.sock, None) + def test_abort(self): + self.client.abort() + def test_retrbinary(self): def callback(data): received.append(data.decode('ascii')) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -143,6 +143,8 @@ - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Kasun Herath. +- Issue #12002: ftplib's abort() method raises TypeError. + - Issue 11916: Add a number of MacOSX specific definitions to the errno module. Patch by Pierre Carrier. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:49:04 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 07 May 2011 19:49:04 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge Message-ID: http://hg.python.org/cpython/rev/6aea90327020 changeset: 69930:6aea90327020 parent: 69929:40fa46249611 parent: 69928:e3f807d52272 user: Antoine Pitrou date: Sat May 07 19:48:40 2011 +0200 summary: Merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 19:59:37 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 07 May 2011 19:59:37 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Message-ID: http://hg.python.org/cpython/rev/bcf04ced5ef1 changeset: 69931:bcf04ced5ef1 branch: 2.7 parent: 69915:7c3a20b5943a user: Antoine Pitrou date: Sat May 07 19:59:33 2011 +0200 summary: Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Kasun Herath. files: Lib/smtplib.py | 6 ++++-- Lib/test/test_smtpnet.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -222,6 +222,7 @@ ehlo_msg = "ehlo" ehlo_resp = None does_esmtp = 0 + default_port = SMTP_PORT def __init__(self, host='', port=0, local_hostname=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): @@ -237,7 +238,6 @@ """ self.timeout = timeout self.esmtp_features = {} - self.default_port = SMTP_PORT if host: (code, msg) = self.connect(host, port) if code != 220: @@ -756,13 +756,15 @@ are also optional - they can contain a PEM formatted private key and certificate chain file for the SSL connection. """ + + default_port = SMTP_SSL_PORT + def __init__(self, host='', port=0, local_hostname=None, keyfile=None, certfile=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): self.keyfile = keyfile self.certfile = certfile SMTP.__init__(self, host, port, local_hostname, timeout) - self.default_port = SMTP_SSL_PORT def _get_socket(self, host, port, timeout): if self.debuglevel > 0: diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -17,6 +17,13 @@ server.ehlo() server.quit() + def test_connect_default_port(self): + test_support.get_attribute(smtplib, 'SMTP_SSL') + with test_support.transient_internet(self.testServer): + server = smtplib.SMTP_SSL(self.testServer) + server.ehlo() + server.quit() + def test_main(): test_support.run_unittest(SmtpSSLTest) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -337,6 +337,7 @@ Lance Finn Helsten Jonathan Hendry James Henstridge +Kasun Herath Chris Herborth Ivan Herman J?rgen Hermann diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -77,6 +77,9 @@ Library ------- +- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch + by Kasun Herath. + - Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to detect mtime changes by comparing to the system clock instead of to the previous value of the mtime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 7 23:16:51 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 07 May 2011 23:16:51 +0200 Subject: [Python-checkins] cpython (2.7): Some tests were incorrectly marked as C specific. Message-ID: http://hg.python.org/cpython/rev/a8b82c283524 changeset: 69932:a8b82c283524 branch: 2.7 user: Raymond Hettinger date: Sat May 07 14:16:42 2011 -0700 summary: Some tests were incorrectly marked as C specific. files: Lib/test/test_heapq.py | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -305,8 +305,6 @@ return chain(imap(lambda x:x, R(Ig(G(seqn))))) class TestErrorHandling(unittest.TestCase): - # only for C implementation - module = c_heapq def test_non_sequence(self): for f in (self.module.heapify, self.module.heappop): @@ -351,12 +349,19 @@ self.assertRaises(TypeError, f, 2, N(s)) self.assertRaises(ZeroDivisionError, f, 2, E(s)) +class TestErrorHandling_Python(unittest.TestCase): + module = py_heapq + +class TestErrorHandling_C(TestErrorHandling): + module = c_heapq + #============================================================================== def test_main(verbose=None): - test_classes = [TestHeapPython, TestHeapC, TestErrorHandling] + test_classes = [TestHeapPython, TestHeapC, TestErrorHandling_Python, + TestErrorHandling_C] test_support.run_unittest(*test_classes) # verify reference counting -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 00:19:41 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 08 May 2011 00:19:41 +0200 Subject: [Python-checkins] cpython (2.7): Fix cut and paste error. Message-ID: http://hg.python.org/cpython/rev/dd2639508dfe changeset: 69933:dd2639508dfe branch: 2.7 user: Raymond Hettinger date: Sat May 07 15:19:34 2011 -0700 summary: Fix cut and paste error. files: Lib/test/test_heapq.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -349,7 +349,7 @@ self.assertRaises(TypeError, f, 2, N(s)) self.assertRaises(ZeroDivisionError, f, 2, E(s)) -class TestErrorHandling_Python(unittest.TestCase): +class TestErrorHandling_Python(TestErrorHandling): module = py_heapq class TestErrorHandling_C(TestErrorHandling): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 01:48:29 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 08 May 2011 01:48:29 +0200 Subject: [Python-checkins] cpython: Issue #8407: Add pthread_kill(), sigpending() and sigwait() functions to the Message-ID: http://hg.python.org/cpython/rev/1d8a57deddc4 changeset: 69934:1d8a57deddc4 parent: 69930:6aea90327020 user: Victor Stinner date: Sun May 08 01:46:11 2011 +0200 summary: Issue #8407: Add pthread_kill(), sigpending() and sigwait() functions to the signal module. files: Doc/library/os.rst | 2 + Doc/library/signal.rst | 53 ++++++++++ Doc/whatsnew/3.3.rst | 9 +- Lib/test/test_signal.py | 141 +++++++++++++++++++++------ Misc/NEWS | 3 + Modules/signalmodule.c | 102 +++++++++++++++++++- configure | 5 +- configure.in | 5 +- pyconfig.h.in | 9 + 9 files changed, 287 insertions(+), 42 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2284,6 +2284,8 @@ will be set to *sig*. The Windows version of :func:`kill` additionally takes process handles to be killed. + See also :func:`signal.pthread_kill`. + .. versionadded:: 3.2 Windows support. diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -179,6 +179,29 @@ will then be called. Returns nothing. Not on Windows. (See the Unix man page :manpage:`signal(2)`.) + See also :func:`sigwait` and :func:`sigpending`. + + +.. function:: pthread_kill(thread_id, signum) + + Send the signal *signum* to the thread *thread_id*, another thread in the same + process as the caller. The signal is asynchronously directed to thread. + + *thread_id* can be read from the :attr:`~threading.Thread.ident` attribute + of :attr:`threading.Thread`. For example, + ``threading.current_thread().ident`` gives the identifier of the current + thread. + + If *signum* is 0, then no signal is sent, but error checking is still + performed; this can be used to check if a thread is still running. + + Availability: Unix (see the man page :manpage:`pthread_kill(3)` for further + information). + + See also :func:`os.kill`. + + .. versionadded:: 3.3 + .. function:: pthread_sigmask(how, mask) @@ -206,6 +229,8 @@ Availability: Unix. See the man page :manpage:`sigprocmask(3)` and :manpage:`pthread_sigmask(3)` for further information. + See also :func:`pause`, :func:`sigpending` and :func:`sigwait`. + .. versionadded:: 3.3 @@ -283,6 +308,34 @@ :const:`SIGTERM`. A :exc:`ValueError` will be raised in any other case. +.. function:: sigpending() + + Examine the set of signals that are pending for delivery to the calling + thread (i.e., the signals which have been raised while blocked). Return the + set of the pending signals. + + Availability: Unix (see the man page :manpage:`sigpending(2)` for further + information). + + See also :func:`pause`, :func:`pthread_sigmask` and :func:`sigwait`. + + .. versionadded:: 3.3 + + +.. function:: sigwait(sigset) + + Suspend execution of the calling thread until the delivery of one of the + signals specified in the signal set *sigset*. The function accepts the signal + (removes it from the pending list of signals), and returns the signal number. + + Availability: Unix (see the man page :manpage:`sigwait(3)` for further + information). + + See also :func:`pause`, :func:`pthread_sigmask` and :func:`sigpending`. + + .. versionadded:: 3.3 + + .. _signal-example: Example diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -123,10 +123,13 @@ signal ------ -* The :mod:`signal` module has a new :func:`~signal.pthread_sigmask` function - to fetch and/or change the signal mask of the calling thread. +* The :mod:`signal` module has a new functions: - (Contributed by Jean-Paul Calderone in :issue:`8407`) + * :func:`~signal.pthread_sigmask`: fetch and/or change the signal mask of the + calling thread (Contributed by Jean-Paul Calderone in :issue:`8407`) ; + * :func:`~signal.pthread_kill`: send a signal to a thread ; + * :func:`~signal.sigpending`: examine pending functions ; + * :func:`~signal.sigwait`: wait a signal. Optimizations diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -8,6 +8,10 @@ import subprocess import traceback import sys, os, time, errno +try: + import threading +except ImportError: + threading = None if sys.platform in ('os2', 'riscos'): raise unittest.SkipTest("Can't test signal on %s" % sys.platform) @@ -187,7 +191,7 @@ @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") -class BasicSignalTests(unittest.TestCase): +class PosixTests(unittest.TestCase): def trivial_signal_handler(self, *args): pass @@ -484,50 +488,121 @@ self.assertEqual(self.hndl_called, True) - at unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), - 'need signal.pthread_sigmask()') class PendingSignalsTests(unittest.TestCase): """ - Tests for the pthread_sigmask() function. + Test pthread_sigmask(), pthread_kill(), sigpending() and sigwait() + functions. """ + def setUp(self): + self.has_pthread_kill = hasattr(signal, 'pthread_kill') + def handler(self, signum, frame): 1/0 def read_sigmask(self): return signal.pthread_sigmask(signal.SIG_BLOCK, []) - def test_pthread_sigmask_arguments(self): - self.assertRaises(TypeError, signal.pthread_sigmask) - self.assertRaises(TypeError, signal.pthread_sigmask, 1) - self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3) - self.assertRaises(RuntimeError, signal.pthread_sigmask, 1700, []) + def can_test_blocked_signals(self, skip): + """ + Check if a blocked signal can be raised to the main thread without + calling its signal handler. We need pthread_kill() or exactly one + thread (the main thread). - def test_pthread_sigmask(self): - import faulthandler - pid = os.getpid() - signum = signal.SIGUSR1 + Return True if it's possible. Otherwise, return False and print a + warning if skip is False, or raise a SkipTest exception if skip is + True. + """ + if self.has_pthread_kill: + return True # The fault handler timeout thread masks all signals. If the main # thread masks also SIGUSR1, all threads mask this signal. In this # case, if we send SIGUSR1 to the process, the signal is pending in the # main or the faulthandler timeout thread. Unblock SIGUSR1 in the main # thread calls the signal handler only if the signal is pending for the - # main thread. - # - # Stop the faulthandler timeout thread to workaround this problem. - # Another solution would be to send the signal directly to the main - # thread using pthread_kill(), but Python doesn't expose this - # function. + # main thread. Stop the faulthandler timeout thread to workaround this + # problem. + import faulthandler faulthandler.cancel_dump_tracebacks_later() - # Issue #11998: The _tkinter module loads the Tcl library which creates - # a thread waiting events in select(). This thread receives signals - # blocked by all other threads. We cannot test blocked signals if the - # _tkinter module is loaded. - can_test_blocked_signals = ('_tkinter' not in sys.modules) - if not can_test_blocked_signals: - print("WARNING: _tkinter is loaded, cannot test signals " - "blocked by pthread_sigmask() (issue #11998)") + # Issue #11998: The _tkinter module loads the Tcl library which + # creates a thread waiting events in select(). This thread receives + # signals blocked by all other threads. We cannot test blocked + # signals + if '_tkinter' in sys.modules: + message = ("_tkinter is loaded and pthread_kill() is missing, " + "cannot test blocked signals (issue #11998)") + if skip: + self.skipTest(message) + else: + print("WARNING: %s" % message) + return False + return True + + def kill(self, signum): + if self.has_pthread_kill: + tid = threading.current_thread().ident + signal.pthread_kill(tid, signum) + else: + pid = os.getpid() + os.kill(pid, signum) + + @unittest.skipUnless(hasattr(signal, 'sigpending'), + 'need signal.sigpending()') + def test_sigpending_empty(self): + self.assertEqual(signal.sigpending(), set()) + + @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), + 'need signal.pthread_sigmask()') + @unittest.skipUnless(hasattr(signal, 'sigpending'), + 'need signal.sigpending()') + def test_sigpending(self): + self.can_test_blocked_signals(True) + + signum = signal.SIGUSR1 + old_handler = signal.signal(signum, self.handler) + self.addCleanup(signal.signal, signum, old_handler) + + signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) + self.kill(signum) + self.assertEqual(signal.sigpending(), {signum}) + with self.assertRaises(ZeroDivisionError): + signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + + @unittest.skipUnless(hasattr(signal, 'pthread_kill'), + 'need signal.pthread_kill()') + def test_pthread_kill(self): + signum = signal.SIGUSR1 + current = threading.current_thread().ident + + old_handler = signal.signal(signum, self.handler) + self.addCleanup(signal.signal, signum, old_handler) + + with self.assertRaises(ZeroDivisionError): + signal.pthread_kill(current, signum) + + @unittest.skipUnless(hasattr(signal, 'sigwait'), + 'need signal.sigwait()') + def test_sigwait(self): + old_handler = signal.signal(signal.SIGALRM, self.handler) + self.addCleanup(signal.signal, signal.SIGALRM, old_handler) + + signal.alarm(1) + self.assertEqual(signal.sigwait([signal.SIGALRM]), signal.SIGALRM) + + @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), + 'need signal.pthread_sigmask()') + def test_pthread_sigmask_arguments(self): + self.assertRaises(TypeError, signal.pthread_sigmask) + self.assertRaises(TypeError, signal.pthread_sigmask, 1) + self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3) + self.assertRaises(OSError, signal.pthread_sigmask, 1700, []) + + @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), + 'need signal.pthread_sigmask()') + def test_pthread_sigmask(self): + test_blocked_signals = self.can_test_blocked_signals(False) + signum = signal.SIGUSR1 # Install our signal handler old_handler = signal.signal(signum, self.handler) @@ -537,13 +612,13 @@ old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, old_mask) with self.assertRaises(ZeroDivisionError): - os.kill(pid, signum) + self.kill(signum) # Block and then raise SIGUSR1. The signal is blocked: the signal # handler is not called, and the signal is now pending signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) - if can_test_blocked_signals: - os.kill(pid, signum) + if test_blocked_signals: + self.kill(signum) # Check the new mask blocked = self.read_sigmask() @@ -551,14 +626,14 @@ self.assertEqual(old_mask ^ blocked, {signum}) # Unblock SIGUSR1 - if can_test_blocked_signals: + if test_blocked_signals: with self.assertRaises(ZeroDivisionError): # unblock the pending signal calls immediatly the signal handler signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) else: signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) with self.assertRaises(ZeroDivisionError): - os.kill(pid, signum) + self.kill(signum) # Check the new mask unblocked = self.read_sigmask() @@ -570,7 +645,7 @@ def test_main(): try: - support.run_unittest(BasicSignalTests, InterProcessSignalTests, + support.run_unittest(PosixTests, InterProcessSignalTests, WakeupSignalTests, SiginterruptTest, ItimerTest, WindowsSignalTests, PendingSignalsTests) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,9 @@ Library ------- +- Issue #8407: Add pthread_kill(), sigpending() and sigwait() functions to the + signal module. + - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Kasun Herath. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -503,7 +503,7 @@ Returns current value of given itimer."); #endif -#ifdef PYPTHREAD_SIGMASK +#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) /* Convert an iterable to a sigset. Return 0 on success, return -1 and raise an exception on error. */ @@ -551,7 +551,9 @@ Py_XDECREF(iterator); return result; } +#endif +#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGPENDING) static PyObject* sigset_to_set(sigset_t mask) { @@ -585,7 +587,9 @@ } return result; } +#endif +#ifdef PYPTHREAD_SIGMASK static PyObject * signal_pthread_sigmask(PyObject *self, PyObject *args) { @@ -603,7 +607,7 @@ err = pthread_sigmask(how, &mask, &previous); if (err != 0) { errno = err; - PyErr_SetFromErrno(PyExc_RuntimeError); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -621,6 +625,88 @@ #endif /* #ifdef PYPTHREAD_SIGMASK */ +#ifdef HAVE_SIGPENDING +static PyObject * +signal_sigpending(PyObject *self) +{ + int err; + sigset_t mask; + err = sigpending(&mask); + if (err) + return PyErr_SetFromErrno(PyExc_OSError); + return sigset_to_set(mask); +} + +PyDoc_STRVAR(signal_sigpending_doc, +"sigpending() -> list\n\ +\n\ +Examine pending signals."); +#endif /* #ifdef HAVE_SIGPENDING */ + + +#ifdef HAVE_SIGWAIT +static PyObject * +signal_sigwait(PyObject *self, PyObject *args) +{ + PyObject *signals; + sigset_t set; + int err, signum; + + if (!PyArg_ParseTuple(args, "O:sigwait", &signals)) + return NULL; + + if (iterable_to_sigset(signals, &set)) + return NULL; + + err = sigwait(&set, &signum); + if (err) { + errno = err; + return PyErr_SetFromErrno(PyExc_OSError); + } + + return PyLong_FromLong(signum); +} + +PyDoc_STRVAR(signal_sigwait_doc, +"sigwait(sigset) -> signum\n\ +\n\ +Wait a signal."); +#endif /* #ifdef HAVE_SIGPENDING */ + + +#if defined(HAVE_PTHREAD_KILL) && defined(WITH_THREAD) +static PyObject * +signal_pthread_kill(PyObject *self, PyObject *args) +{ + long tid; + int signum; + int err; + + if (!PyArg_ParseTuple(args, "li:pthread_kill", &tid, &signum)) + return NULL; + + err = pthread_kill(tid, signum); + if (err != 0) { + errno = err; + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + /* the signal may have been send to the current thread */ + if (PyErr_CheckSignals()) + return NULL; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(signal_pthread_kill_doc, +"pthread_kill(thread_id, signum)\n\ +\n\ +Send a signal to a thread."); +#endif /* #if defined(HAVE_PTHREAD_KILL) && defined(WITH_THREAD) */ + + + /* List of functions defined in the module */ static PyMethodDef signal_methods[] = { #ifdef HAVE_ALARM @@ -644,10 +730,22 @@ #endif {"default_int_handler", signal_default_int_handler, METH_VARARGS, default_int_handler_doc}, +#if defined(HAVE_PTHREAD_KILL) && defined(WITH_THREAD) + {"pthread_kill", (PyCFunction)signal_pthread_kill, + METH_VARARGS, signal_pthread_kill_doc}, +#endif #ifdef PYPTHREAD_SIGMASK {"pthread_sigmask", (PyCFunction)signal_pthread_sigmask, METH_VARARGS, signal_pthread_sigmask_doc}, #endif +#ifdef HAVE_SIGPENDING + {"sigpending", (PyCFunction)signal_sigpending, + METH_NOARGS, signal_sigpending_doc}, +#endif +#ifdef HAVE_SIGWAIT + {"sigwait", (PyCFunction)signal_sigwait, + METH_VARARGS, signal_sigwait_doc}, +#endif {NULL, NULL} /* sentinel */ }; diff --git a/configure b/configure --- a/configure +++ b/configure @@ -9258,11 +9258,12 @@ initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \ posix_fallocate posix_fadvise pread \ - pthread_init putenv pwrite readlink readlinkat readv realpath renameat \ + pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \ select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ setgid sethostname \ setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \ - sigaction sigaltstack siginterrupt sigrelse snprintf strftime strlcpy symlinkat sync \ + sigaction sigaltstack siginterrupt sigpending \ + sigrelse sigwait snprintf strftime strlcpy symlinkat sync \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \ wcscoll wcsftime wcsxfrm writev _getpty diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -2503,11 +2503,12 @@ initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \ posix_fallocate posix_fadvise pread \ - pthread_init putenv pwrite readlink readlinkat readv realpath renameat \ + pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \ select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ setgid sethostname \ setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \ - sigaction sigaltstack siginterrupt sigrelse snprintf strftime strlcpy symlinkat sync \ + sigaction sigaltstack siginterrupt sigpending \ + sigrelse sigwait snprintf strftime strlcpy symlinkat sync \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \ wcscoll wcsftime wcsxfrm writev _getpty) diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -590,6 +590,9 @@ /* Define to 1 if you have the `pthread_sigmask' function. */ #undef HAVE_PTHREAD_SIGMASK +/* Define to 1 if you have the `pthread_kill' function. */ +#undef HAVE_PTHREAD_KILL + /* Define to 1 if you have the header file. */ #undef HAVE_PTY_H @@ -719,12 +722,18 @@ /* Define to 1 if you have the `siginterrupt' function. */ #undef HAVE_SIGINTERRUPT +/* Define to 1 if you have the `sigpending' function. */ +#undef HAVE_SIGPENDING + /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the `sigrelse' function. */ #undef HAVE_SIGRELSE +/* Define to 1 if you have the `sigwait' function. */ +#undef HAVE_SIGWAIT + /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 02:03:43 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 08 May 2011 02:03:43 +0200 Subject: [Python-checkins] cpython: Issue #8407: The signal handler writes the signal number as a single byte Message-ID: http://hg.python.org/cpython/rev/f8c49a930015 changeset: 69935:f8c49a930015 user: Victor Stinner date: Sun May 08 02:03:15 2011 +0200 summary: Issue #8407: The signal handler writes the signal number as a single byte instead of a nul byte into the wakeup file descriptor. So it is possible to wait more than one signal and know which signals were raised. files: Doc/library/signal.rst | 10 +++++++--- Doc/whatsnew/3.3.rst | 4 ++++ Lib/test/test_signal.py | 15 +++++++++++++++ Misc/NEWS | 4 ++++ Modules/signalmodule.c | 7 +++++-- 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -262,13 +262,17 @@ .. function:: set_wakeup_fd(fd) - Set the wakeup fd to *fd*. When a signal is received, a ``'\0'`` byte is - written to the fd. This can be used by a library to wakeup a poll or select - call, allowing the signal to be fully processed. + Set the wakeup file descriptor to *fd*. When a signal is received, the + signal number is written as a single byte into the fd. This can be used by + a library to wakeup a poll or select call, allowing the signal to be fully + processed. The old wakeup fd is returned. *fd* must be non-blocking. It is up to the library to remove any bytes before calling poll or select again. + Use for example ``struct.unpack('%uB' % len(data), data)`` to decode the + signal numbers list. + When threads are enabled, this function can only be called from the main thread; attempting to call it from other threads will cause a :exc:`ValueError` exception to be raised. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -131,6 +131,10 @@ * :func:`~signal.sigpending`: examine pending functions ; * :func:`~signal.sigwait`: wait a signal. +* The signal handler writes the signal number as a single byte instead of + a nul byte into the wakeup file descriptor. So it is possible to wait more + than one signal and know which signals were raised. + Optimizations ============= diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -5,6 +5,7 @@ import pickle import select import signal +import struct import subprocess import traceback import sys, os, time, errno @@ -236,6 +237,11 @@ TIMEOUT_FULL = 10 TIMEOUT_HALF = 5 + def check_signum(self, *signals): + data = os.read(self.read, len(signals)+1) + raised = struct.unpack('%uB' % len(data), data) + self.assertSequenceEqual(raised, signals) + def test_wakeup_fd_early(self): import select @@ -249,6 +255,7 @@ select.select([self.read], [], [], self.TIMEOUT_FULL) after_time = time.time() self.assertTrue(after_time - mid_time < self.TIMEOUT_HALF) + self.check_signum(signal.SIGALRM) def test_wakeup_fd_during(self): import select @@ -260,6 +267,14 @@ [self.read], [], [], self.TIMEOUT_FULL) after_time = time.time() self.assertTrue(after_time - before_time < self.TIMEOUT_HALF) + self.check_signum(signal.SIGALRM) + + def test_signum(self): + old_handler = signal.signal(signal.SIGUSR1, lambda x,y:None) + self.addCleanup(signal.signal, signal.SIGUSR1, old_handler) + os.kill(os.getpid(), signal.SIGUSR1) + os.kill(os.getpid(), signal.SIGALRM) + self.check_signum(signal.SIGUSR1, signal.SIGALRM) def setUp(self): import fcntl diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,10 @@ Library ------- +- Issue #8407: The signal handler writes the signal number as a single byte + instead of a nul byte into the wakeup file descriptor. So it is possible to + wait more than one signal and know which signals were raised. + - Issue #8407: Add pthread_kill(), sigpending() and sigwait() functions to the signal module. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -176,6 +176,7 @@ static void trip_signal(int sig_num) { + unsigned char byte; Handlers[sig_num].tripped = 1; if (is_tripped) return; @@ -183,8 +184,10 @@ cleared in PyErr_CheckSignals() before .tripped. */ is_tripped = 1; Py_AddPendingCall(checksignals_witharg, NULL); - if (wakeup_fd != -1) - write(wakeup_fd, "\0", 1); + if (wakeup_fd != -1) { + byte = (unsigned char)sig_num; + write(wakeup_fd, &byte, 1); + } } static void -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 02:10:49 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 08 May 2011 02:10:49 +0200 Subject: [Python-checkins] cpython: Issue #8407: Remove debug code from test_signal Message-ID: http://hg.python.org/cpython/rev/e3cb2c99a5a9 changeset: 69936:e3cb2c99a5a9 user: Victor Stinner date: Sun May 08 02:10:36 2011 +0200 summary: Issue #8407: Remove debug code from test_signal I don't think that we still need it. files: Lib/test/test_signal.py | 47 ++++++---------------------- 1 files changed, 10 insertions(+), 37 deletions(-) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -58,15 +58,9 @@ def handlerA(self, signum, frame): self.a_called = True - if support.verbose: - print("handlerA invoked from signal %s at:\n%s" % ( - signum, self.format_frame(frame, limit=1))) def handlerB(self, signum, frame): self.b_called = True - if support.verbose: - print ("handlerB invoked from signal %s at:\n%s" % ( - signum, self.format_frame(frame, limit=1))) raise HandlerBCalled(signum, self.format_frame(frame)) def wait(self, child): @@ -93,8 +87,6 @@ # Let the sub-processes know who to send signals to. pid = os.getpid() - if support.verbose: - print("test runner's pid is", pid) child = ignoring_eintr(subprocess.Popen, ['kill', '-HUP', str(pid)]) if child: @@ -118,8 +110,6 @@ except HandlerBCalled: self.assertTrue(self.b_called) self.assertFalse(self.a_called) - if support.verbose: - print("HandlerBCalled exception caught") child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)]) if child: @@ -135,8 +125,7 @@ # may return early. time.sleep(1) except KeyboardInterrupt: - if support.verbose: - print("KeyboardInterrupt (the alarm() went off)") + pass except: self.fail("Some other exception woke us from pause: %s" % traceback.format_exc()) @@ -359,10 +348,9 @@ return True def test_without_siginterrupt(self): - """If a signal handler is installed and siginterrupt is not called - at all, when that signal arrives, it interrupts a syscall that's in - progress. - """ + # If a signal handler is installed and siginterrupt is not called + # at all, when that signal arrives, it interrupts a syscall that's in + # progress. i = self.readpipe_interrupted() self.assertTrue(i) # Arrival of the signal shouldn't have changed anything. @@ -370,10 +358,9 @@ self.assertTrue(i) def test_siginterrupt_on(self): - """If a signal handler is installed and siginterrupt is called with - a true value for the second argument, when that signal arrives, it - interrupts a syscall that's in progress. - """ + # If a signal handler is installed and siginterrupt is called with + # a true value for the second argument, when that signal arrives, it + # interrupts a syscall that's in progress. signal.siginterrupt(self.signum, 1) i = self.readpipe_interrupted() self.assertTrue(i) @@ -382,10 +369,9 @@ self.assertTrue(i) def test_siginterrupt_off(self): - """If a signal handler is installed and siginterrupt is called with - a false value for the second argument, when that signal arrives, it - does not interrupt a syscall that's in progress. - """ + # If a signal handler is installed and siginterrupt is called with + # a false value for the second argument, when that signal arrives, it + # does not interrupt a syscall that's in progress. signal.siginterrupt(self.signum, 0) i = self.readpipe_interrupted() self.assertFalse(i) @@ -410,8 +396,6 @@ def sig_alrm(self, *args): self.hndl_called = True - if support.verbose: - print("SIGALRM handler invoked", args) def sig_vtalrm(self, *args): self.hndl_called = True @@ -423,21 +407,13 @@ elif self.hndl_count == 3: # disable ITIMER_VIRTUAL, this function shouldn't be called anymore signal.setitimer(signal.ITIMER_VIRTUAL, 0) - if support.verbose: - print("last SIGVTALRM handler call") self.hndl_count += 1 - if support.verbose: - print("SIGVTALRM handler invoked", args) - def sig_prof(self, *args): self.hndl_called = True signal.setitimer(signal.ITIMER_PROF, 0) - if support.verbose: - print("SIGPROF handler invoked", args) - def test_itimer_exc(self): # XXX I'm assuming -1 is an invalid itimer, but maybe some platform # defines it ? @@ -450,10 +426,7 @@ def test_itimer_real(self): self.itimer = signal.ITIMER_REAL signal.setitimer(self.itimer, 1.0) - if support.verbose: - print("\ncall pause()...") signal.pause() - self.assertEqual(self.hndl_called, True) # Issue 3864, unknown if this affects earlier versions of freebsd also -- Repository URL: http://hg.python.org/cpython From nnorwitz at gmail.com Sun May 8 02:36:53 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Sat, 7 May 2011 20:36:53 -0400 Subject: [Python-checkins] Python Regression Test Failures doc (1) Message-ID: <20110508003653.GA5280@kbk-i386-bb.dyndns.org> rm -rf build/* rm -rf tools/sphinx rm -rf tools/pygments rm -rf tools/jinja2 rm -rf tools/docutils Checking out Sphinx... A tools/sphinx/jinja2glue.py A tools/sphinx/quickstart.py A tools/sphinx/theming.py A tools/sphinx/pycode A tools/sphinx/pycode/nodes.py A tools/sphinx/pycode/Grammar.txt A tools/sphinx/pycode/__init__.py A tools/sphinx/pycode/pgen2 A tools/sphinx/pycode/pgen2/tokenize.py A tools/sphinx/pycode/pgen2/pgen.py A tools/sphinx/pycode/pgen2/parse.py A tools/sphinx/pycode/pgen2/driver.py A tools/sphinx/pycode/pgen2/__init__.py A tools/sphinx/pycode/pgen2/literals.py A tools/sphinx/pycode/pgen2/token.py A tools/sphinx/pycode/pgen2/grammar.py A tools/sphinx/themes A tools/sphinx/themes/sphinxdoc A tools/sphinx/themes/sphinxdoc/layout.html A tools/sphinx/themes/sphinxdoc/theme.conf A tools/sphinx/themes/sphinxdoc/static A tools/sphinx/themes/sphinxdoc/static/contents.png A tools/sphinx/themes/sphinxdoc/static/navigation.png A tools/sphinx/themes/sphinxdoc/static/sphinxdoc.css A tools/sphinx/themes/basic A tools/sphinx/themes/basic/page.html A tools/sphinx/themes/basic/layout.html A tools/sphinx/themes/basic/genindex-single.html A tools/sphinx/themes/basic/genindex.html A tools/sphinx/themes/basic/opensearch.xml A tools/sphinx/themes/basic/theme.conf A tools/sphinx/themes/basic/static A tools/sphinx/themes/basic/static/doctools.js A tools/sphinx/themes/basic/static/searchtools.js A tools/sphinx/themes/basic/static/file.png A tools/sphinx/themes/basic/static/plus.png A tools/sphinx/themes/basic/static/basic.css A tools/sphinx/themes/basic/static/jquery.js A tools/sphinx/themes/basic/static/minus.png A tools/sphinx/themes/basic/changes A tools/sphinx/themes/basic/changes/versionchanges.html A tools/sphinx/themes/basic/changes/frameset.html A tools/sphinx/themes/basic/changes/rstsource.html A tools/sphinx/themes/basic/search.html A tools/sphinx/themes/basic/defindex.html A tools/sphinx/themes/basic/modindex.html A tools/sphinx/themes/basic/genindex-split.html A tools/sphinx/themes/default A tools/sphinx/themes/default/theme.conf A tools/sphinx/themes/default/static A tools/sphinx/themes/default/static/default.css_t A tools/sphinx/themes/traditional A tools/sphinx/themes/traditional/theme.conf A tools/sphinx/themes/traditional/static A tools/sphinx/themes/traditional/static/traditional.css A tools/sphinx/setup_command.py A tools/sphinx/__init__.py A tools/sphinx/application.py A tools/sphinx/environment.py A tools/sphinx/search.py A tools/sphinx/config.py A tools/sphinx/highlighting.py A tools/sphinx/writers A tools/sphinx/writers/latex.py A tools/sphinx/writers/__init__.py A tools/sphinx/writers/html.py A tools/sphinx/writers/text.py A tools/sphinx/locale A tools/sphinx/locale/__init__.py A tools/sphinx/locale/ru A tools/sphinx/locale/ru/LC_MESSAGES A tools/sphinx/locale/ru/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/ru/LC_MESSAGES/sphinx.js A tools/sphinx/locale/ru/LC_MESSAGES/sphinx.po A tools/sphinx/locale/de A tools/sphinx/locale/de/LC_MESSAGES A tools/sphinx/locale/de/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/de/LC_MESSAGES/sphinx.js A tools/sphinx/locale/de/LC_MESSAGES/sphinx.po A tools/sphinx/locale/ja A tools/sphinx/locale/ja/LC_MESSAGES A tools/sphinx/locale/ja/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/ja/LC_MESSAGES/sphinx.js A tools/sphinx/locale/ja/LC_MESSAGES/sphinx.po A tools/sphinx/locale/zh_TW A tools/sphinx/locale/zh_TW/LC_MESSAGES A tools/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js A tools/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po A tools/sphinx/locale/fi A tools/sphinx/locale/fi/LC_MESSAGES A tools/sphinx/locale/fi/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/fi/LC_MESSAGES/sphinx.js A tools/sphinx/locale/fi/LC_MESSAGES/sphinx.po A tools/sphinx/locale/uk_UA A tools/sphinx/locale/uk_UA/LC_MESSAGES A tools/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/uk_UA/LC_Msvn: REPORT request failed on '/projects/!svn/vcc/default' svn: REPORT of '/projects/!svn/vcc/default': Could not read response body: connection timed out. (http://svn.python.org) ESSAGES/sphinx.js A tools/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po A tools/sphinx/locale/cs A tools/sphinx/locale/cs/LC_MESSAGES A tools/sphinx/locale/cs/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/cs/LC_MESSAGES/sphinx.js A tools/sphinx/locale/cs/LC_MESSAGES/sphinx.po A tools/sphinx/locale/pt_BR A tools/sphinx/locale/pt_BR/LC_MESSAGES A tools/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js A tools/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po A tools/sphinx/locale/es A tools/sphinx/locale/es/LC_MESSAGES A tools/sphinx/locale/es/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/es/LC_MESSAGES/sphinx.js A tools/sphinx/locale/es/LC_MESSAGES/sphinx.po A tools/sphinx/locale/fr A tools/sphinx/locale/fr/LC_MESSAGES A tools/sphinx/locale/fr/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/fr/LC_MESSAGES/sphinx.js A tools/sphinx/locale/fr/LC_MESSAGES/sphinx.po A tools/sphinx/locale/nl A tools/sphinx/locale/nl/LC_MESSAGES A tools/sphinx/locale/nl/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/nl/LC_MESSAGES/sphinx.js A tools/sphinx/locale/nl/LC_MESSAGES/sphinx.po A tools/sphinx/locale/sphinx.pot A tools/sphinx/locale/pl A tools/sphinx/locale/pl/LC_MESSAGES A tools/sphinx/locale/pl/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/pl/LC_MESSAGES/sphinx.js A tools/sphinx/locale/pl/LC_MESSAGES/sphinx.po A tools/sphinx/locale/it A tools/sphinx/locale/it/LC_MESSAGES A tools/sphinx/locale/it/LC_MESSAGES/sphinx.mo A tools/sphinx/locale/it/LC_MESSAGES/sphinx.js make: *** [checkout] Error 1 From solipsis at pitrou.net Sun May 8 04:58:52 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 08 May 2011 04:58:52 +0200 Subject: [Python-checkins] Daily reference leaks (e3cb2c99a5a9): sum=0 Message-ID: results for e3cb2c99a5a9 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogk1PGLQ', '-x'] From python-checkins at python.org Sun May 8 09:05:49 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 08 May 2011 09:05:49 +0200 Subject: [Python-checkins] release: Initial hg fixup: replace all references to "svn" with hopefully correct Message-ID: http://hg.python.org/release/rev/8940e710382e changeset: 55:8940e710382e user: Georg Brandl date: Sun May 08 09:05:45 2011 +0200 summary: Initial hg fixup: replace all references to "svn" with hopefully correct counterparts. files: release.py | 39 ++++++++++++--------------------------- 1 files changed, 12 insertions(+), 27 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -15,7 +15,6 @@ import shutil from contextlib import contextmanager -from urllib.parse import urlsplit, urlunsplit COMMASPACE = ', ' SPACE = ' ' @@ -50,8 +49,8 @@ if 'EDITOR' not in os.environ: error('editor not detected.', 'Please set your EDITOR enviroment variable') - if not os.path.exists('.svn'): - error('CWD is not a Subversion checkout') + if not os.path.exists('.hg'): + error('CWD is not a Mercurial clone') def get_arg_parser(): @@ -62,7 +61,7 @@ help='bump the revision number in important files') p.add_option('-e', '--export', default=False, action='store_true', - help='Export the SVN tag to a tarball and build docs') + help='Export the hg tag to a tarball and build docs') p.add_option('-u', '--upload', metavar="username", help='Upload the tarballs and docs to dinsdale') p.add_option('-m', '--branch', @@ -140,9 +139,9 @@ break full_path = os.path.join('Misc/RPM/', file) print('\nrenaming %s to %s' % (full_path, wanted_file)) - run_cmd(['svn', 'rename', '--force', full_path, wanted_file]) + run_cmd(['hg', 'rename', '--force', full_path, wanted_file]) print('File was renamed; please commit') - run_cmd(['svn', 'commit']) + run_cmd(['hg', 'commit']) new = '%define version ' + tag.text + \ '\n%define libvers ' + tag.basic_version constant_replace(wanted_file, new, '#', '') @@ -258,9 +257,7 @@ with changed_dir(tag.text): print('Exporting tag:', tag.text) archivename = 'Python-%s' % tag.text - run_cmd(['svn', 'export', '-q', - 'http://svn.python.org/projects/python/tags/r%s' - % tag.nickname, archivename]) + run_cmd(['hg', 'archive', '-r', tag.hgname, archivename]) with changed_dir(archivename): print('Removing VCS .*ignore and .hgeol') for name in ('.hgignore', '.hgeol', '.bzrignore', '.gitignore'): @@ -359,33 +356,21 @@ def nickname(self): return self.text.replace('.', '') + @property + def hgname(self): + return 'v' + self.text + def branch(tag): if tag.patch > 0 or tag.level != "f": print('It doesn\'t look like you\'re making a final release.') if input('Are you sure you want to branch?') != "y": return - url = urlsplit(get_current_location()) - new_path = 'python/branches/release%s%s-maint' % (tag.major, tag.minor) - tag_url = urlunsplit((url.scheme, url.netloc, new_path, - url.query, url.fragment)) - run_cmd(['svn', 'copy', get_current_location(), tag_url]) - - -def get_current_location(): - proc = subprocess.Popen('svn info', shell=True, stdout=subprocess.PIPE) - data = proc.stdout.read().decode("utf-8").splitlines() - for line in data: - if line.startswith('URL: '): - return line.lstrip('URL: ') + run_cmd(['hg', 'branch', tag.basic_version]) def make_tag(tag): - url = urlsplit(get_current_location()) - new_path = 'python/tags/r' + tag.nickname - tag_url = urlunsplit((url.scheme, url.netloc, new_path, - url.query, url.fragment)) - run_cmd(['svn', 'copy', get_current_location(), tag_url]) + run_cmd(['hg', 'tag', tag.hgname]) NEWS_TEMPLATE = """ -- Repository URL: http://hg.python.org/release From python-checkins at python.org Sun May 8 10:09:42 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 08 May 2011 10:09:42 +0200 Subject: [Python-checkins] release: Remove the "branch" operation, it is nothing more than a wrapper of "hg branch". Message-ID: http://hg.python.org/release/rev/855b8c8d17d2 changeset: 56:855b8c8d17d2 user: Georg Brandl date: Sun May 08 09:19:42 2011 +0200 summary: Remove the "branch" operation, it is nothing more than a wrapper of "hg branch". files: release.py | 20 +++++++------------- 1 files changed, 7 insertions(+), 13 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -361,14 +361,6 @@ return 'v' + self.text -def branch(tag): - if tag.patch > 0 or tag.level != "f": - print('It doesn\'t look like you\'re making a final release.') - if input('Are you sure you want to branch?') != "y": - return - run_cmd(['hg', 'branch', tag.basic_version]) - - def make_tag(tag): run_cmd(['hg', 'tag', tag.hgname]) @@ -414,17 +406,19 @@ parser = get_arg_parser() options, args = parser.parse_args(argv) if len(args) != 2: - parser.print_usage() - sys.exit(1) - tag = Tag(args[1]) + if 'RELEASE_TAG' not in os.environ: + parser.print_usage() + sys.exit(1) + tagname = os.environ['RELEASE_TAG'] + else: + tagname = args[1] + tag = Tag(tagname) if not (options.export or options.upload): check_env() if options.bump: bump(tag) if options.tag: make_tag(tag) - if options.branch: - branch(tag) if options.export: export(tag) if options.upload: -- Repository URL: http://hg.python.org/release From python-checkins at python.org Sun May 8 10:09:43 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 08 May 2011 10:09:43 +0200 Subject: [Python-checkins] release: Add a check for the correct branch when tagging. Message-ID: http://hg.python.org/release/rev/55798757d032 changeset: 57:55798757d032 user: Georg Brandl date: Sun May 08 10:09:39 2011 +0200 summary: Add a check for the correct branch when tagging. files: release.py | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -45,6 +45,10 @@ return code +def get_output(args): + return subprocess.check_output(SPACE.join(args), shell=True) + + def check_env(): if 'EDITOR' not in os.environ: error('editor not detected.', @@ -362,6 +366,12 @@ def make_tag(tag): + # make sure we're on the correct branch + if tag.patch > 0: + if get_output(['hg', 'branch']).strip().decode() != tag.basic_version: + print('It doesn\'t look like you\'re on the correct branch.') + if input('Are you sure you want to tag?') != "y": + return run_cmd(['hg', 'tag', tag.hgname]) -- Repository URL: http://hg.python.org/release From python-checkins at python.org Sun May 8 11:14:51 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 08 May 2011 11:14:51 +0200 Subject: [Python-checkins] peps: This should be most of the edits needed for releasing from hg. Message-ID: http://hg.python.org/peps/rev/38f77ef60e03 changeset: 3873:38f77ef60e03 user: Georg Brandl date: Sun May 08 11:14:12 2011 +0200 summary: This should be most of the edits needed for releasing from hg. files: pep-0101.txt | 309 +++++++++++++++++--------------------- 1 files changed, 140 insertions(+), 169 deletions(-) diff --git a/pep-0101.txt b/pep-0101.txt --- a/pep-0101.txt +++ b/pep-0101.txt @@ -27,15 +27,14 @@ How to Make A Release - Here are the steps taken to make a Python release. Some steps are - more fuzzy than others because there's little that can be - automated (e.g. writing the NEWS entries). Where a step is - usually performed by An Expert, the role of that expert is given. - Otherwise, assume the step is done by the Release Manager (RM), - the designated person performing the release. The roles and their - current experts are: + Here are the steps taken to make a Python release. Some steps are more + fuzzy than others because there's little that can be automated (e.g. + writing the NEWS entries). Where a step is usually performed by An + Expert, the role of that expert is given. Otherwise, assume the step is + done by the Release Manager (RM), the designated person performing the + release. The roles and their current experts are: - * RM = Release Manager: Benjamin Peterson (US/Central) + * RM = Release Manager: Georg Brandl (Central Europe) * WE = Windows: Martin von Loewis (Central Europe) * ME = Mac: Ronald Oussoren (Central Europe) * DE = Docs: Georg Brandl (Central Europe) @@ -54,24 +53,21 @@ following experts before updating the web pages and sending the announcement: WE, DE - XXX: We should include a dependency graph to illustrate the steps - that can be taken in parallel, or those that depend on other - steps. + XXX: We should include a dependency graph to illustrate the steps that can + be taken in parallel, or those that depend on other steps. As much as possible, the release steps are automated and guided by the - release script, which is available in the Python sandbox. The release - script is currently being maintained here: + release script, which is available in a separate repository: - http://svn.python.org/view/sandbox/trunk/release/ + http://hg.python.org/release/ We use the following conventions in the examples below. Where a release number is given, it is of the form X.YaZ, e.g. 2.6a3 for Python 2.6 alpha - 3, where "a" == alpha, "b" == beta, "rc" == release candidate. + 3, where "a" == alpha, "b" == beta, "rc" == release candidate. If a micro + release number is used, then we'll say X.Y.MaZ. - Final releases are named "releaseXY". The branch tag is "releaseXY-maint" - because this will point to the long lived maintenance branch. The fork - tag on the trunk is "releaseXY-fork". If a micro release number is used, - then we'll say X.Y.MaZ. + Release tags are named "vX.YaZ". The branch name for minor release + maintenance branches is "X.Y". This helps by performing several automatic editing steps, and guides you to perform some manual editing steps. @@ -81,18 +77,6 @@ You probably need to coordinate with other people around the world. This IRC channel is where we've arranged to meet. - ___ Impose a check-in freeze by sending email to python-committers at python.org - - At this point, nobody except the RM or his duly assigned agents should - make any commits to the branches. The assigned agents are either from - the list above or by coordination as necessary. If a checkin needs to - be made, make sure to state in the checkin comment that the change was - approved. If the RM screwed up and some desperate last minute change to - the branch is necessary, it can mean extra work for others. So try to - avoid this! - - The RM has full authority to revert any unapproved commits. - ___ Check to see if there are any showstopper bugs. Go to http://bugs.python.org and look for any open bugs that can block @@ -127,19 +111,48 @@ use your judgement, taking into account whether you are making an alpha, beta, or final release. - ___ Regenerate Lib/pydoc-topics.py + ___ Make a release clone. + + Create a local clone of the cpython repository (called the "release + clone" from now on). + + Also clone the repo at http://hg.python.org/cpython using the + server-side clone feature. The name of the new clone should preferably + have a "releasing/" prefix. The other experts will use the release + clone for making the binaries, so it is important that they have access + to it! + + Optionally, set up your local release clone to push to the remote + release clone by default (by editing .hg/hgrc to that effect). + + ___ Notify all committers by sending email to python-committers at python.org. + + Since we're now working with a distributed version control system, there + is no need to stop everyone from pushing to the main repo; you'll just + work in your own clone. Therefore, there won't be any checkin freezes. + + However, all committers should know the point at which your release + clone was made, as later commits won't make it into the release without + extra effort. + + ___ Make sure the current branch of your release clone is the branch you + want to release from. + + ___ Regenerate Lib/pydoc-topics.py. cd to the Doc directory and type ``make pydoc-topics``. Then copy ``build/pydoc-topics/pydoc-topics.py`` to ``../Lib/pydoc_topics.py``. - - ___ Check the docs for markup errors + + ___ Check the docs for markup errors. In the Doc directory, type ``make suspicious``. If any markup errors are found, fix them. + ___ Commit any changes to pydoc_topics.py and the doc sources. + ___ Bump version numbers via the release script. - .../sandbox/release/release.py --bump X.YaZ + $ .../release/release.py --bump X.YaZ This automates updating various release numbers, but you will have to modify a few files manually. If your $EDITOR environment variable is @@ -151,6 +164,8 @@ content of this file. You should only need to review the text for sanity, and update the release date with today's date. + Commit the changes once you have reviewed them. + ___ Check the years on the copyright notice. If the last release was some time last year, add the current year to the copyright notice in several places: @@ -178,24 +193,22 @@ alpha or beta releases. Note that Andrew Kuchling often takes care of this. - ___ If this is a final major release, branch the tree for X.Y + ___ Tag the release for X.YaZ. - When making a major release (e.g., for 2.6), you must create the - long-lived maintenance branch. To create a _branch_ (e.g., - release26-maint), do the following: + $ .../release/release.py --tag X.YaZ - .../sandbox/release/release.py --branch X.Y + ___ If this is a final major release, branch the tree for X.Y. - ___ If you just made the release branch, check out a clean version - into a new directory. You'll be doing the release from this new - branch. + When making a major release (e.g., for 3.2), you must create the + long-lived maintenance branch. - % svn co \ - svn+ssh://pythondev at svn.python.org/python/branches/release26-maint + ___ Note down the current revision ID of the tree. - ___ Set the original trunk up to be the next release. + $ hg identify - % .../sandbox/release/release.py --bump 2.7a0 + ___ First, set the original trunk up to be the next release. + + $ .../release/release.py --bump 3.3a0 ___ Edit all version references in the README @@ -205,27 +218,35 @@ ___ The LICENSE file. Add the pending version to the list of releases, and be sure to check the release dates. - ___ There's a copy of the license in Doc/license.rst + ___ There's a copy of the license in Doc/license.rst. - ___ Doc/tutorial/interpreter.rst (2 references to '[Pp]ython26', one - to 'Python 2.6'). + ___ Doc/tutorial/interpreter.rst (2 references to '[Pp]ython32', one + to 'Python 3.2'). ___ Doc/tutorial/stdlib.rst and Doc/tutorial/stdlib2.rst, which have - each one reference to '[Pp]ython26'. + each one reference to '[Pp]ython32'. ___ Update the version number in configure.in and re-run autoconf. ___ Update the version numbers for the Windows builds in PC/ and - PCbuild/, which have references to python26. + PCbuild/, which have references to python32. - % find PC/ PCbuild/ \( -type f -and -not -wholename '*/.svn/*' \) | xargs sed -i 's/python26/python27/g' - % svn mv PC/os2emx/python26.def PC/os2emx/python27.def + $ find PC/ PCbuild/ -type f | xargs sed -i 's/python32/python33/g' + $ hg mv -f PC/os2emx/python32.def PC/os2emx/python33.def - ___ cd release26-maint # cd into the branch directory. + ___ Commit these changes to the default branch. + + ___ Now, go back to the previously noted revision and make the + maintenance branch *from there*. - ___ Tag the release for X.YaZ + $ hg update deadbeef # revision ID noted down before + $ hg branch 3.2 - .../sandbox/release/release.py --tag X.YaZ + ___ Push your commits to the remote release clone. + + $ hg push ssh://hg.python.org/releasing/... + + ___ Notify the experts that they can start building binaries. ___ STOP STOP STOP STOP STOP STOP STOP STOP @@ -233,9 +254,6 @@ order to create the release. There are things you can do while you wait though, so keep reading until you hit the next STOP. - ___ Forward the commit message that created the tag to python-committers and - ask that the experts build the binaries. - ___ XXX The WE builds the Windows helpfile, using (in Doc/) either $ make htmlhelp (on Unix) @@ -244,64 +262,53 @@ > make.bat htmlhelp (on Windows) - to create suitable input for HTML Help Workshop in - build/htmlhelp. HTML Help Workshop is then fired up on the - created python26.hhp file, finally resulting in an - python26.chm file. He then copies the file into the Doc + to create suitable input for HTML Help Workshop in build/htmlhelp. HTML + Help Workshop is then fired up on the created python26.hhp file, finally + resulting in an python26.chm file. He then copies the file into the Doc directories of the build trees (once for each target architecture). XXX The CHM file should also be scp'd to the docs download location. ___ XXX The WE then generates Windows installer files for each Windows - target architecture (for Python 2.6, this means x86 - and AMD64). He has one checkout tree per target architecture, - and builds the pcbuild.sln project for the appropriate - architecture. He then edits Tools/msi/config.py to update - full_current_version, sets snapshot to False and runs msi.py with - ActivePython 2.5 or Python 2.5 with pywin32. + target architecture (for Python 2.6, this means x86 and AMD64). He has + one checkout tree per target architecture, and builds the pcbuild.sln + project for the appropriate architecture. He then edits + Tools/msi/config.py to update full_current_version, sets snapshot to + False and runs msi.py with ActivePython 2.5 or Python 2.5 with pywin32. For that to work, the following prerequisites must be met: - PC\icons.mak must have been run with nmake. - - The cmd.exe window in which this is run must have Cygwin/bin - in its path (atleast for x86). + - The cmd.exe window in which this is run must have Cygwin/bin in its + path (atleast for x86). - The cmd.exe window must have MS compiler tools for the target - architecture in its path (VS 2003 for x86, the platform - SDK for AMD64). + architecture in its path (VS 2003 for x86, the platform SDK for + AMD64). - - The cmd.exe window must also have cabarc.exe from the CAB SDK - in its path. + - The cmd.exe window must also have cabarc.exe from the CAB SDK in its + path. - The WE checksums the files (*.msi and *.chm), uploads them to - some place in the net, and emails you the location and md5sums. + The WE checksums the files (*.msi and *.chm), uploads them to some place + in the net, and emails you the location and md5sums. - ___ Time to build the source tarball. If you created a branch, be - sure to cd to your working directory for the branch. E.g. + ___ Time to build the source tarball. Be sure to update your clone to the + correct branch. E.g. - % cd .../python26 + $ hg update 3.2 - ___ Do a "svn update ; svn status" in this directory. + ___ Do a "hg status" in this directory. You should not see any files. I.e. you better not have any uncommitted - changes in your working directory, but you may pick up some of the - expert's last minute changes. - - ___ If you've seen updates to existing files and you want these to make it - into the release, update the branches. - - ___ Delete the old tag branch and re-tag the tree - ___ Delete the maintenance branch and re-branch the trunk. - - This should be rare and indicates a breakdown in the process. + changes in your working directory. ___ Use the release script to create the source gzip and bz2 tarballs, md5 checksums, documentation tar and zip files, and gpg signature files. - .../sandbox/release/release.py --export X.YaZ + $ .../release/release.py --export X.YaZ - This will leave all the relevant files in a subdirectory called 'dist', - and the built docs in 'dist/docs'. + This will leave all the relevant files in a subdirectory called + 'X.YaZ/src', and the built docs in 'X.YaZ/docs' (for final releases). ___ scp or rsync all the files to your home directory on dinsdale.python.org. @@ -315,40 +322,40 @@ virgin build passes the regression test. Here are the best steps to take: - % cd /tmp - % tar xzvf ~/Python-2.6c2.tgz # tar xjvf ~/Python-2.6c2.tar.bz2 - % cd Python-2.6c2 - % ls + $ cd /tmp + $ tar xvf ~/Python-3.2rc2.tgz + $ cd Python-3.2rc2 + $ ls (Do things look reasonable?) - % ls Lib + $ ls Lib (Are there stray .pyc files?) - % ls Doc/tools + $ ls Doc/tools (Make sure it doesn't contain "docutils", "sphinx", "jinja" or "pygments" directories. Also look for stray .pyc files.) - % ./configure + $ ./configure (Loads of configure output) - % make test + $ make test (Do all the expected tests pass?) If you're feeling lucky and have some time to kill, or if you are making a release candidate or final release, run the full test suite: - % make TESTOPTS='-u all' test + $ make TESTOPTS='-u all' test If the tests pass, then you can feel good that the tarball is fine. If some of the tests fail, or anything else about the freshly unpacked directory looks weird, you better stop now and figure out what the problem is. - ___ Now you need to go to dinsdale.python.org and move all the files - in place over there. Our policy is that every Python version gets its - own directory, but each directory may contain several releases. We keep - all old releases, moving them into a "prev" subdirectory when we have a - new release. + ___ Now you need to go to dinsdale.python.org and move all the files in + place over there. Our policy is that every Python version gets its own + directory, but each directory may contain several releases. We keep all + old releases, moving them into a "prev" subdirectory when we have a new + release. - So, there's a directory called "2.6" which contains Python-2.6a2.exe and - Python-2.6a2.tgz, along with a "prev" subdirectory containing - Python-2.6a1.msi, Python-2.6a1.tgz, Python-2.6a1.tar.bz2, etc. + So, there's a directory called "3.2" which contains Python-3.2.msi and + Python-3.2.tgz, along with a "prev" subdirectory containing + Python-3.2a1.msi, Python-3.2a1.tgz, Python-3.2a1.tar.bz2, etc. ___ On dinsdale, cd /data/ftp.python.org/pub/python/X.Y[.Z] creating it if necessary. @@ -395,9 +402,9 @@ Make sure the md5 checksums match. Then unpack the tarball, and do a clean make test. - % make distclean - % ./configure - % make test + $ make distclean + $ ./configure + $ make test To ensure that the regression test suite passes. If not, you screwed up somewhere! @@ -499,65 +506,29 @@ Now it's time to do some cleaning up. These steps are very important! - ___ If you made a non-maintenance branch, be sure to merge it into - the trunk! Now that we've released this branch, we don't need it any - more. We've already tagged it so we can always reproduce it. Note that - merging branches is a bit of a black art, but here's what's worked for - us. - - NOTE: If this was an X.Y major release, we will be using this as - the maintenance branch for a long time to come. - - ___ Check out a completely clean, virgin working directory of the - trunk, by doing this in the directory that is the parent of - your branch working directory python-XYaZ: - % svn co \ - svn+ssh://pythondev at svn.python.org/python/trunk python-clean - - ___ Run a diff against your branch by doing this in the common - parent directory containing both python-clean and python-XYaZ: - % diff -r python-clean python-26a2 | grep ^diff | grep -v /.svn/ \ - > /tmp/diffcmd.sh - - ___ Edit diffcmd.sh to get rid of files that you know don't have - important changes. You're looking for files that have updates - in the branch that haven't made it to the trunk. - - Generally you can ignore any changes to the Doc or Mac - subdirectories, or any changes to Windows related files. The - sub-RMs for those parts will take care of any necessary merges - from the branch to the trunk. - - If you've been diligent about merging changes from the trunk - into the branch, there shouldn't be many of these files. - - ___ Edit /tmp/diffcmd.sh, changing all the -r's into -u's. Run - the /tmp/diffcmd.sh command like so: - % sh /tmp/diffcmd.sh > /tmp/pydiff.txt - - ___ Attempt to patch your python-clean working directory. Do this - first, noting that --dry-run does not actually apply any - patches, it just makes sure that the patch command runs - successfully to completion: - % patch -p1 --dry-run < /tmp/pydiff.txt - - ___ If this goes well, run it again, taking out the --dry-run - option. If this fails, or if it prompts you for a file to - patch, try using -p0 instead of -p1. Otherwise, your diff - command was messed up, so try again. - - ___ cd to python-clean and do a "svn commit". Use as your log - message something like "Merging the rXYaZ-maint tag back into - the trunk". - ___ Do the guided post-release steps with the release script. - .../sandbox/release/release.py --done X.YaZ + $ .../release/release.py --done X.YaZ Review and commit these changes. - ___ Send email to python-committers informing them that the branch has been - unfrozen. + ___ Merge your release clone into the main development repo: + + $ cd ../cpython # your clone of the main repo + $ hg pull ssh://hg.python.org/cpython # update from remote first + $ hg pull ../cpython-releaseX.Y # now pull from release clone + + Now merge your release clone's changes in every branch you touched + (usually only one, except if you made a new maintenance release). + Easily resolvable conflicts may appear in Misc/NEWS. + + Commit and push to the main repo. + + ___ You can delete the remote release clone, or simply reuse it for the next + release. + + ___ Send email to python-committers informing them that the release has been + published. ___ Update any release PEPs (e.g. 361) with the release dates. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun May 8 19:01:47 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 08 May 2011 19:01:47 +0200 Subject: [Python-checkins] cpython (3.1): Add back Misc/NEWS entry that got lost during merge, and fix a couple of other Message-ID: http://hg.python.org/cpython/rev/bdc68fc8d3c9 changeset: 69937:bdc68fc8d3c9 branch: 3.1 parent: 69926:7884783c9145 user: Ezio Melotti date: Sun May 08 19:58:08 2011 +0300 summary: Add back Misc/NEWS entry that got lost during merge, and fix a couple of other things. files: Misc/NEWS | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,7 +69,9 @@ - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Kasun Herath. -- Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to +- Issue #12002: ftplib's abort() method raises TypeError. + +- Issue #11999: fixed sporadic sync failure mailbox.Maildir due to its trying to detect mtime changes by comparing to the system clock instead of to the previous value of the mtime. @@ -314,8 +316,8 @@ - Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified IP addresses in the proxy exception list. -Extensions ----------- +Extension Modules +----------------- - Issue #12017: Fix segfault in json.loads() while decoding highly-nested objects using the C accelerations. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 19:01:48 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 08 May 2011 19:01:48 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/c3bd98e1318b changeset: 69938:c3bd98e1318b branch: 3.2 parent: 69928:e3f807d52272 parent: 69937:bdc68fc8d3c9 user: Ezio Melotti date: Sun May 08 20:00:03 2011 +0300 summary: Merge with 3.1. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,7 +88,7 @@ - Issue #12002: ftplib's abort() method raises TypeError. -- Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to +- Issue #11999: fixed sporadic sync failure mailbox.Maildir due to its trying to detect mtime changes by comparing to the system clock instead of to the previous value of the mtime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 19:01:49 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 08 May 2011 19:01:49 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/3bb8c44996c1 changeset: 69939:3bb8c44996c1 parent: 69936:e3cb2c99a5a9 parent: 69938:c3bd98e1318b user: Ezio Melotti date: Sun May 08 20:01:36 2011 +0300 summary: Merge with 3.2. files: Misc/NEWS | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -152,10 +152,10 @@ - Issue #12002: ftplib's abort() method raises TypeError. -- Issue 11916: Add a number of MacOSX specific definitions to the errno module. +- Issue #11916: Add a number of MacOSX specific definitions to the errno module. Patch by Pierre Carrier. -- Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to +- Issue #11999: fixed sporadic sync failure mailbox.Maildir due to its trying to detect mtime changes by comparing to the system clock instead of to the previous value of the mtime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 19:24:07 2011 From: python-checkins at python.org (ezio.melotti) Date: Sun, 08 May 2011 19:24:07 +0200 Subject: [Python-checkins] cpython: Refactor buggy test to correctly use the msg argument of assertRaises. Message-ID: http://hg.python.org/cpython/rev/9af64d83c217 changeset: 69940:9af64d83c217 user: Ezio Melotti date: Sun May 08 20:23:57 2011 +0300 summary: Refactor buggy test to correctly use the msg argument of assertRaises. files: Lib/test/test_socket.py | 13 ++++--------- 1 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -270,18 +270,13 @@ def testSocketError(self): # Testing socket module exceptions - def raise_error(*args, **kwargs): + msg = "Error raising socket exception (%s)." + with self.assertRaises(socket.error, msg=msg % 'socket.error'): raise socket.error - def raise_herror(*args, **kwargs): + with self.assertRaises(socket.error, msg=msg % 'socket.herror'): raise socket.herror - def raise_gaierror(*args, **kwargs): + with self.assertRaises(socket.error, msg=msg % 'socket.gaierror'): raise socket.gaierror - self.assertRaises(socket.error, raise_error, - "Error raising socket exception.") - self.assertRaises(socket.error, raise_herror, - "Error raising socket exception.") - self.assertRaises(socket.error, raise_gaierror, - "Error raising socket exception.") def testSendtoErrors(self): # Testing that sendto doens't masks failures. See #10169. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 22:33:19 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 08 May 2011 22:33:19 +0200 Subject: [Python-checkins] cpython (2.7): import_fresh_module ought to be in __all__ Message-ID: http://hg.python.org/cpython/rev/827a455a2d13 changeset: 69941:827a455a2d13 branch: 2.7 parent: 69933:dd2639508dfe user: Benjamin Peterson date: Sun May 08 15:32:04 2011 -0500 summary: import_fresh_module ought to be in __all__ files: Lib/test/test_support.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -35,7 +35,8 @@ "run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest", "BasicTestRunner", "run_unittest", "run_doctest", "threading_setup", "threading_cleanup", "reap_children", "cpython_only", - "check_impl_detail", "get_attribute", "py3k_bytes"] + "check_impl_detail", "get_attribute", "py3k_bytes", + "import_fresh_module"] class Error(Exception): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 22:33:22 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 08 May 2011 22:33:22 +0200 Subject: [Python-checkins] cpython (3.1): put import_fresh_module in __all__ Message-ID: http://hg.python.org/cpython/rev/92bc1518f20d changeset: 69942:92bc1518f20d branch: 3.1 parent: 69937:bdc68fc8d3c9 user: Benjamin Peterson date: Sun May 08 15:32:46 2011 -0500 summary: put import_fresh_module in __all__ files: Lib/test/support.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -32,6 +32,7 @@ "set_memlimit", "bigmemtest", "bigaddrspacetest", "BasicTestRunner", "run_unittest", "run_doctest", "threading_setup", "threading_cleanup", "reap_children", "cpython_only", "check_impl_detail", "get_attribute", + "import_fresh_module" ] class Error(Exception): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 22:33:24 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 08 May 2011 22:33:24 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge 3.1 Message-ID: http://hg.python.org/cpython/rev/ae6cd69ce9f8 changeset: 69943:ae6cd69ce9f8 branch: 3.2 parent: 69938:c3bd98e1318b parent: 69942:92bc1518f20d user: Benjamin Peterson date: Sun May 08 15:34:24 2011 -0500 summary: merge 3.1 files: Lib/test/support.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -43,8 +43,9 @@ "run_unittest", "run_doctest", "threading_setup", "threading_cleanup", "reap_children", "cpython_only", "check_impl_detail", "get_attribute", "swap_item", "swap_attr", "requires_IEEE_754", - "TestHandler", "Matcher", "can_symlink", "skip_unless_symlink"] - + "TestHandler", "Matcher", "can_symlink", "skip_unless_symlink", + "import_fresh_module" + ] class Error(Exception): """Base class for regression test exceptions.""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 8 22:33:29 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 08 May 2011 22:33:29 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge 3.2 Message-ID: http://hg.python.org/cpython/rev/b6a335b9e717 changeset: 69944:b6a335b9e717 parent: 69940:9af64d83c217 parent: 69943:ae6cd69ce9f8 user: Benjamin Peterson date: Sun May 08 15:35:09 2011 -0500 summary: merge 3.2 files: Lib/test/support.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -42,8 +42,9 @@ "BasicTestRunner", "run_unittest", "run_doctest", "threading_setup", "threading_cleanup", "reap_children", "cpython_only", "check_impl_detail", "get_attribute", "swap_item", "swap_attr", "requires_IEEE_754", - "TestHandler", "Matcher", "can_symlink", "skip_unless_symlink"] - + "TestHandler", "Matcher", "can_symlink", "skip_unless_symlink", + "import_fresh_module" + ] class Error(Exception): """Base class for regression test exceptions.""" -- Repository URL: http://hg.python.org/cpython From nnorwitz at gmail.com Sun May 8 22:00:46 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Sun, 8 May 2011 16:00:46 -0400 Subject: [Python-checkins] Python Regression Test Failures doc (1) Message-ID: <20110508200046.GA2465@kbk-i386-bb.dyndns.org> rm -rf build/* rm -rf tools/sphinx rm -rf tools/pygments rm -rf tools/jinja2 rm -rf tools/docutils Checking out Sphinx... svn: PROPFIND request failed on '/projects/external/Sphinx-0.6.5/sphinx' svn: PROPFIND of '/projects/external/Sphinx-0.6.5/sphinx': Could not resolve hostname `svn.python.org': Host not found (http://svn.python.org) make: *** [checkout] Error 1 From python-checkins at python.org Mon May 9 00:43:45 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 09 May 2011 00:43:45 +0200 Subject: [Python-checkins] cpython: Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional Message-ID: http://hg.python.org/cpython/rev/5296c3e2f166 changeset: 69945:5296c3e2f166 user: Victor Stinner date: Mon May 09 00:42:58 2011 +0200 summary: Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional OpenSSL is now compiled with OPENSSL_NO_SSL2 defined (without the SSLv2 protocol) on Debian: fix the ssl module on Debian Testing and Debian Sid. Optimize also ssl.get_protocol_name(): speed does matter! files: Doc/library/ssl.rst | 3 + Lib/ssl.py | 26 +++++++------ Lib/test/test_ssl.py | 57 +++++++++++++++++++------------ Misc/NEWS | 2 + Modules/_ssl.c | 8 +++- 5 files changed, 60 insertions(+), 36 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -292,6 +292,9 @@ Selects SSL version 2 as the channel encryption protocol. + This protocol is not available if OpenSSL is compiled with OPENSSL_NO_SSL2 + flag. + .. warning:: SSL version 2 is insecure. Its use is highly discouraged. diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -62,8 +62,6 @@ from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION from _ssl import _SSLContext, SSLError from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED -from _ssl import (PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, - PROTOCOL_TLSv1) from _ssl import OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1 from _ssl import RAND_status, RAND_egd, RAND_add from _ssl import ( @@ -78,6 +76,19 @@ SSL_ERROR_INVALID_ERROR_CODE, ) from _ssl import HAS_SNI +from _ssl import (PROTOCOL_SSLv3, PROTOCOL_SSLv23, + PROTOCOL_TLSv1) +_PROTOCOL_NAMES = { + PROTOCOL_TLSv1: "TLSv1", + PROTOCOL_SSLv23: "SSLv23", + PROTOCOL_SSLv3: "SSLv3", +} +try: + from _ssl import PROTOCOL_SSLv2 +except ImportError: + pass +else: + _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2" from socket import getnameinfo as _getnameinfo from socket import error as socket_error @@ -552,13 +563,4 @@ return DER_cert_to_PEM_cert(dercert) def get_protocol_name(protocol_code): - if protocol_code == PROTOCOL_TLSv1: - return "TLSv1" - elif protocol_code == PROTOCOL_SSLv23: - return "SSLv23" - elif protocol_code == PROTOCOL_SSLv2: - return "SSLv2" - elif protocol_code == PROTOCOL_SSLv3: - return "SSLv3" - else: - return "" + return _PROTOCOL_NAMES.get(protocol_code, '') diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -21,9 +21,11 @@ ssl = support.import_module("ssl") PROTOCOLS = [ - ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, + ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1 ] +if hasattr(ssl, 'PROTOCOL_SSLv2'): + PROTOCOLS.append(ssl.PROTOCOL_SSLv2) HOST = support.HOST @@ -67,22 +69,25 @@ # Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2 def skip_if_broken_ubuntu_ssl(func): - @functools.wraps(func) - def f(*args, **kwargs): - try: - ssl.SSLContext(ssl.PROTOCOL_SSLv2) - except ssl.SSLError: - if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and - platform.linux_distribution() == ('debian', 'squeeze/sid', '')): - raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour") - return func(*args, **kwargs) - return f + if hasattr(ssl, 'PROTOCOL_SSLv2'): + @functools.wraps(func) + def f(*args, **kwargs): + try: + ssl.SSLContext(ssl.PROTOCOL_SSLv2) + except ssl.SSLError: + if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and + platform.linux_distribution() == ('debian', 'squeeze/sid', '')): + raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour") + return func(*args, **kwargs) + return f + else: + return func class BasicSocketTests(unittest.TestCase): def test_constants(self): - ssl.PROTOCOL_SSLv2 + #ssl.PROTOCOL_SSLv2 ssl.PROTOCOL_SSLv23 ssl.PROTOCOL_SSLv3 ssl.PROTOCOL_TLSv1 @@ -310,7 +315,8 @@ @skip_if_broken_ubuntu_ssl def test_constructor(self): - ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv2) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv2) ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv3) ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) @@ -1204,6 +1210,8 @@ t.join() @skip_if_broken_ubuntu_ssl + @unittest.skipUnless(hasattr(ssl, 'PROTOCOL_SSLv2'), + "OpenSSL is compiled without SSLv2 support") def test_protocol_sslv2(self): """Connecting to an SSLv2 server with various client options""" if support.verbose: @@ -1229,14 +1237,15 @@ """Connecting to an SSLv23 server with various client options""" if support.verbose: sys.stdout.write("\n") - try: - try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True) - except (ssl.SSLError, socket.error) as x: - # this fails on some older versions of OpenSSL (0.9.7l, for instance) - if support.verbose: - sys.stdout.write( - " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" - % str(x)) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try: + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True) + except (ssl.SSLError, socket.error) as x: + # this fails on some older versions of OpenSSL (0.9.7l, for instance) + if support.verbose: + sys.stdout.write( + " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" + % str(x)) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True) @@ -1267,7 +1276,8 @@ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False) if no_sslv2_implies_sslv3_hello(): @@ -1283,7 +1293,8 @@ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,8 @@ Library ------- +- Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. + - Issue #8407: The signal handler writes the signal number as a single byte instead of a nul byte into the wakeup file descriptor. So it is possible to wait more than one signal and know which signals were raised. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -63,8 +63,10 @@ }; enum py_ssl_version { +#ifndef OPENSSL_NO_SSL2 PY_SSL_VERSION_SSL2, - PY_SSL_VERSION_SSL3, +#endif + PY_SSL_VERSION_SSL3=1, PY_SSL_VERSION_SSL23, PY_SSL_VERSION_TLS1 }; @@ -1447,8 +1449,10 @@ ctx = SSL_CTX_new(TLSv1_method()); else if (proto_version == PY_SSL_VERSION_SSL3) ctx = SSL_CTX_new(SSLv3_method()); +#ifndef OPENSSL_NO_SSL2 else if (proto_version == PY_SSL_VERSION_SSL2) ctx = SSL_CTX_new(SSLv2_method()); +#endif else if (proto_version == PY_SSL_VERSION_SSL23) ctx = SSL_CTX_new(SSLv23_method()); else @@ -2107,8 +2111,10 @@ PY_SSL_CERT_REQUIRED); /* protocol versions */ +#ifndef OPENSSL_NO_SSL2 PyModule_AddIntConstant(m, "PROTOCOL_SSLv2", PY_SSL_VERSION_SSL2); +#endif PyModule_AddIntConstant(m, "PROTOCOL_SSLv3", PY_SSL_VERSION_SSL3); PyModule_AddIntConstant(m, "PROTOCOL_SSLv23", -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 01:05:18 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 09 May 2011 01:05:18 +0200 Subject: [Python-checkins] cpython: Issue #11888: Add log2 function to math module. Patch written by Mark Message-ID: http://hg.python.org/cpython/rev/6d1cbfcee45a changeset: 69946:6d1cbfcee45a user: Victor Stinner date: Mon May 09 01:01:09 2011 +0200 summary: Issue #11888: Add log2 function to math module. Patch written by Mark Dickinson. files: Doc/library/math.rst | 7 + Doc/whatsnew/3.3.rst | 44 ++++++--- Lib/test/math_testcases.txt | 114 ++++++++++++++++++++++++ Lib/test/test_math.py | 22 ++++ Misc/NEWS | 3 + Modules/mathmodule.c | 59 ++++++++++++ 6 files changed, 234 insertions(+), 15 deletions(-) diff --git a/Doc/library/math.rst b/Doc/library/math.rst --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -184,6 +184,13 @@ result is calculated in a way which is accurate for *x* near zero. +.. function:: log2(x) + + Return the base-2 logarithm of *x*. + + .. versionadded:: 3.3 + + .. function:: log10(x) Return the base-10 logarithm of *x*. This is usually more accurate diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -76,6 +76,33 @@ * :envvar:`PYTHONFAULTHANDLER` * :option:`-X` ``faulthandler`` + +math +---- + +The :mod:`math` module has a new function: + + * :func:`~math.log2`: return the base-2 logarithm of *x* + (Written by Mark Dickinson in :issue:`11888`). + + +nntplib +------- + +The :class:`nntplib.NNTP` class now supports the context manager protocol to +unconditionally consume :exc:`socket.error` exceptions and to close the NNTP +connection when done:: + + >>> from nntplib import NNTP + >>> with nntplib.NNTP('news.gmane.org') as n: + ... n.group('gmane.comp.python.committers') + ... + ('211 1454 1 1454 gmane.comp.python.committers', '1454', '1', '1454', 'gmane.comp.python.committers') + >>> + +(Contributed by Giampaolo Rodol? in :issue:`9795`) + + os -- @@ -96,21 +123,6 @@ (Patch submitted by Giampaolo Rodol? in :issue:`10784`.) -nntplib -------- - -The :class:`nntplib.NNTP` class now supports the context manager protocol to -unconditionally consume :exc:`socket.error` exceptions and to close the NNTP -connection when done:: - - >>> from nntplib import NNTP - >>> with nntplib.NNTP('news.gmane.org') as n: - ... n.group('gmane.comp.python.committers') - ... - ('211 1454 1 1454 gmane.comp.python.committers', '1454', '1', '1454', 'gmane.comp.python.committers') - >>> - -(Contributed by Giampaolo Rodol? in :issue:`9795`) sys --- @@ -120,10 +132,11 @@ (:issue:`11223`) + signal ------ -* The :mod:`signal` module has a new functions: +* The :mod:`signal` module has new functions: * :func:`~signal.pthread_sigmask`: fetch and/or change the signal mask of the calling thread (Contributed by Jean-Paul Calderone in :issue:`8407`) ; diff --git a/Lib/test/math_testcases.txt b/Lib/test/math_testcases.txt --- a/Lib/test/math_testcases.txt +++ b/Lib/test/math_testcases.txt @@ -517,3 +517,117 @@ -- weaker version of expm10302 expm10307 expm1 709.5 -> 1.3549863193146328e+308 + +------------------------- +-- log2: log to base 2 -- +------------------------- + +-- special values +log20000 log2 0.0 -> -inf divide-by-zero +log20001 log2 -0.0 -> -inf divide-by-zero +log20002 log2 inf -> inf +log20003 log2 -inf -> nan invalid +log20004 log2 nan -> nan + +-- exact value at 1.0 +log20010 log2 1.0 -> 0.0 + +-- negatives +log20020 log2 -5e-324 -> nan invalid +log20021 log2 -1.0 -> nan invalid +log20022 log2 -1.7e-308 -> nan invalid + +-- exact values at powers of 2 +log20100 log2 2.0 -> 1.0 +log20101 log2 4.0 -> 2.0 +log20102 log2 8.0 -> 3.0 +log20103 log2 16.0 -> 4.0 +log20104 log2 32.0 -> 5.0 +log20105 log2 64.0 -> 6.0 +log20106 log2 128.0 -> 7.0 +log20107 log2 256.0 -> 8.0 +log20108 log2 512.0 -> 9.0 +log20109 log2 1024.0 -> 10.0 +log20110 log2 2048.0 -> 11.0 + +log20200 log2 0.5 -> -1.0 +log20200 log2 0.25 -> -2.0 +log20200 log2 0.125 -> -3.0 +log20200 log2 0.0625 -> -4.0 + +-- values close to 1.0 +log20300 log2 1.0000000000000002 -> 3.2034265038149171e-16 +log20301 log2 1.0000000001 -> 1.4426951601859516e-10 +log20302 log2 1.00001 -> 1.4426878274712997e-5 + +log20310 log2 0.9999999999999999 -> -1.6017132519074588e-16 +log20311 log2 0.9999999999 -> -1.4426951603302210e-10 +log20312 log2 0.99999 -> -1.4427022544056922e-5 + +-- tiny values +log20400 log2 5e-324 -> -1074.0 +log20401 log2 1e-323 -> -1073.0 +log20402 log2 1.5e-323 -> -1072.4150374992789 +log20403 log2 2e-323 -> -1072.0 + +log20410 log2 1e-308 -> -1023.1538532253076 +log20411 log2 2.2250738585072014e-308 -> -1022.0 +log20412 log2 4.4501477170144028e-308 -> -1021.0 +log20412 log2 1e-307 -> -1019.8319251304202 + +-- huge values +log20500 log2 1.7976931348623157e+308 -> 1024.0 +log20501 log2 1.7e+308 -> 1023.9193879716706 +log20502 log2 8.9884656743115795e+307 -> 1023.0 + +-- selection of random values +log20600 log2 -7.2174324841039838e+289 -> nan invalid +log20601 log2 -2.861319734089617e+265 -> nan invalid +log20602 log2 -4.3507646894008962e+257 -> nan invalid +log20603 log2 -6.6717265307520224e+234 -> nan invalid +log20604 log2 -3.9118023786619294e+229 -> nan invalid +log20605 log2 -1.5478221302505161e+206 -> nan invalid +log20606 log2 -1.4380485131364602e+200 -> nan invalid +log20607 log2 -3.7235198730382645e+185 -> nan invalid +log20608 log2 -1.0472242235095724e+184 -> nan invalid +log20609 log2 -5.0141781956163884e+160 -> nan invalid +log20610 log2 -2.1157958031160324e+124 -> nan invalid +log20611 log2 -7.9677558612567718e+90 -> nan invalid +log20612 log2 -5.5553906194063732e+45 -> nan invalid +log20613 log2 -16573900952607.953 -> nan invalid +log20614 log2 -37198371019.888618 -> nan invalid +log20615 log2 -6.0727115121422674e-32 -> nan invalid +log20616 log2 -2.5406841656526057e-38 -> nan invalid +log20617 log2 -4.9056766703267657e-43 -> nan invalid +log20618 log2 -2.1646786075228305e-71 -> nan invalid +log20619 log2 -2.470826790488573e-78 -> nan invalid +log20620 log2 -3.8661709303489064e-165 -> nan invalid +log20621 log2 -1.0516496976649986e-182 -> nan invalid +log20622 log2 -1.5935458614317996e-255 -> nan invalid +log20623 log2 -2.8750977267336654e-293 -> nan invalid +log20624 log2 -7.6079466794732585e-296 -> nan invalid +log20625 log2 3.2073253539988545e-307 -> -1018.1505544209213 +log20626 log2 1.674937885472249e-244 -> -809.80634755783126 +log20627 log2 1.0911259044931283e-214 -> -710.76679472274213 +log20628 log2 2.0275372624809709e-154 -> -510.55719818383272 +log20629 log2 7.3926087369631841e-115 -> -379.13564735312292 +log20630 log2 1.3480198206342423e-86 -> -285.25497445094436 +log20631 log2 8.9927384655719947e-83 -> -272.55127136401637 +log20632 log2 3.1452398713597487e-60 -> -197.66251564496875 +log20633 log2 7.0706573215457351e-55 -> -179.88420087782217 +log20634 log2 3.1258285390731669e-49 -> -161.13023800505653 +log20635 log2 8.2253046627829942e-41 -> -133.15898277355879 +log20636 log2 7.8691367397519897e+49 -> 165.75068202732419 +log20637 log2 2.9920561983925013e+64 -> 214.18453534573757 +log20638 log2 4.7827254553946841e+77 -> 258.04629628445673 +log20639 log2 3.1903566496481868e+105 -> 350.47616767491166 +log20640 log2 5.6195082449502419e+113 -> 377.86831861008250 +log20641 log2 9.9625658250651047e+125 -> 418.55752921228753 +log20642 log2 2.7358945220961532e+145 -> 483.13158636923413 +log20643 log2 2.785842387926931e+174 -> 579.49360214860280 +log20644 log2 2.4169172507252751e+193 -> 642.40529039289652 +log20645 log2 3.1689091206395632e+205 -> 682.65924573798395 +log20646 log2 2.535995592365391e+208 -> 692.30359597460460 +log20647 log2 6.2011236566089916e+233 -> 776.64177576730913 +log20648 log2 2.1843274820677632e+253 -> 841.57499717289647 +log20649 log2 8.7493931063474791e+297 -> 989.74182713073981 diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -649,6 +649,28 @@ n= 2**90 self.assertAlmostEqual(math.log1p(n), math.log1p(float(n))) + @requires_IEEE_754 + def testLog2(self): + self.assertRaises(TypeError, math.log2) + # Check that we get exact equality for log2 of powers of 2. + actual = [math.log2(2.0**n) for n in range(-324, 1024)] + expected = [float(n) for n in range(-324, 1024)] + self.assertEqual(actual, expected) + + # Check some integer values + self.assertEqual(math.log2(1), 0.0) + self.assertEqual(math.log2(2), 1.0) + self.assertEqual(math.log2(4), 2.0) + + # Large integer values + self.assertEqual(math.log2(2**1023), 1023.0) + self.assertEqual(math.log2(2**1024), 1024.0) + self.assertEqual(math.log2(2**2000), 2000.0) + + self.assertRaises(ValueError, math.log2, -1.5) + self.assertRaises(ValueError, math.log2, NINF) + self.assertTrue(math.isnan(math.log2(NAN))) + def testLog10(self): self.assertRaises(TypeError, math.log10) self.ftest('log10(0.1)', math.log10(0.1), -1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,9 @@ Library ------- +- Issue #11888: Add log2 function to math module. Patch written by Mark + Dickinson. + - Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. - Issue #8407: The signal handler writes the signal number as a single byte diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -577,6 +577,55 @@ } } +/* + log2: log to base 2. + + Uses an algorithm that should: + (a) produce exact results for powers of 2, and + (b) be monotonic, assuming that the system log is monotonic. +*/ + +static double +m_log2(double x) +{ + if (!Py_IS_FINITE(x)) { + if (Py_IS_NAN(x)) + return x; /* log2(nan) = nan */ + else if (x > 0.0) + return x; /* log2(+inf) = +inf */ + else { + errno = EDOM; + return Py_NAN; /* log2(-inf) = nan, invalid-operation */ + } + } + + if (x > 0.0) { + double m; + int e; + m = frexp(x, &e); + /* We want log2(m * 2**e) == log(m) / log(2) + e. Care is needed when + * x is just greater than 1.0: in that case e is 1, log(m) is negative, + * and we get significant cancellation error from the addition of + * log(m) / log(2) to e. The slight rewrite of the expression below + * avoids this problem. + */ + if (x >= 1.0) { + return log(2.0 * m) / log(2.0) + (e - 1); + } + else { + return log(m) / log(2.0) + e; + } + } + else if (x == 0.0) { + errno = EDOM; + return -Py_HUGE_VAL; /* log2(0) = -inf, divide-by-zero */ + } + else { + errno = EDOM; + return Py_NAN; /* log10(-inf) = nan, invalid-operation */ + } +} + static double m_log10(double x) { @@ -1623,6 +1672,15 @@ If the base not specified, returns the natural logarithm (base e) of x."); static PyObject * +math_log2(PyObject *self, PyObject *arg) +{ + return loghelper(arg, m_log2, "log2"); +} + +PyDoc_STRVAR(math_log2_doc, +"log2(x)\n\nReturn the base 2 logarithm of x."); + +static PyObject * math_log10(PyObject *self, PyObject *arg) { return loghelper(arg, m_log10, "log10"); @@ -1894,6 +1952,7 @@ {"log", math_log, METH_VARARGS, math_log_doc}, {"log1p", math_log1p, METH_O, math_log1p_doc}, {"log10", math_log10, METH_O, math_log10_doc}, + {"log2", math_log2, METH_O, math_log2_doc}, {"modf", math_modf, METH_O, math_modf_doc}, {"pow", math_pow, METH_VARARGS, math_pow_doc}, {"radians", math_radians, METH_O, math_radians_doc}, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 01:29:31 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 09 May 2011 01:29:31 +0200 Subject: [Python-checkins] cpython: Close #12032: Fix scripts/crlf.py for Python 3 Message-ID: http://hg.python.org/cpython/rev/f94d74c85dcb changeset: 69947:f94d74c85dcb user: Victor Stinner date: Mon May 09 01:29:30 2011 +0200 summary: Close #12032: Fix scripts/crlf.py for Python 3 files: Tools/scripts/crlf.py | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Tools/scripts/crlf.py b/Tools/scripts/crlf.py --- a/Tools/scripts/crlf.py +++ b/Tools/scripts/crlf.py @@ -8,16 +8,16 @@ if os.path.isdir(filename): print(filename, "Directory!") continue - data = open(filename, "rb").read() - if '\0' in data: + with open(filename, "rb") as f: + data = f.read() + if b'\0' in data: print(filename, "Binary!") continue - newdata = data.replace("\r\n", "\n") + newdata = data.replace(b"\r\n", b"\n") if newdata != data: print(filename) - f = open(filename, "wb") - f.write(newdata) - f.close() + with open(filename, "wb") as f: + f.write(newdata) if __name__ == '__main__': main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 02:46:12 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 09 May 2011 02:46:12 +0200 Subject: [Python-checkins] cpython: note the point of having log2 Message-ID: http://hg.python.org/cpython/rev/5107b11c6d6b changeset: 69948:5107b11c6d6b user: Benjamin Peterson date: Sun May 08 19:48:08 2011 -0500 summary: note the point of having log2 files: Doc/library/math.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/math.rst b/Doc/library/math.rst --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -186,7 +186,8 @@ .. function:: log2(x) - Return the base-2 logarithm of *x*. + Return the base-2 logarithm of *x*. This is usually more accurate than + ``log(x, 2)``. .. versionadded:: 3.3 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 03:00:57 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 03:00:57 +0200 Subject: [Python-checkins] cpython (2.7): Add a note to the str.find doc to suggest the use of the "in" operator. Message-ID: http://hg.python.org/cpython/rev/85fb264b5922 changeset: 69949:85fb264b5922 branch: 2.7 parent: 69941:827a455a2d13 user: Ezio Melotti date: Mon May 09 03:54:30 2011 +0300 summary: Add a note to the str.find doc to suggest the use of the "in" operator. files: Doc/library/stdtypes.rst | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -944,6 +944,15 @@ *start* and *end* are interpreted as in slice notation. Return ``-1`` if *sub* is not found. + .. note:: + + The :meth:`~str.find` method should be used only if you need to know the + position of *sub*. To check if *sub* is a substring or not, use the + :keyword:`in` operator:: + + >>> 'Py' in 'Python' + True + .. method:: str.format(*args, **kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 03:00:58 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 03:00:58 +0200 Subject: [Python-checkins] cpython (3.1): Add a note to the str.find doc to suggest the use of the "in" operator. Message-ID: http://hg.python.org/cpython/rev/e4acbe2c8164 changeset: 69950:e4acbe2c8164 branch: 3.1 parent: 69942:92bc1518f20d user: Ezio Melotti date: Mon May 09 03:54:30 2011 +0300 summary: Add a note to the str.find doc to suggest the use of the "in" operator. files: Doc/library/stdtypes.rst | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -883,6 +883,15 @@ *start* and *end* are interpreted as in slice notation. Return ``-1`` if *sub* is not found. + .. note:: + + The :meth:`~str.find` method should be used only if you need to know the + position of *sub*. To check if *sub* is a substring or not, use the + :keyword:`in` operator:: + + >>> 'Py' in 'Python' + True + .. method:: str.format(*args, **kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 03:00:59 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 03:00:59 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/0ea2c5866e7d changeset: 69951:0ea2c5866e7d branch: 3.2 parent: 69943:ae6cd69ce9f8 parent: 69950:e4acbe2c8164 user: Ezio Melotti date: Mon May 09 04:00:06 2011 +0300 summary: Merge with 3.1. files: Doc/library/stdtypes.rst | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1047,6 +1047,15 @@ *start* and *end* are interpreted as in slice notation. Return ``-1`` if *sub* is not found. + .. note:: + + The :meth:`~str.find` method should be used only if you need to know the + position of *sub*. To check if *sub* is a substring or not, use the + :keyword:`in` operator:: + + >>> 'Py' in 'Python' + True + .. method:: str.format(*args, **kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 03:01:00 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 03:01:00 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/e7d8713f95f3 changeset: 69952:e7d8713f95f3 parent: 69948:5107b11c6d6b parent: 69951:0ea2c5866e7d user: Ezio Melotti date: Mon May 09 04:00:47 2011 +0300 summary: Merge with 3.2. files: Doc/library/stdtypes.rst | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1047,6 +1047,15 @@ *start* and *end* are interpreted as in slice notation. Return ``-1`` if *sub* is not found. + .. note:: + + The :meth:`~str.find` method should be used only if you need to know the + position of *sub*. To check if *sub* is a substring or not, use the + :keyword:`in` operator:: + + >>> 'Py' in 'Python' + True + .. method:: str.format(*args, **kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 04:58:27 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 04:58:27 +0200 Subject: [Python-checkins] cpython (2.7): Fix deprecation warnings in test_unittest. Message-ID: http://hg.python.org/cpython/rev/8e60c3fe21f6 changeset: 69953:8e60c3fe21f6 branch: 2.7 parent: 69949:85fb264b5922 user: Ezio Melotti date: Mon May 09 05:58:17 2011 +0300 summary: Fix deprecation warnings in test_unittest. files: Lib/unittest/test/test_result.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/unittest/test/test_result.py b/Lib/unittest/test/test_result.py --- a/Lib/unittest/test/test_result.py +++ b/Lib/unittest/test/test_result.py @@ -503,7 +503,7 @@ class Foo(unittest.TestCase): @classmethod def setUpClass(cls): - 1/0 + 1//0 def test_foo(self): pass suite = unittest.TestSuite([Foo('test_foo')]) @@ -517,7 +517,7 @@ class Foo(unittest.TestCase): @classmethod def tearDownClass(cls): - 1/0 + 1//0 def test_foo(self): pass suite = unittest.TestSuite([Foo('test_foo')]) @@ -534,7 +534,7 @@ class Module(object): @staticmethod def setUpModule(): - 1/0 + 1//0 Foo.__module__ = 'Module' sys.modules['Module'] = Module @@ -553,7 +553,7 @@ class Module(object): @staticmethod def tearDownModule(): - 1/0 + 1//0 Foo.__module__ = 'Module' sys.modules['Module'] = Module -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon May 9 04:59:05 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 09 May 2011 04:59:05 +0200 Subject: [Python-checkins] Daily reference leaks (e7d8713f95f3): sum=0 Message-ID: results for e7d8713f95f3 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog7RGAOM', '-x'] From python-checkins at python.org Mon May 9 05:28:57 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 05:28:57 +0200 Subject: [Python-checkins] cpython (2.7): #11910: change import_fresh_module to return None when one of the "fresh" Message-ID: http://hg.python.org/cpython/rev/c1a12a308c5b changeset: 69954:c1a12a308c5b branch: 2.7 user: Ezio Melotti date: Mon May 09 06:28:42 2011 +0300 summary: #11910: change import_fresh_module to return None when one of the "fresh" modules can not be imported. files: Lib/test/test_support.py | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -84,12 +84,14 @@ def _save_and_remove_module(name, orig_modules): """Helper function to save and remove a module from sys.modules - Return value is True if the module was in sys.modules and - False otherwise.""" + Return True if the module was in sys.modules, False otherwise. + Raise ImportError if the module can't be imported.""" saved = True try: orig_modules[name] = sys.modules[name] except KeyError: + # try to import the module and raise an error if it can't be imported + __import__(name) saved = False else: del sys.modules[name] @@ -99,8 +101,7 @@ def _save_and_block_module(name, orig_modules): """Helper function to save and block a module in sys.modules - Return value is True if the module was in sys.modules and - False otherwise.""" + Return True if the module was in sys.modules, False otherwise.""" saved = True try: orig_modules[name] = sys.modules[name] @@ -116,6 +117,7 @@ the sys.modules cache is restored to its original state. Modules named in fresh are also imported anew if needed by the import. + If one of these modules can't be imported, None is returned. Importing of modules named in blocked is prevented while the fresh import takes place. @@ -137,6 +139,8 @@ if not _save_and_block_module(blocked_name, orig_modules): names_to_remove.append(blocked_name) fresh_module = importlib.import_module(name) + except ImportError: + fresh_module = None finally: for orig_name, module in orig_modules.items(): sys.modules[orig_name] = module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 05:44:47 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 05:44:47 +0200 Subject: [Python-checkins] cpython (3.1): #11910: change import_fresh_module to return None when one of the "fresh" Message-ID: http://hg.python.org/cpython/rev/3ab1eb027856 changeset: 69955:3ab1eb027856 branch: 3.1 parent: 69950:e4acbe2c8164 user: Ezio Melotti date: Mon May 09 06:41:55 2011 +0300 summary: #11910: change import_fresh_module to return None when one of the "fresh" modules can not be imported. files: Lib/test/support.py | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -80,12 +80,14 @@ def _save_and_remove_module(name, orig_modules): """Helper function to save and remove a module from sys.modules - Return value is True if the module was in sys.modules and - False otherwise.""" + Return True if the module was in sys.modules, False otherwise. + Raise ImportError if the module can't be imported.""" saved = True try: orig_modules[name] = sys.modules[name] except KeyError: + # try to import the module and raise an error if it can't be imported + __import__(name) saved = False else: del sys.modules[name] @@ -95,8 +97,7 @@ def _save_and_block_module(name, orig_modules): """Helper function to save and block a module in sys.modules - Return value is True if the module was in sys.modules and - False otherwise.""" + Return True if the module was in sys.modules, False otherwise.""" saved = True try: orig_modules[name] = sys.modules[name] @@ -112,6 +113,7 @@ the sys.modules cache is restored to its original state. Modules named in fresh are also imported anew if needed by the import. + If one of these modules can't be imported, None is returned. Importing of modules named in blocked is prevented while the fresh import takes place. @@ -133,6 +135,8 @@ if not _save_and_block_module(blocked_name, orig_modules): names_to_remove.append(blocked_name) fresh_module = importlib.import_module(name) + except ImportError: + fresh_module = None finally: for orig_name, module in orig_modules.items(): sys.modules[orig_name] = module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 05:44:48 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 05:44:48 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11910: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/754bafe8db5f changeset: 69956:754bafe8db5f branch: 3.2 parent: 69951:0ea2c5866e7d parent: 69955:3ab1eb027856 user: Ezio Melotti date: Mon May 09 06:43:14 2011 +0300 summary: #11910: merge with 3.1. files: Lib/test/support.py | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -92,12 +92,14 @@ def _save_and_remove_module(name, orig_modules): """Helper function to save and remove a module from sys.modules - Return value is True if the module was in sys.modules and - False otherwise.""" + Return True if the module was in sys.modules, False otherwise. + Raise ImportError if the module can't be imported.""" saved = True try: orig_modules[name] = sys.modules[name] except KeyError: + # try to import the module and raise an error if it can't be imported + __import__(name) saved = False else: del sys.modules[name] @@ -107,8 +109,7 @@ def _save_and_block_module(name, orig_modules): """Helper function to save and block a module in sys.modules - Return value is True if the module was in sys.modules and - False otherwise.""" + Return True if the module was in sys.modules, False otherwise.""" saved = True try: orig_modules[name] = sys.modules[name] @@ -124,6 +125,7 @@ the sys.modules cache is restored to its original state. Modules named in fresh are also imported anew if needed by the import. + If one of these modules can't be imported, None is returned. Importing of modules named in blocked is prevented while the fresh import takes place. @@ -145,6 +147,8 @@ if not _save_and_block_module(blocked_name, orig_modules): names_to_remove.append(blocked_name) fresh_module = importlib.import_module(name) + except ImportError: + fresh_module = None finally: for orig_name, module in orig_modules.items(): sys.modules[orig_name] = module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 05:44:48 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 05:44:48 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11910: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/3e8f0111feed changeset: 69957:3e8f0111feed parent: 69952:e7d8713f95f3 parent: 69956:754bafe8db5f user: Ezio Melotti date: Mon May 09 06:44:36 2011 +0300 summary: #11910: merge with 3.2. files: Lib/test/support.py | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -91,12 +91,14 @@ def _save_and_remove_module(name, orig_modules): """Helper function to save and remove a module from sys.modules - Return value is True if the module was in sys.modules and - False otherwise.""" + Return True if the module was in sys.modules, False otherwise. + Raise ImportError if the module can't be imported.""" saved = True try: orig_modules[name] = sys.modules[name] except KeyError: + # try to import the module and raise an error if it can't be imported + __import__(name) saved = False else: del sys.modules[name] @@ -106,8 +108,7 @@ def _save_and_block_module(name, orig_modules): """Helper function to save and block a module in sys.modules - Return value is True if the module was in sys.modules and - False otherwise.""" + Return True if the module was in sys.modules, False otherwise.""" saved = True try: orig_modules[name] = sys.modules[name] @@ -123,6 +124,7 @@ the sys.modules cache is restored to its original state. Modules named in fresh are also imported anew if needed by the import. + If one of these modules can't be imported, None is returned. Importing of modules named in blocked is prevented while the fresh import takes place. @@ -144,6 +146,8 @@ if not _save_and_block_module(blocked_name, orig_modules): names_to_remove.append(blocked_name) fresh_module = importlib.import_module(name) + except ImportError: + fresh_module = None finally: for orig_name, module in orig_modules.items(): sys.modules[orig_name] = module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 06:30:36 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 06:30:36 +0200 Subject: [Python-checkins] cpython (2.7): #11910: Fix test_heapq to skip the C tests when _heapq is missing. Message-ID: http://hg.python.org/cpython/rev/3cbbb2a7c56d changeset: 69958:3cbbb2a7c56d branch: 2.7 parent: 69954:c1a12a308c5b user: Ezio Melotti date: Mon May 09 06:54:53 2011 +0300 summary: #11910: Fix test_heapq to skip the C tests when _heapq is missing. files: Lib/test/test_heapq.py | 44 +++++++++++++++++++---------- Misc/NEWS | 2 + 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -1,16 +1,31 @@ """Unittests for heapq.""" +import sys import random -import unittest + from test import test_support -import sys +from unittest import TestCase, skipUnless -# We do a bit of trickery here to be able to test both the C implementation -# and the Python implementation of the module. -import heapq as c_heapq py_heapq = test_support.import_fresh_module('heapq', blocked=['_heapq']) +c_heapq = test_support.import_fresh_module('heapq', fresh=['_heapq']) -class TestHeap(unittest.TestCase): +# _heapq.nlargest/nsmallest are saved in heapq._nlargest/_smallest when +# _heapq is imported, so check them there +func_names = ['heapify', 'heappop', 'heappush', 'heappushpop', + 'heapreplace', '_nlargest', '_nsmallest'] + +class TestModules(TestCase): + def test_py_functions(self): + for fname in func_names: + self.assertEqual(getattr(py_heapq, fname).__module__, 'heapq') + + @skipUnless(c_heapq, 'requires _heapq') + def test_c_functions(self): + for fname in func_names: + self.assertEqual(getattr(c_heapq, fname).__module__, '_heapq') + + +class TestHeap(TestCase): module = None def test_push_pop(self): @@ -175,16 +190,12 @@ self.assertEqual(self.module.nlargest(n, data, key=f), sorted(data, key=f, reverse=True)[:n]) + class TestHeapPython(TestHeap): module = py_heapq - # As an early adopter, we sanity check the - # test_support.import_fresh_module utility function - def test_pure_python(self): - self.assertFalse(sys.modules['heapq'] is self.module) - self.assertTrue(hasattr(self.module.heapify, 'func_code')) - + at skipUnless(c_heapq, 'requires _heapq') class TestHeapC(TestHeap): module = c_heapq @@ -304,7 +315,7 @@ 'Test multiple tiers of iterators' return chain(imap(lambda x:x, R(Ig(G(seqn))))) -class TestErrorHandling(unittest.TestCase): +class TestErrorHandling(TestCase): def test_non_sequence(self): for f in (self.module.heapify, self.module.heappop): @@ -349,9 +360,12 @@ self.assertRaises(TypeError, f, 2, N(s)) self.assertRaises(ZeroDivisionError, f, 2, E(s)) + class TestErrorHandling_Python(TestErrorHandling): module = py_heapq + + at skipUnless(c_heapq, 'requires _heapq') class TestErrorHandling_C(TestErrorHandling): module = c_heapq @@ -360,8 +374,8 @@ def test_main(verbose=None): - test_classes = [TestHeapPython, TestHeapC, TestErrorHandling_Python, - TestErrorHandling_C] + test_classes = [TestModules, TestHeapPython, TestHeapC, + TestErrorHandling_Python, TestErrorHandling_C] test_support.run_unittest(*test_classes) # verify reference counting diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -421,6 +421,8 @@ Tests ----- +- Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. + - Fix test_startfile to wait for child process to terminate before finishing. - Issue #11719: Fix message about unexpected test_msilib skip on non-Windows -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 06:30:37 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 06:30:37 +0200 Subject: [Python-checkins] cpython (3.1): #11910: Fix test_heapq to skip the C tests when _heapq is missing. Message-ID: http://hg.python.org/cpython/rev/677ee366c9f5 changeset: 69959:677ee366c9f5 branch: 3.1 parent: 69955:3ab1eb027856 user: Ezio Melotti date: Mon May 09 07:15:04 2011 +0300 summary: #11910: Fix test_heapq to skip the C tests when _heapq is missing. files: Lib/test/test_heapq.py | 47 +++++++++++++++++------------ Misc/NEWS | 2 + 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -1,16 +1,31 @@ """Unittests for heapq.""" +import sys import random -import unittest + from test import support -import sys +from unittest import TestCase, skipUnless -# We do a bit of trickery here to be able to test both the C implementation -# and the Python implementation of the module. -import heapq as c_heapq py_heapq = support.import_fresh_module('heapq', blocked=['_heapq']) +c_heapq = support.import_fresh_module('heapq', fresh=['_heapq']) -class TestHeap(unittest.TestCase): +# _heapq.nlargest/nsmallest are saved in heapq._nlargest/_smallest when +# _heapq is imported, so check them there +func_names = ['heapify', 'heappop', 'heappush', 'heappushpop', + 'heapreplace', '_nlargest', '_nsmallest'] + +class TestModules(TestCase): + def test_py_functions(self): + for fname in func_names: + self.assertEqual(getattr(py_heapq, fname).__module__, 'heapq') + + @skipUnless(c_heapq, 'requires _heapq') + def test_c_functions(self): + for fname in func_names: + self.assertEqual(getattr(c_heapq, fname).__module__, '_heapq') + + +class TestHeap(TestCase): module = None def test_push_pop(self): @@ -176,16 +191,12 @@ self.assertEqual(list(self.module.nlargest(n, data, key=f)), sorted(data, key=f, reverse=True)[:n]) + class TestHeapPython(TestHeap): module = py_heapq - # As an early adopter, we sanity check the - # test.support.import_fresh_module utility function - def test_pure_python(self): - self.assertFalse(sys.modules['heapq'] is self.module) - self.assertTrue(hasattr(self.module.heapify, '__code__')) - + at skipUnless(c_heapq, 'requires _heapq') class TestHeapC(TestHeap): module = c_heapq @@ -211,12 +222,6 @@ self.assertEqual(hsort(data, LT), target) self.assertRaises(TypeError, data, LE) - # As an early adopter, we sanity check the - # test.support.import_fresh_module utility function - def test_accelerated(self): - self.assertTrue(sys.modules['heapq'] is self.module) - self.assertFalse(hasattr(self.module.heapify, '__code__')) - #============================================================================== @@ -313,7 +318,9 @@ 'Test multiple tiers of iterators' return chain(map(lambda x:x, R(Ig(G(seqn))))) -class TestErrorHandling(unittest.TestCase): + + at skipUnless(c_heapq, 'requires _heapq') +class TestErrorHandling(TestCase): # only for C implementation module = c_heapq @@ -372,7 +379,7 @@ def test_main(verbose=None): from types import BuiltinFunctionType - test_classes = [TestHeapPython, TestHeapC, TestErrorHandling] + test_classes = [TestModules, TestHeapPython, TestHeapC, TestErrorHandling] support.run_unittest(*test_classes) # verify reference counting diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -353,6 +353,8 @@ Tests ----- +- Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. + - Fix test_startfile to wait for child process to terminate before finishing. - Issue #11719: Fix message about unexpected test_msilib skip on non-Windows -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 06:30:40 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 06:30:40 +0200 Subject: [Python-checkins] cpython (3.2): Some tests were incorrectly marked as C specific. Message-ID: http://hg.python.org/cpython/rev/07d124f340cd changeset: 69960:07d124f340cd branch: 3.2 parent: 69956:754bafe8db5f user: Ezio Melotti date: Mon May 09 07:20:47 2011 +0300 summary: Some tests were incorrectly marked as C specific. files: Lib/test/test_heapq.py | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -308,8 +308,7 @@ return chain(map(lambda x:x, R(Ig(G(seqn))))) class TestErrorHandling(unittest.TestCase): - # only for C implementation - module = c_heapq + module = None def test_non_sequence(self): for f in (self.module.heapify, self.module.heappop): @@ -359,12 +358,19 @@ self.assertRaises(TypeError, f, 2, N(s)) self.assertRaises(ZeroDivisionError, f, 2, E(s)) +class TestErrorHandlingPython(TestErrorHandling): + module = py_heapq + +class TestErrorHandlingC(TestErrorHandling): + module = c_heapq + #============================================================================== def test_main(verbose=None): - test_classes = [TestHeapPython, TestHeapC, TestErrorHandling] + test_classes = [TestHeapPython, TestHeapC, TestErrorHandlingPython, + TestErrorHandlingC] support.run_unittest(*test_classes) # verify reference counting -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 06:30:43 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 06:30:43 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11910: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/4f3f67a595fb changeset: 69961:4f3f67a595fb branch: 3.2 parent: 69960:07d124f340cd parent: 69959:677ee366c9f5 user: Ezio Melotti date: Mon May 09 07:27:20 2011 +0300 summary: #11910: merge with 3.1. files: Lib/test/test_heapq.py | 44 +++++++++++++++++++---------- Misc/NEWS | 2 + 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -1,16 +1,31 @@ """Unittests for heapq.""" +import sys import random -import unittest + from test import support -import sys +from unittest import TestCase, skipUnless -# We do a bit of trickery here to be able to test both the C implementation -# and the Python implementation of the module. -import heapq as c_heapq py_heapq = support.import_fresh_module('heapq', blocked=['_heapq']) +c_heapq = support.import_fresh_module('heapq', fresh=['_heapq']) -class TestHeap(unittest.TestCase): +# _heapq.nlargest/nsmallest are saved in heapq._nlargest/_smallest when +# _heapq is imported, so check them there +func_names = ['heapify', 'heappop', 'heappush', 'heappushpop', + 'heapreplace', '_nlargest', '_nsmallest'] + +class TestModules(TestCase): + def test_py_functions(self): + for fname in func_names: + self.assertEqual(getattr(py_heapq, fname).__module__, 'heapq') + + @skipUnless(c_heapq, 'requires _heapq') + def test_c_functions(self): + for fname in func_names: + self.assertEqual(getattr(c_heapq, fname).__module__, '_heapq') + + +class TestHeap(TestCase): module = None def test_push_pop(self): @@ -176,16 +191,12 @@ self.assertEqual(list(self.module.nlargest(n, data, key=f)), sorted(data, key=f, reverse=True)[:n]) + class TestHeapPython(TestHeap): module = py_heapq - # As an early adopter, we sanity check the - # test.support.import_fresh_module utility function - def test_pure_python(self): - self.assertFalse(sys.modules['heapq'] is self.module) - self.assertTrue(hasattr(self.module.heapify, '__code__')) - + at skipUnless(c_heapq, 'requires _heapq') class TestHeapC(TestHeap): module = c_heapq @@ -307,7 +318,8 @@ 'Test multiple tiers of iterators' return chain(map(lambda x:x, R(Ig(G(seqn))))) -class TestErrorHandling(unittest.TestCase): + +class TestErrorHandling(TestCase): module = None def test_non_sequence(self): @@ -358,9 +370,11 @@ self.assertRaises(TypeError, f, 2, N(s)) self.assertRaises(ZeroDivisionError, f, 2, E(s)) + class TestErrorHandlingPython(TestErrorHandling): module = py_heapq + at skipUnless(c_heapq, 'requires _heapq') class TestErrorHandlingC(TestErrorHandling): module = c_heapq @@ -369,8 +383,8 @@ def test_main(verbose=None): - test_classes = [TestHeapPython, TestHeapC, TestErrorHandlingPython, - TestErrorHandlingC] + test_classes = [TestModules, TestHeapPython, TestHeapC, + TestErrorHandlingPython, TestErrorHandlingC] support.run_unittest(*test_classes) # verify reference counting diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -826,6 +826,8 @@ Tests ----- +- Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. + - Fix test_startfile to wait for child process to terminate before finishing. - Issue #10822: Fix test_posix:test_getgroups failure under Solaris. Patch -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 06:30:44 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 06:30:44 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11910: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/3449406fd04a changeset: 69962:3449406fd04a parent: 69957:3e8f0111feed parent: 69961:4f3f67a595fb user: Ezio Melotti date: Mon May 09 07:30:21 2011 +0300 summary: #11910: merge with 3.2. files: Lib/test/test_heapq.py | 52 ++++++++++++++++++++--------- Misc/NEWS | 2 + 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -1,16 +1,31 @@ """Unittests for heapq.""" +import sys import random -import unittest + from test import support -import sys +from unittest import TestCase, skipUnless -# We do a bit of trickery here to be able to test both the C implementation -# and the Python implementation of the module. -import heapq as c_heapq py_heapq = support.import_fresh_module('heapq', blocked=['_heapq']) +c_heapq = support.import_fresh_module('heapq', fresh=['_heapq']) -class TestHeap(unittest.TestCase): +# _heapq.nlargest/nsmallest are saved in heapq._nlargest/_smallest when +# _heapq is imported, so check them there +func_names = ['heapify', 'heappop', 'heappush', 'heappushpop', + 'heapreplace', '_nlargest', '_nsmallest'] + +class TestModules(TestCase): + def test_py_functions(self): + for fname in func_names: + self.assertEqual(getattr(py_heapq, fname).__module__, 'heapq') + + @skipUnless(c_heapq, 'requires _heapq') + def test_c_functions(self): + for fname in func_names: + self.assertEqual(getattr(c_heapq, fname).__module__, '_heapq') + + +class TestHeap(TestCase): module = None def test_push_pop(self): @@ -176,16 +191,12 @@ self.assertEqual(list(self.module.nlargest(n, data, key=f)), sorted(data, key=f, reverse=True)[:n]) + class TestHeapPython(TestHeap): module = py_heapq - # As an early adopter, we sanity check the - # test.support.import_fresh_module utility function - def test_pure_python(self): - self.assertFalse(sys.modules['heapq'] is self.module) - self.assertTrue(hasattr(self.module.heapify, '__code__')) - + at skipUnless(c_heapq, 'requires _heapq') class TestHeapC(TestHeap): module = c_heapq @@ -307,9 +318,9 @@ 'Test multiple tiers of iterators' return chain(map(lambda x:x, R(Ig(G(seqn))))) -class TestErrorHandling(unittest.TestCase): - # only for C implementation - module = c_heapq + +class TestErrorHandling(TestCase): + module = None def test_non_sequence(self): for f in (self.module.heapify, self.module.heappop): @@ -360,11 +371,20 @@ self.assertRaises(ZeroDivisionError, f, 2, E(s)) +class TestErrorHandlingPython(TestErrorHandling): + module = py_heapq + + at skipUnless(c_heapq, 'requires _heapq') +class TestErrorHandlingC(TestErrorHandling): + module = c_heapq + + #============================================================================== def test_main(verbose=None): - test_classes = [TestHeapPython, TestHeapC, TestErrorHandling] + test_classes = [TestModules, TestHeapPython, TestHeapC, + TestErrorHandlingPython, TestErrorHandlingC] support.run_unittest(*test_classes) # verify reference counting diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1132,6 +1132,8 @@ Tests ----- +- Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. + - Fix test_startfile to wait for child process to terminate before finishing. - Issue #10822: Fix test_posix:test_getgroups failure under Solaris. Patch -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 07:43:36 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 May 2011 07:43:36 +0200 Subject: [Python-checkins] cpython (3.2): Use --as-needed when linking libpython3.so. Closes #11347. Message-ID: http://hg.python.org/cpython/rev/749686064642 changeset: 69963:749686064642 branch: 3.2 parent: 69961:4f3f67a595fb user: Martin v. L?wis date: Mon May 09 07:37:45 2011 +0200 summary: Use --as-needed when linking libpython3.so. Closes #11347. Patch by Arfrever Frehtes Taifersar Arahesis. files: Makefile.pre.in | 3 +- Misc/NEWS | 2 + configure | 125 ++++++++++++++++++++++------------- configure.in | 12 +++ 4 files changed, 94 insertions(+), 48 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -76,6 +76,7 @@ # environment variables PY_CPPFLAGS= -I. -IInclude -I$(srcdir)/Include $(CONFIGURE_CPPFLAGS) $(CPPFLAGS) PY_LDFLAGS= $(CONFIGURE_LDFLAGS) $(LDFLAGS) +NO_AS_NEEDED= @NO_AS_NEEDED@ LDLAST= @LDLAST@ SGI_ABI= @SGI_ABI@ CCSHARED= @CCSHARED@ @@ -459,7 +460,7 @@ fi libpython3.so: libpython$(LDVERSION).so - $(BLDSHARED) -o $@ -Wl,-hl$@ $^ + $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^ libpython$(LDVERSION).dylib: $(LIBRARY_OBJS) $(CC) -dynamiclib -Wl,-single_module $(PY_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -313,6 +313,8 @@ Build ----- +- Issue #11347: Use --as-needed when linking libpython3.so. + - Issue #11411: Fix 'make DESTDIR=' with a relative destination. - Issue #11268: Prevent Mac OS X Installer failure if Documentation diff --git a/configure b/configure --- a/configure +++ b/configure @@ -668,6 +668,7 @@ EGREP GREP CPP +NO_AS_NEEDED MAINCC CXX OBJEXT @@ -1572,6 +1573,52 @@ } # ac_fn_c_try_compile +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. @@ -1773,52 +1820,6 @@ } # ac_fn_c_check_header_compile -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache @@ -4168,8 +4169,38 @@ fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wl,--no-as-needed" >&5 +$as_echo_n "checking for -Wl,--no-as-needed... " >&6; } +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS -Wl,--no-as-needed" + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + NO_AS_NEEDED="-Wl,--no-as-needed" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + NO_AS_NEEDED="" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LDFLAGS="$save_LDFLAGS" + + + # checks for UNIX variants that set C preprocessor variables - ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -525,6 +525,18 @@ fi +AC_MSG_CHECKING([for -Wl,--no-as-needed]) +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS -Wl,--no-as-needed" +AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [NO_AS_NEEDED="-Wl,--no-as-needed" + AC_MSG_RESULT([yes])], + [NO_AS_NEEDED="" + AC_MSG_RESULT([no])]) +LDFLAGS="$save_LDFLAGS" +AC_SUBST(NO_AS_NEEDED) + + # checks for UNIX variants that set C preprocessor variables AC_USE_SYSTEM_EXTENSIONS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 07:43:37 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 May 2011 07:43:37 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge 11347. Message-ID: http://hg.python.org/cpython/rev/4bc0d1b45898 changeset: 69964:4bc0d1b45898 parent: 69962:3449406fd04a parent: 69963:749686064642 user: Martin v. L?wis date: Mon May 09 07:41:32 2011 +0200 summary: merge 11347. files: Makefile.pre.in | 3 +- Misc/NEWS | 2 + configure | 1160 ++++++++++++++++++---------------- configure.in | 12 + 4 files changed, 633 insertions(+), 544 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -75,6 +75,7 @@ # environment variables PY_CPPFLAGS= -I. -IInclude -I$(srcdir)/Include $(CONFIGURE_CPPFLAGS) $(CPPFLAGS) PY_LDFLAGS= $(CONFIGURE_LDFLAGS) $(LDFLAGS) +NO_AS_NEEDED= @NO_AS_NEEDED@ LDLAST= @LDLAST@ SGI_ABI= @SGI_ABI@ CCSHARED= @CCSHARED@ @@ -459,7 +460,7 @@ fi libpython3.so: libpython$(LDVERSION).so - $(BLDSHARED) -o $@ -Wl,-hl$@ $^ + $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^ libpython$(LDVERSION).dylib: $(LIBRARY_OBJS) $(CC) -dynamiclib -Wl,-single_module $(PY_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -578,6 +578,8 @@ Build ----- +- Issue #11347: Use --as-needed when linking libpython3.so. + - Issue #11411: Fix 'make DESTDIR=' with a relative destination. - Issue #11268: Prevent Mac OS X Installer failure if Documentation diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,14 +1,14 @@ #! /bin/sh # From configure.in Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.65 for python 3.3. +# Generated by GNU Autoconf 2.68 for python 3.3. # # Report bugs to . # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. # # # This configure script is free software; the Free Software Foundation @@ -92,6 +92,7 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -217,11 +218,18 @@ # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -320,7 +328,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 +368,19 @@ fi # as_fn_arith -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS 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=$?; 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 + 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 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -534,7 +542,7 @@ exec 6>&1 # Name of the host. -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` @@ -659,6 +667,7 @@ EGREP GREP CPP +NO_AS_NEEDED MAINCC CXX OBJEXT @@ -831,8 +840,9 @@ fi case $ac_option in - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *) ac_optarg=yes ;; + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. @@ -877,7 +887,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 @@ -903,7 +913,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 @@ -1107,7 +1117,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 @@ -1123,7 +1133,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 @@ -1153,8 +1163,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" ;; *=*) @@ -1162,7 +1172,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 ;; @@ -1172,7 +1182,7 @@ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac @@ -1180,13 +1190,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 @@ -1209,7 +1219,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' @@ -1223,8 +1233,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 @@ -1239,9 +1249,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. @@ -1280,11 +1290,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 @@ -1324,7 +1334,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 +1519,9 @@ if $ac_init_version; then cat <<\_ACEOF python configure 3.3 -generated by GNU Autoconf 2.65 - -Copyright (C) 2009 Free Software Foundation, Inc. +generated by GNU Autoconf 2.68 + +Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1555,11 +1565,57 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. @@ -1581,7 +1637,7 @@ mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } >/dev/null && { + test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : @@ -1592,7 +1648,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp @@ -1605,10 +1661,10 @@ ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -1644,7 +1700,7 @@ else ac_header_preproc=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } @@ -1667,17 +1723,15 @@ $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;} -( cat <<\_ASBOX -## -------------------------------------- ## +( $as_echo "## -------------------------------------- ## ## 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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -1686,7 +1740,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel @@ -1727,7 +1781,7 @@ ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run @@ -1741,7 +1795,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -1759,56 +1813,10 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache @@ -1818,7 +1826,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1859,7 +1867,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type @@ -1872,7 +1880,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1902,8 +1910,7 @@ esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - eval as_val=\$$3 - if test "x$as_val" = x""no; then : + if eval test \"x\$"$3"\" = x"no"; then : else break @@ -1913,7 +1920,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t @@ -1926,7 +1933,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1937,11 +1944,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(enum { N = $2 / 2 - 1 }; - 0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0 ; @@ -1952,11 +1959,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !(enum { N = $2 / 2 - 1 }; - ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0 @@ -1977,8 +1984,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - eval as_val=\$$3 - if test "x$as_val" = x""no; then : + if eval test \"x\$"$3"\" = x"no"; then : else break @@ -1988,7 +1994,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t @@ -2165,7 +2171,7 @@ rm -f conftest.val fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_compute_int @@ -2178,7 +2184,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2233,7 +2239,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func @@ -2246,7 +2252,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 { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2290,19 +2296,22 @@ eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member -# ac_fn_c_check_decl LINENO SYMBOL VAR -# ------------------------------------ -# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. +# 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 () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $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_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 \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2311,8 +2320,12 @@ int main () { -#ifndef $2 - (void) $2; +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif #endif ; @@ -2329,7 +2342,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl cat >config.log <<_ACEOF @@ -2337,7 +2350,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by python $as_me 3.3, which was -generated by GNU Autoconf 2.65. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2447,11 +2460,9 @@ { echo - cat <<\_ASBOX -## ---------------- ## + $as_echo "## ---------------- ## ## Cache variables. ## -## ---------------- ## -_ASBOX +## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( @@ -2485,11 +2496,9 @@ ) echo - cat <<\_ASBOX -## ----------------- ## + $as_echo "## ----------------- ## ## Output variables. ## -## ----------------- ## -_ASBOX +## ----------------- ##" echo for ac_var in $ac_subst_vars do @@ -2502,11 +2511,9 @@ echo if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------------- ## + $as_echo "## ------------------- ## ## File substitutions. ## -## ------------------- ## -_ASBOX +## ------------------- ##" echo for ac_var in $ac_subst_files do @@ -2520,11 +2527,9 @@ fi if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## + $as_echo "## ----------- ## ## confdefs.h. ## -## ----------- ## -_ASBOX +## ----------- ##" echo cat confdefs.h echo @@ -2579,7 +2584,12 @@ ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - ac_site_file1=$CONFIG_SITE + # 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 elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site @@ -2594,7 +2604,11 @@ { $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" + . "$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; } fi done @@ -2670,7 +2684,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. ## @@ -2771,7 +2785,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 @@ -3163,7 +3177,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 @@ -3183,7 +3197,7 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3223,7 +3237,7 @@ set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3276,7 +3290,7 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3316,7 +3330,7 @@ set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3375,7 +3389,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3419,7 +3433,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3473,8 +3487,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 @@ -3588,9 +3602,8 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "C compiler cannot create executables -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "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; } @@ -3632,8 +3645,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 @@ -3690,9 +3703,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 @@ -3703,7 +3716,7 @@ ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then : +if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3743,8 +3756,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 @@ -3754,7 +3767,7 @@ ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then : +if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3791,7 +3804,7 @@ ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then : +if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag @@ -3869,7 +3882,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then : +if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no @@ -4004,7 +4017,7 @@ set dummy g++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CXX+set}" = set; then : +if ${ac_cv_path_CXX+:} false; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4045,7 +4058,7 @@ set dummy c++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CXX+set}" = set; then : +if ${ac_cv_path_CXX+:} false; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4096,7 +4109,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CXX+set}" = set; then : +if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then @@ -4153,8 +4166,38 @@ fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wl,--no-as-needed" >&5 +$as_echo_n "checking for -Wl,--no-as-needed... " >&6; } +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS -Wl,--no-as-needed" + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + NO_AS_NEEDED="-Wl,--no-as-needed" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + NO_AS_NEEDED="" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LDFLAGS="$save_LDFLAGS" + + + # checks for UNIX variants that set C preprocessor variables - ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4167,7 +4210,7 @@ CPP= fi if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then : + if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded @@ -4197,7 +4240,7 @@ # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -4213,11 +4256,11 @@ ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi @@ -4256,7 +4299,7 @@ # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -4272,18 +4315,18 @@ ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i 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 @@ -4295,7 +4338,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then : +if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -4344,7 +4387,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 @@ -4358,7 +4401,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then : +if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -4410,7 +4453,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 @@ -4425,7 +4468,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4542,8 +4585,7 @@ 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 " -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -4555,7 +4597,7 @@ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = x""yes; then : +if test "x$ac_cv_header_minix_config_h" = xyes; then : MINIX=yes else MINIX= @@ -4577,7 +4619,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : +if ${ac_cv_safe_to_define___extensions__+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4770,7 +4812,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } -if test "${ac_cv_c_inline+set}" = set; then : +if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no @@ -4966,7 +5008,7 @@ set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then : +if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then @@ -5006,7 +5048,7 @@ set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then @@ -5060,7 +5102,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AR+set}" = set; then : +if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then @@ -5112,7 +5154,7 @@ set dummy hg; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_HAS_HG+set}" = set; then : +if ${ac_cv_prog_HAS_HG+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$HAS_HG"; then @@ -5167,16 +5209,22 @@ esac ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - 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 + 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 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, @@ -5205,7 +5253,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if test "${ac_cv_path_install+set}" = set; then : +if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5391,7 +5439,7 @@ ac_save_cc="$CC" CC="$CC -fno-strict-aliasing" save_CFLAGS="$CFLAGS" - if test "${ac_cv_no_strict_aliasing+set}" = set; then : + if ${ac_cv_no_strict_aliasing+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5514,7 +5562,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 @@ -5641,7 +5689,7 @@ # options before we can check whether -Kpthread improves anything. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads are available without options" >&5 $as_echo_n "checking whether pthreads are available without options... " >&6; } -if test "${ac_cv_pthread_is_default+set}" = set; then : +if ${ac_cv_pthread_is_default+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -5694,7 +5742,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kpthread" >&5 $as_echo_n "checking whether $CC accepts -Kpthread... " >&6; } -if test "${ac_cv_kpthread+set}" = set; then : +if ${ac_cv_kpthread+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5743,7 +5791,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kthread" >&5 $as_echo_n "checking whether $CC accepts -Kthread... " >&6; } -if test "${ac_cv_kthread+set}" = set; then : +if ${ac_cv_kthread+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5792,7 +5840,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -pthread" >&5 $as_echo_n "checking whether $CC accepts -pthread... " >&6; } -if test "${ac_cv_thread+set}" = set; then : +if ${ac_cv_thread+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5877,7 +5925,7 @@ # checks for header files { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6002,8 +6050,7 @@ 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" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -6017,7 +6064,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 { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6044,8 +6091,7 @@ eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF @@ -6058,7 +6104,7 @@ if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6092,11 +6138,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no @@ -6115,7 +6161,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6149,11 +6195,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no @@ -6173,7 +6219,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 $as_echo_n "checking whether sys/types.h defines makedev... " >&6; } -if test "${ac_cv_header_sys_types_h_makedev+set}" = set; then : +if ${ac_cv_header_sys_types_h_makedev+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6201,7 +6247,7 @@ if test $ac_cv_header_sys_types_h_makedev = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = x""yes; then : +if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : $as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h @@ -6211,7 +6257,7 @@ if test $ac_cv_header_sys_mkdev_h = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = x""yes; then : +if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then : $as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h @@ -6231,7 +6277,7 @@ #endif " -if test "x$ac_cv_header_term_h" = x""yes; then : +if test "x$ac_cv_header_term_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_TERM_H 1 _ACEOF @@ -6253,7 +6299,7 @@ #endif " -if test "x$ac_cv_header_linux_netlink_h" = x""yes; then : +if test "x$ac_cv_header_linux_netlink_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_NETLINK_H 1 _ACEOF @@ -6389,7 +6435,7 @@ # Type availability checks ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" -if test "x$ac_cv_type_mode_t" = x""yes; then : +if test "x$ac_cv_type_mode_t" = xyes; then : else @@ -6400,7 +6446,7 @@ fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" -if test "x$ac_cv_type_off_t" = x""yes; then : +if test "x$ac_cv_type_off_t" = xyes; then : else @@ -6411,7 +6457,7 @@ fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = x""yes; then : +if test "x$ac_cv_type_pid_t" = xyes; then : else @@ -6427,7 +6473,7 @@ _ACEOF ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = x""yes; then : +if test "x$ac_cv_type_size_t" = xyes; then : else @@ -6439,7 +6485,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if test "${ac_cv_type_uid_t+set}" = set; then : +if ${ac_cv_type_uid_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6518,7 +6564,7 @@ esac ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" -if test "x$ac_cv_type_ssize_t" = x""yes; then : +if test "x$ac_cv_type_ssize_t" = xyes; then : $as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h @@ -6533,7 +6579,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 $as_echo_n "checking size of int... " >&6; } -if test "${ac_cv_sizeof_int+set}" = set; then : +if ${ac_cv_sizeof_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : @@ -6542,9 +6588,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (int) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (int) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int=0 fi @@ -6567,7 +6612,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } -if test "${ac_cv_sizeof_long+set}" = set; then : +if ${ac_cv_sizeof_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : @@ -6576,9 +6621,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (long) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long=0 fi @@ -6601,7 +6645,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 $as_echo_n "checking size of void *... " >&6; } -if test "${ac_cv_sizeof_void_p+set}" = set; then : +if ${ac_cv_sizeof_void_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : @@ -6610,9 +6654,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (void *) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (void *) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_void_p=0 fi @@ -6635,7 +6678,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 $as_echo_n "checking size of short... " >&6; } -if test "${ac_cv_sizeof_short+set}" = set; then : +if ${ac_cv_sizeof_short+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : @@ -6644,9 +6687,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (short) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (short) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_short=0 fi @@ -6669,7 +6711,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 $as_echo_n "checking size of float... " >&6; } -if test "${ac_cv_sizeof_float+set}" = set; then : +if ${ac_cv_sizeof_float+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default"; then : @@ -6678,9 +6720,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (float) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (float) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_float=0 fi @@ -6703,7 +6744,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 $as_echo_n "checking size of double... " >&6; } -if test "${ac_cv_sizeof_double+set}" = set; then : +if ${ac_cv_sizeof_double+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then : @@ -6712,9 +6753,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (double) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (double) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_double=0 fi @@ -6737,7 +6777,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 $as_echo_n "checking size of fpos_t... " >&6; } -if test "${ac_cv_sizeof_fpos_t+set}" = set; then : +if ${ac_cv_sizeof_fpos_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default"; then : @@ -6746,9 +6786,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (fpos_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (fpos_t) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_fpos_t=0 fi @@ -6771,7 +6810,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 $as_echo_n "checking size of size_t... " >&6; } -if test "${ac_cv_sizeof_size_t+set}" = set; then : +if ${ac_cv_sizeof_size_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : @@ -6780,9 +6819,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (size_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (size_t) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_size_t=0 fi @@ -6805,7 +6843,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 $as_echo_n "checking size of pid_t... " >&6; } -if test "${ac_cv_sizeof_pid_t+set}" = set; then : +if ${ac_cv_sizeof_pid_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default"; then : @@ -6814,9 +6852,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (pid_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (pid_t) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_pid_t=0 fi @@ -6866,7 +6903,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 $as_echo_n "checking size of long long... " >&6; } -if test "${ac_cv_sizeof_long_long+set}" = set; then : +if ${ac_cv_sizeof_long_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : @@ -6875,9 +6912,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (long long) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long long) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_long=0 fi @@ -6928,7 +6964,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 $as_echo_n "checking size of long double... " >&6; } -if test "${ac_cv_sizeof_long_double+set}" = set; then : +if ${ac_cv_sizeof_long_double+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then : @@ -6937,9 +6973,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (long double) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long double) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_double=0 fi @@ -6991,7 +7026,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of _Bool" >&5 $as_echo_n "checking size of _Bool... " >&6; } -if test "${ac_cv_sizeof__Bool+set}" = set; then : +if ${ac_cv_sizeof__Bool+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default"; then : @@ -7000,9 +7035,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (_Bool) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (_Bool) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof__Bool=0 fi @@ -7028,7 +7062,7 @@ #include #endif " -if test "x$ac_cv_type_uintptr_t" = x""yes; then : +if test "x$ac_cv_type_uintptr_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINTPTR_T 1 @@ -7040,7 +7074,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 $as_echo_n "checking size of uintptr_t... " >&6; } -if test "${ac_cv_sizeof_uintptr_t+set}" = set; then : +if ${ac_cv_sizeof_uintptr_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default"; then : @@ -7049,9 +7083,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (uintptr_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (uintptr_t) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uintptr_t=0 fi @@ -7077,7 +7110,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 $as_echo_n "checking size of off_t... " >&6; } -if test "${ac_cv_sizeof_off_t+set}" = set; then : +if ${ac_cv_sizeof_off_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " @@ -7091,9 +7124,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (off_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (off_t) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_off_t=0 fi @@ -7137,7 +7169,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 $as_echo_n "checking size of time_t... " >&6; } -if test "${ac_cv_sizeof_time_t+set}" = set; then : +if ${ac_cv_sizeof_time_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " @@ -7154,9 +7186,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (time_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (time_t) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_time_t=0 fi @@ -7213,7 +7244,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 $as_echo_n "checking size of pthread_t... " >&6; } -if test "${ac_cv_sizeof_pthread_t+set}" = set; then : +if ${ac_cv_sizeof_pthread_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " @@ -7227,9 +7258,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (pthread_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (pthread_t) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_pthread_t=0 fi @@ -7316,7 +7346,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 @@ -7328,7 +7358,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 @@ -7354,7 +7384,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 @@ -7660,7 +7690,7 @@ # checks for libraries { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile in -lsendfile" >&5 $as_echo_n "checking for sendfile in -lsendfile... " >&6; } -if test "${ac_cv_lib_sendfile_sendfile+set}" = set; then : +if ${ac_cv_lib_sendfile_sendfile+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7694,7 +7724,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sendfile_sendfile" >&5 $as_echo "$ac_cv_lib_sendfile_sendfile" >&6; } -if test "x$ac_cv_lib_sendfile_sendfile" = x""yes; then : +if test "x$ac_cv_lib_sendfile_sendfile" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSENDFILE 1 _ACEOF @@ -7705,7 +7735,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then : +if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7739,7 +7769,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF @@ -7750,7 +7780,7 @@ # Dynamic linking for SunOS/Solaris and SYSV { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } -if test "${ac_cv_lib_dld_shl_load+set}" = set; then : +if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7784,7 +7814,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDLD 1 _ACEOF @@ -7798,7 +7828,7 @@ if test "$with_threads" = "yes" -o -z "$with_threads"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5 $as_echo_n "checking for library containing sem_init... " >&6; } -if test "${ac_cv_search_sem_init+set}" = set; then : +if ${ac_cv_search_sem_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -7832,11 +7862,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_sem_init+set}" = set; then : + if ${ac_cv_search_sem_init+:} false; then : break fi done -if test "${ac_cv_search_sem_init+set}" = set; then : +if ${ac_cv_search_sem_init+:} false; then : else ac_cv_search_sem_init=no @@ -7859,7 +7889,7 @@ # check if we need libintl for locale functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for textdomain in -lintl" >&5 $as_echo_n "checking for textdomain in -lintl... " >&6; } -if test "${ac_cv_lib_intl_textdomain+set}" = set; then : +if ${ac_cv_lib_intl_textdomain+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7893,7 +7923,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_textdomain" >&5 $as_echo "$ac_cv_lib_intl_textdomain" >&6; } -if test "x$ac_cv_lib_intl_textdomain" = x""yes; then : +if test "x$ac_cv_lib_intl_textdomain" = xyes; then : $as_echo "#define WITH_LIBINTL 1" >>confdefs.h @@ -7940,7 +7970,7 @@ # Most SVR4 platforms (e.g. Solaris) need -lsocket and -lnsl. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for t_open in -lnsl" >&5 $as_echo_n "checking for t_open in -lnsl... " >&6; } -if test "${ac_cv_lib_nsl_t_open+set}" = set; then : +if ${ac_cv_lib_nsl_t_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7974,13 +8004,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 $as_echo "$ac_cv_lib_nsl_t_open" >&6; } -if test "x$ac_cv_lib_nsl_t_open" = x""yes; then : +if test "x$ac_cv_lib_nsl_t_open" = xyes; then : LIBS="-lnsl $LIBS" fi # SVR4 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 $as_echo_n "checking for socket in -lsocket... " >&6; } -if test "${ac_cv_lib_socket_socket+set}" = set; then : +if ${ac_cv_lib_socket_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8014,7 +8044,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 $as_echo "$ac_cv_lib_socket_socket" >&6; } -if test "x$ac_cv_lib_socket_socket" = x""yes; then : +if test "x$ac_cv_lib_socket_socket" = xyes; then : LIBS="-lsocket $LIBS" fi # SVR4 sockets @@ -8040,7 +8070,7 @@ set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_PKG_CONFIG+set}" = set; then : +if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in @@ -8083,7 +8113,7 @@ set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then : +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in @@ -8194,12 +8224,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 @@ -8348,7 +8378,7 @@ $as_echo "#define _REENTRANT 1" >>confdefs.h ac_fn_c_check_header_mongrel "$LINENO" "cthreads.h" "ac_cv_header_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_cthreads_h" = x""yes; then : +if test "x$ac_cv_header_cthreads_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8361,7 +8391,7 @@ else ac_fn_c_check_header_mongrel "$LINENO" "mach/cthreads.h" "ac_cv_header_mach_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_mach_cthreads_h" = x""yes; then : +if test "x$ac_cv_header_mach_cthreads_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8405,7 +8435,7 @@ LIBS=$_libs ac_fn_c_check_func "$LINENO" "pthread_detach" "ac_cv_func_pthread_detach" -if test "x$ac_cv_func_pthread_detach" = x""yes; then : +if test "x$ac_cv_func_pthread_detach" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8414,7 +8444,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 $as_echo_n "checking for pthread_create in -lpthreads... " >&6; } -if test "${ac_cv_lib_pthreads_pthread_create+set}" = set; then : +if ${ac_cv_lib_pthreads_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8448,7 +8478,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 $as_echo "$ac_cv_lib_pthreads_pthread_create" >&6; } -if test "x$ac_cv_lib_pthreads_pthread_create" = x""yes; then : +if test "x$ac_cv_lib_pthreads_pthread_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8458,7 +8488,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 $as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if test "${ac_cv_lib_c_r_pthread_create+set}" = set; then : +if ${ac_cv_lib_c_r_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8492,7 +8522,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 $as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = x""yes; then : +if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8502,7 +8532,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_create_system in -lpthread" >&5 $as_echo_n "checking for __pthread_create_system in -lpthread... " >&6; } -if test "${ac_cv_lib_pthread___pthread_create_system+set}" = set; then : +if ${ac_cv_lib_pthread___pthread_create_system+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8536,7 +8566,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_create_system" >&5 $as_echo "$ac_cv_lib_pthread___pthread_create_system" >&6; } -if test "x$ac_cv_lib_pthread___pthread_create_system" = x""yes; then : +if test "x$ac_cv_lib_pthread___pthread_create_system" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8546,7 +8576,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lcma" >&5 $as_echo_n "checking for pthread_create in -lcma... " >&6; } -if test "${ac_cv_lib_cma_pthread_create+set}" = set; then : +if ${ac_cv_lib_cma_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8580,7 +8610,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cma_pthread_create" >&5 $as_echo "$ac_cv_lib_cma_pthread_create" >&6; } -if test "x$ac_cv_lib_cma_pthread_create" = x""yes; then : +if test "x$ac_cv_lib_cma_pthread_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8612,7 +8642,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usconfig in -lmpc" >&5 $as_echo_n "checking for usconfig in -lmpc... " >&6; } -if test "${ac_cv_lib_mpc_usconfig+set}" = set; then : +if ${ac_cv_lib_mpc_usconfig+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8646,7 +8676,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mpc_usconfig" >&5 $as_echo "$ac_cv_lib_mpc_usconfig" >&6; } -if test "x$ac_cv_lib_mpc_usconfig" = x""yes; then : +if test "x$ac_cv_lib_mpc_usconfig" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lmpc" @@ -8658,7 +8688,7 @@ if test "$posix_threads" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for thr_create in -lthread" >&5 $as_echo_n "checking for thr_create in -lthread... " >&6; } -if test "${ac_cv_lib_thread_thr_create+set}" = set; then : +if ${ac_cv_lib_thread_thr_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8692,7 +8722,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_thread_thr_create" >&5 $as_echo "$ac_cv_lib_thread_thr_create" >&6; } -if test "x$ac_cv_lib_thread_thr_create" = x""yes; then : +if test "x$ac_cv_lib_thread_thr_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lthread" @@ -8732,7 +8762,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PTHREAD_SCOPE_SYSTEM is supported" >&5 $as_echo_n "checking if PTHREAD_SCOPE_SYSTEM is supported... " >&6; } - if test "${ac_cv_pthread_system_supported+set}" = set; then : + if ${ac_cv_pthread_system_supported+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -8775,7 +8805,7 @@ for ac_func in pthread_sigmask do : ac_fn_c_check_func "$LINENO" "pthread_sigmask" "ac_cv_func_pthread_sigmask" -if test "x$ac_cv_func_pthread_sigmask" = x""yes; then : +if test "x$ac_cv_func_pthread_sigmask" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_SIGMASK 1 _ACEOF @@ -9167,12 +9197,12 @@ $as_echo "$with_valgrind" >&6; } if test "$with_valgrind" != no; then ac_fn_c_check_header_mongrel "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_valgrind_h" = x""yes; then : +if test "x$ac_cv_header_valgrind_valgrind_h" = xyes; then : $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 @@ -9189,7 +9219,7 @@ for ac_func in dlopen do : ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = x""yes; then : +if test "x$ac_cv_func_dlopen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLOPEN 1 _ACEOF @@ -9270,8 +9300,7 @@ 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -9521,7 +9550,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock declaration" >&5 $as_echo_n "checking for flock declaration... " >&6; } -if test "${ac_cv_flock_decl+set}" = set; then : +if ${ac_cv_flock_decl+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -9551,7 +9580,7 @@ for ac_func in flock do : ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" -if test "x$ac_cv_func_flock" = x""yes; then : +if test "x$ac_cv_func_flock" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FLOCK 1 _ACEOF @@ -9559,7 +9588,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 $as_echo_n "checking for flock in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_flock+set}" = set; then : +if ${ac_cv_lib_bsd_flock+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9593,7 +9622,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_flock" >&5 $as_echo "$ac_cv_lib_bsd_flock" >&6; } -if test "x$ac_cv_lib_bsd_flock" = x""yes; then : +if test "x$ac_cv_lib_bsd_flock" = xyes; then : $as_echo "#define HAVE_FLOCK 1" >>confdefs.h @@ -9670,7 +9699,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_TRUE+set}" = set; then : +if ${ac_cv_prog_TRUE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$TRUE"; then @@ -9710,7 +9739,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lc" >&5 $as_echo_n "checking for inet_aton in -lc... " >&6; } -if test "${ac_cv_lib_c_inet_aton+set}" = set; then : +if ${ac_cv_lib_c_inet_aton+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9744,12 +9773,12 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_aton" >&5 $as_echo "$ac_cv_lib_c_inet_aton" >&6; } -if test "x$ac_cv_lib_c_inet_aton" = x""yes; then : +if test "x$ac_cv_lib_c_inet_aton" = xyes; then : $ac_cv_prog_TRUE else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 $as_echo_n "checking for inet_aton in -lresolv... " >&6; } -if test "${ac_cv_lib_resolv_inet_aton+set}" = set; then : +if ${ac_cv_lib_resolv_inet_aton+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9783,7 +9812,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5 $as_echo "$ac_cv_lib_resolv_inet_aton" >&6; } -if test "x$ac_cv_lib_resolv_inet_aton" = x""yes; then : +if test "x$ac_cv_lib_resolv_inet_aton" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF @@ -9800,7 +9829,7 @@ # exit Python { $as_echo "$as_me:${as_lineno-$LINENO}: checking for chflags" >&5 $as_echo_n "checking for chflags... " >&6; } -if test "${ac_cv_have_chflags+set}" = set; then : +if ${ac_cv_have_chflags+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -9834,7 +9863,7 @@ $as_echo "$ac_cv_have_chflags" >&6; } if test "$ac_cv_have_chflags" = cross ; then ac_fn_c_check_func "$LINENO" "chflags" "ac_cv_func_chflags" -if test "x$ac_cv_func_chflags" = x""yes; then : +if test "x$ac_cv_func_chflags" = xyes; then : ac_cv_have_chflags="yes" else ac_cv_have_chflags="no" @@ -9849,7 +9878,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lchflags" >&5 $as_echo_n "checking for lchflags... " >&6; } -if test "${ac_cv_have_lchflags+set}" = set; then : +if ${ac_cv_have_lchflags+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -9883,7 +9912,7 @@ $as_echo "$ac_cv_have_lchflags" >&6; } if test "$ac_cv_have_lchflags" = cross ; then ac_fn_c_check_func "$LINENO" "lchflags" "ac_cv_func_lchflags" -if test "x$ac_cv_func_lchflags" = x""yes; then : +if test "x$ac_cv_func_lchflags" = xyes; then : ac_cv_have_lchflags="yes" else ac_cv_have_lchflags="no" @@ -9907,7 +9936,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 $as_echo_n "checking for inflateCopy in -lz... " >&6; } -if test "${ac_cv_lib_z_inflateCopy+set}" = set; then : +if ${ac_cv_lib_z_inflateCopy+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9941,7 +9970,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 $as_echo "$ac_cv_lib_z_inflateCopy" >&6; } -if test "x$ac_cv_lib_z_inflateCopy" = x""yes; then : +if test "x$ac_cv_lib_z_inflateCopy" = xyes; then : $as_echo "#define HAVE_ZLIB_COPY 1" >>confdefs.h @@ -10084,7 +10113,7 @@ for ac_func in openpty do : ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty" -if test "x$ac_cv_func_openpty" = x""yes; then : +if test "x$ac_cv_func_openpty" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENPTY 1 _ACEOF @@ -10092,7 +10121,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 $as_echo_n "checking for openpty in -lutil... " >&6; } -if test "${ac_cv_lib_util_openpty+set}" = set; then : +if ${ac_cv_lib_util_openpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10126,13 +10155,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 $as_echo "$ac_cv_lib_util_openpty" >&6; } -if test "x$ac_cv_lib_util_openpty" = x""yes; then : +if test "x$ac_cv_lib_util_openpty" = xyes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 $as_echo_n "checking for openpty in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_openpty+set}" = set; then : +if ${ac_cv_lib_bsd_openpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10166,7 +10195,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_openpty" >&5 $as_echo "$ac_cv_lib_bsd_openpty" >&6; } -if test "x$ac_cv_lib_bsd_openpty" = x""yes; then : +if test "x$ac_cv_lib_bsd_openpty" = xyes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10181,7 +10210,7 @@ for ac_func in forkpty do : ac_fn_c_check_func "$LINENO" "forkpty" "ac_cv_func_forkpty" -if test "x$ac_cv_func_forkpty" = x""yes; then : +if test "x$ac_cv_func_forkpty" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FORKPTY 1 _ACEOF @@ -10189,7 +10218,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 $as_echo_n "checking for forkpty in -lutil... " >&6; } -if test "${ac_cv_lib_util_forkpty+set}" = set; then : +if ${ac_cv_lib_util_forkpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10223,13 +10252,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_forkpty" >&5 $as_echo "$ac_cv_lib_util_forkpty" >&6; } -if test "x$ac_cv_lib_util_forkpty" = x""yes; then : +if test "x$ac_cv_lib_util_forkpty" = xyes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 $as_echo_n "checking for forkpty in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_forkpty+set}" = set; then : +if ${ac_cv_lib_bsd_forkpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10263,7 +10292,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_forkpty" >&5 $as_echo "$ac_cv_lib_bsd_forkpty" >&6; } -if test "x$ac_cv_lib_bsd_forkpty" = x""yes; then : +if test "x$ac_cv_lib_bsd_forkpty" = xyes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10280,7 +10309,7 @@ for ac_func in memmove do : ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" -if test "x$ac_cv_func_memmove" = x""yes; then : +if test "x$ac_cv_func_memmove" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MEMMOVE 1 _ACEOF @@ -10294,8 +10323,7 @@ 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -10304,31 +10332,50 @@ done -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 +ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" +if test "x$ac_cv_func_dup2" = xyes; then : + $as_echo "#define HAVE_DUP2 1" >>confdefs.h else case " $LIBOBJS " in - *" $ac_func.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" + *" dup2.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS dup2.$ac_objext" ;; esac fi -done + +ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" +if test "x$ac_cv_func_getcwd" = xyes; 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" = xyes; then : + $as_echo "#define HAVE_STRDUP 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" strdup.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strdup.$ac_objext" + ;; +esac + +fi for ac_func in getpgrp do : ac_fn_c_check_func "$LINENO" "getpgrp" "ac_cv_func_getpgrp" -if test "x$ac_cv_func_getpgrp" = x""yes; then : +if test "x$ac_cv_func_getpgrp" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETPGRP 1 _ACEOF @@ -10356,7 +10403,7 @@ for ac_func in setpgrp do : ac_fn_c_check_func "$LINENO" "setpgrp" "ac_cv_func_setpgrp" -if test "x$ac_cv_func_setpgrp" = x""yes; then : +if test "x$ac_cv_func_setpgrp" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETPGRP 1 _ACEOF @@ -10384,7 +10431,7 @@ for ac_func in gettimeofday do : ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" -if test "x$ac_cv_func_gettimeofday" = x""yes; then : +if test "x$ac_cv_func_gettimeofday" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETTIMEOFDAY 1 _ACEOF @@ -10486,7 +10533,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking getaddrinfo bug" >&5 $as_echo_n "checking getaddrinfo bug... " >&6; } - if test "${ac_cv_buggy_getaddrinfo+set}" = set; then : + if ${ac_cv_buggy_getaddrinfo+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10615,7 +10662,7 @@ for ac_func in getnameinfo do : ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo" -if test "x$ac_cv_func_getnameinfo" = x""yes; then : +if test "x$ac_cv_func_getnameinfo" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETNAMEINFO 1 _ACEOF @@ -10627,7 +10674,7 @@ # checks for structures { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if test "${ac_cv_header_time+set}" = set; then : +if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10662,7 +10709,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if test "${ac_cv_struct_tm+set}" = set; then : +if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10699,7 +10746,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -10715,7 +10762,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = x""yes; then : +if test "x$ac_cv_have_decl_tzname" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -10727,7 +10774,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if test "${ac_cv_var_tzname+set}" = set; then : +if ${ac_cv_var_tzname+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10763,7 +10810,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_RDEV 1 @@ -10773,7 +10820,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blksize" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 @@ -10783,7 +10830,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_flags" "ac_cv_member_struct_stat_st_flags" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_flags" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_flags" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_FLAGS 1 @@ -10793,7 +10840,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_gen" "ac_cv_member_struct_stat_st_gen" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_gen" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_gen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_GEN 1 @@ -10803,7 +10850,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtime" "ac_cv_member_struct_stat_st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtime" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_birthtime" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 @@ -10813,7 +10860,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blocks" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLOCKS 1 @@ -10835,7 +10882,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 $as_echo_n "checking for time.h that defines altzone... " >&6; } -if test "${ac_cv_header_time_altzone+set}" = set; then : +if ${ac_cv_header_time_altzone+:} false; then : $as_echo_n "(cached) " >&6 else @@ -10899,7 +10946,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for addrinfo" >&5 $as_echo_n "checking for addrinfo... " >&6; } -if test "${ac_cv_struct_addrinfo+set}" = set; then : +if ${ac_cv_struct_addrinfo+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10931,7 +10978,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sockaddr_storage" >&5 $as_echo_n "checking for sockaddr_storage... " >&6; } -if test "${ac_cv_struct_sockaddr_storage+set}" = set; then : +if ${ac_cv_struct_sockaddr_storage+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10967,7 +11014,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether char is unsigned" >&5 $as_echo_n "checking whether char is unsigned... " >&6; } -if test "${ac_cv_c_char_unsigned+set}" = set; then : +if ${ac_cv_c_char_unsigned+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10999,7 +11046,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if test "${ac_cv_c_const+set}" = set; then : +if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11287,7 +11334,7 @@ ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" -if test "x$ac_cv_func_gethostbyname_r" = x""yes; then : +if test "x$ac_cv_func_gethostbyname_r" = xyes; then : $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h @@ -11418,7 +11465,7 @@ for ac_func in gethostbyname do : ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = x""yes; then : +if test "x$ac_cv_func_gethostbyname" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTBYNAME 1 _ACEOF @@ -11440,12 +11487,12 @@ # Linux requires this for correct f.p. operations ac_fn_c_check_func "$LINENO" "__fpu_control" "ac_cv_func___fpu_control" -if test "x$ac_cv_func___fpu_control" = x""yes; then : +if test "x$ac_cv_func___fpu_control" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 $as_echo_n "checking for __fpu_control in -lieee... " >&6; } -if test "${ac_cv_lib_ieee___fpu_control+set}" = set; then : +if ${ac_cv_lib_ieee___fpu_control+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -11479,7 +11526,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee___fpu_control" >&5 $as_echo "$ac_cv_lib_ieee___fpu_control" >&6; } -if test "x$ac_cv_lib_ieee___fpu_control" = x""yes; then : +if test "x$ac_cv_lib_ieee___fpu_control" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBIEEE 1 _ACEOF @@ -11535,7 +11582,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 @@ -11559,7 +11606,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 @@ -11573,7 +11620,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are little-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are little-endian IEEE 754 binary64... " >&6; } -if test "${ac_cv_little_endian_double+set}" = set; then : +if ${ac_cv_little_endian_double+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11615,7 +11662,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are big-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are big-endian IEEE 754 binary64... " >&6; } -if test "${ac_cv_big_endian_double+set}" = set; then : +if ${ac_cv_big_endian_double+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11661,7 +11708,7 @@ # conversions work. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are ARM mixed-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are ARM mixed-endian IEEE 754 binary64... " >&6; } -if test "${ac_cv_mixed_endian_double+set}" = set; then : +if ${ac_cv_mixed_endian_double+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11809,8 +11856,7 @@ 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -11822,8 +11868,7 @@ 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -11833,7 +11878,7 @@ ac_fn_c_check_decl "$LINENO" "isinf" "ac_cv_have_decl_isinf" "#include " -if test "x$ac_cv_have_decl_isinf" = x""yes; then : +if test "x$ac_cv_have_decl_isinf" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11844,7 +11889,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isnan" "ac_cv_have_decl_isnan" "#include " -if test "x$ac_cv_have_decl_isnan" = x""yes; then : +if test "x$ac_cv_have_decl_isnan" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11855,7 +11900,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isfinite" "ac_cv_have_decl_isfinite" "#include " -if test "x$ac_cv_have_decl_isfinite" = x""yes; then : +if test "x$ac_cv_have_decl_isfinite" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11870,7 +11915,7 @@ # -0. on some architectures. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tanh preserves the sign of zero" >&5 $as_echo_n "checking whether tanh preserves the sign of zero... " >&6; } -if test "${ac_cv_tanh_preserves_zero_sign+set}" = set; then : +if ${ac_cv_tanh_preserves_zero_sign+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11918,7 +11963,7 @@ # -0. See issue #9920. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether log1p drops the sign of negative zero" >&5 $as_echo_n "checking whether log1p drops the sign of negative zero... " >&6; } - if test "${ac_cv_log1p_drops_zero_sign+set}" = set; then : + if ${ac_cv_log1p_drops_zero_sign+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11970,7 +12015,7 @@ # sem_open results in a 'Signal 12' error. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX semaphores are enabled" >&5 $as_echo_n "checking whether POSIX semaphores are enabled... " >&6; } -if test "${ac_cv_posix_semaphores_enabled+set}" = set; then : +if ${ac_cv_posix_semaphores_enabled+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12021,7 +12066,7 @@ # Multiprocessing check for broken sem_getvalue { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken sem_getvalue" >&5 $as_echo_n "checking for broken sem_getvalue... " >&6; } -if test "${ac_cv_broken_sem_getvalue+set}" = set; then : +if ${ac_cv_broken_sem_getvalue+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12086,7 +12131,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; } @@ -12104,7 +12149,7 @@ # check for wchar.h ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" -if test "x$ac_cv_header_wchar_h" = x""yes; then : +if test "x$ac_cv_header_wchar_h" = xyes; then : $as_echo "#define HAVE_WCHAR_H 1" >>confdefs.h @@ -12127,7 +12172,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 $as_echo_n "checking size of wchar_t... " >&6; } -if test "${ac_cv_sizeof_wchar_t+set}" = set; then : +if ${ac_cv_sizeof_wchar_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include @@ -12137,9 +12182,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (wchar_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (wchar_t) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_wchar_t=0 fi @@ -12194,7 +12238,7 @@ # check whether wchar_t is signed or not { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wchar_t is signed" >&5 $as_echo_n "checking whether wchar_t is signed... " >&6; } - if test "${ac_cv_wchar_t_signed+set}" = set; then : + if ${ac_cv_wchar_t_signed+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12290,7 +12334,7 @@ # check for endianness { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if test "${ac_cv_c_bigendian+set}" = set; then : +if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown @@ -12508,7 +12552,7 @@ ;; #( *) - as_fn_error "unknown endianness + as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac @@ -12581,7 +12625,7 @@ # or fills with zeros (like the Cray J90, according to Tim Peters). { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether right shift extends the sign bit" >&5 $as_echo_n "checking whether right shift extends the sign bit... " >&6; } -if test "${ac_cv_rshift_extends_sign+set}" = set; then : +if ${ac_cv_rshift_extends_sign+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12620,7 +12664,7 @@ # check for getc_unlocked and related locking functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getc_unlocked() and friends" >&5 $as_echo_n "checking for getc_unlocked() and friends... " >&6; } -if test "${ac_cv_have_getc_unlocked+set}" = set; then : +if ${ac_cv_have_getc_unlocked+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12718,7 +12762,7 @@ # check for readline 2.1 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_callback_handler_install in -lreadline" >&5 $as_echo_n "checking for rl_callback_handler_install in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_callback_handler_install+set}" = set; then : +if ${ac_cv_lib_readline_rl_callback_handler_install+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12752,7 +12796,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_callback_handler_install" >&5 $as_echo "$ac_cv_lib_readline_rl_callback_handler_install" >&6; } -if test "x$ac_cv_lib_readline_rl_callback_handler_install" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_callback_handler_install" = xyes; then : $as_echo "#define HAVE_RL_CALLBACK 1" >>confdefs.h @@ -12770,7 +12814,7 @@ have_readline=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext if test $have_readline = yes then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12804,7 +12848,7 @@ # check for readline 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_pre_input_hook in -lreadline" >&5 $as_echo_n "checking for rl_pre_input_hook in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_pre_input_hook+set}" = set; then : +if ${ac_cv_lib_readline_rl_pre_input_hook+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12838,7 +12882,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_pre_input_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_pre_input_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_pre_input_hook" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_pre_input_hook" = xyes; then : $as_echo "#define HAVE_RL_PRE_INPUT_HOOK 1" >>confdefs.h @@ -12848,7 +12892,7 @@ # also in 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_display_matches_hook in -lreadline" >&5 $as_echo_n "checking for rl_completion_display_matches_hook in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_completion_display_matches_hook+set}" = set; then : +if ${ac_cv_lib_readline_rl_completion_display_matches_hook+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12882,7 +12926,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_display_matches_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_display_matches_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = xyes; then : $as_echo "#define HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK 1" >>confdefs.h @@ -12892,7 +12936,7 @@ # check for readline 4.2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_matches in -lreadline" >&5 $as_echo_n "checking for rl_completion_matches in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_completion_matches+set}" = set; then : +if ${ac_cv_lib_readline_rl_completion_matches+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12926,7 +12970,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_matches" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_matches" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_matches" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_completion_matches" = xyes; then : $as_echo "#define HAVE_RL_COMPLETION_MATCHES 1" >>confdefs.h @@ -12944,7 +12988,7 @@ have_readline=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext if test $have_readline = yes then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12967,7 +13011,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken nice()" >&5 $as_echo_n "checking for broken nice()... " >&6; } -if test "${ac_cv_broken_nice+set}" = set; then : +if ${ac_cv_broken_nice+:} false; then : $as_echo_n "(cached) " >&6 else @@ -13008,7 +13052,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken poll()" >&5 $as_echo_n "checking for broken poll()... " >&6; } -if test "${ac_cv_broken_poll+set}" = set; then : +if ${ac_cv_broken_poll+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13063,7 +13107,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -13079,7 +13123,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = x""yes; then : +if test "x$ac_cv_have_decl_tzname" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -13091,7 +13135,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if test "${ac_cv_var_tzname+set}" = set; then : +if ${ac_cv_var_tzname+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13130,7 +13174,7 @@ # check tzset(3) exists and works like we expect it to { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working tzset()" >&5 $as_echo_n "checking for working tzset()... " >&6; } -if test "${ac_cv_working_tzset+set}" = set; then : +if ${ac_cv_working_tzset+:} false; then : $as_echo_n "(cached) " >&6 else @@ -13227,7 +13271,7 @@ # Look for subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec in struct stat" >&5 $as_echo_n "checking for tv_nsec in struct stat... " >&6; } -if test "${ac_cv_stat_tv_nsec+set}" = set; then : +if ${ac_cv_stat_tv_nsec+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13264,7 +13308,7 @@ # Look for BSD style subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec2 in struct stat" >&5 $as_echo_n "checking for tv_nsec2 in struct stat... " >&6; } -if test "${ac_cv_stat_tv_nsec2+set}" = set; then : +if ${ac_cv_stat_tv_nsec2+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13301,7 +13345,7 @@ # On HP/UX 11.0, mvwdelch is a block with a return statement { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mvwdelch is an expression" >&5 $as_echo_n "checking whether mvwdelch is an expression... " >&6; } -if test "${ac_cv_mvwdelch_is_expression+set}" = set; then : +if ${ac_cv_mvwdelch_is_expression+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13338,7 +13382,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether WINDOW has _flags" >&5 $as_echo_n "checking whether WINDOW has _flags... " >&6; } -if test "${ac_cv_window_has_flags+set}" = set; then : +if ${ac_cv_window_has_flags+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13486,7 +13530,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %lld and %llu printf() format support" >&5 $as_echo_n "checking for %lld and %llu printf() format support... " >&6; } - if test "${ac_cv_have_long_long_format+set}" = set; then : + if ${ac_cv_have_long_long_format+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13556,7 +13600,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %zd printf() format support" >&5 $as_echo_n "checking for %zd printf() format support... " >&6; } -if test "${ac_cv_have_size_t_format+set}" = set; then : +if ${ac_cv_have_size_t_format+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13629,7 +13673,7 @@ #endif " -if test "x$ac_cv_type_socklen_t" = x""yes; then : +if test "x$ac_cv_type_socklen_t" = xyes; then : else @@ -13640,7 +13684,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken mbstowcs" >&5 $as_echo_n "checking for broken mbstowcs... " >&6; } -if test "${ac_cv_broken_mbstowcs+set}" = set; then : +if ${ac_cv_broken_mbstowcs+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13680,7 +13724,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports computed gotos" >&5 $as_echo_n "checking whether $CC supports computed gotos... " >&6; } -if test "${ac_cv_computed_gotos+set}" = set; then : +if ${ac_cv_computed_gotos+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13760,7 +13804,7 @@ ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" -if test "x$ac_cv_func_pipe2" = x""yes; then : +if test "x$ac_cv_func_pipe2" = xyes; then : $as_echo "#define HAVE_PIPE2 1" >>confdefs.h @@ -13855,10 +13899,21 @@ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && + if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} @@ -13874,6 +13929,7 @@ 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$//' @@ -13890,7 +13946,7 @@ -: ${CONFIG_STATUS=./config.status} +: "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" @@ -13991,6 +14047,7 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -14036,19 +14093,19 @@ (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS 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=$?; 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 + 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 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -14244,7 +14301,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 @@ -14298,7 +14355,7 @@ # values after options handling. ac_log=" This file was extended by python $as_me 3.3, which was -generated by GNU Autoconf 2.65. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -14322,8 +14379,8 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. -config_files="`echo $ac_config_files`" -config_headers="`echo $ac_config_headers`" +config_files="$ac_config_files" +config_headers="$ac_config_headers" _ACEOF @@ -14360,10 +14417,10 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ python config.status 3.3 -configured by $0, generated by GNU Autoconf 2.65, +configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" -Copyright (C) 2009 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -14379,11 +14436,16 @@ 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 @@ -14405,6 +14467,7 @@ $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;; @@ -14417,7 +14480,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 ;; @@ -14426,7 +14489,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" @@ -14485,7 +14548,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 @@ -14507,9 +14570,10 @@ # after its creation but before its name has been assigned to `$tmp'. $debug || { - tmp= + tmp= ac_tmp= trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } @@ -14517,12 +14581,13 @@ { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" + test -d "$tmp" } || { 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 +ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -14539,12 +14604,12 @@ 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 -echo 'BEGIN {' >"$tmp/subs1.awk" && +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF @@ -14553,18 +14618,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 @@ -14572,7 +14637,7 @@ rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h @@ -14620,7 +14685,7 @@ rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$tmp/subs1.awk" <<_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" @@ -14652,21 +14717,29 @@ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ - || as_fn_error "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || 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 # 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[ ]*=/{ -s/:*\$(srcdir):*/:/ -s/:*\${srcdir}:*/:/ -s/:*@srcdir@:*/:/ -s/^\([^=]*=[ ]*\):*/\1/ + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// s/^[^=]*=[ ]*$// }' fi @@ -14678,7 +14751,7 @@ # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then -cat >"$tmp/defines.awk" <<\_ACAWK || +cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF @@ -14690,11 +14763,11 @@ # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do - ac_t=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_t"; then + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; 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 @@ -14779,7 +14852,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" @@ -14792,7 +14865,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 @@ -14811,7 +14884,7 @@ for ac_f do case $ac_f in - -) ac_f="$tmp/stdin";; + -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. @@ -14820,7 +14893,7 @@ [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "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'" @@ -14846,8 +14919,8 @@ esac case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -14977,23 +15050,24 @@ s&@INSTALL@&$ac_INSTALL&;t t $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 +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || 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"; } && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_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;} - - rm -f "$tmp/stdin" +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" case $ac_file in - -) cat "$tmp/out" && rm -f "$tmp/out";; - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_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) # @@ -15002,21 +15076,21 @@ if test x"$ac_file" != x-; then { $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 - if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_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 + mv "$ac_tmp/config.h" "$ac_file" \ + || 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 + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; @@ -15036,7 +15110,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. @@ -15057,7 +15131,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 $? + $ac_cs_success || as_fn_exit 1 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 diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -518,6 +518,18 @@ fi +AC_MSG_CHECKING([for -Wl,--no-as-needed]) +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS -Wl,--no-as-needed" +AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [NO_AS_NEEDED="-Wl,--no-as-needed" + AC_MSG_RESULT([yes])], + [NO_AS_NEEDED="" + AC_MSG_RESULT([no])]) +LDFLAGS="$save_LDFLAGS" +AC_SUBST(NO_AS_NEEDED) + + # checks for UNIX variants that set C preprocessor variables AC_USE_SYSTEM_EXTENSIONS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 07:43:43 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 May 2011 07:43:43 +0200 Subject: [Python-checkins] cpython (3.2): The option is actually --no-as-needed. Message-ID: http://hg.python.org/cpython/rev/916c6239c7a7 changeset: 69965:916c6239c7a7 branch: 3.2 parent: 69963:749686064642 user: Martin v. L?wis date: Mon May 09 07:42:28 2011 +0200 summary: The option is actually --no-as-needed. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -313,7 +313,7 @@ Build ----- -- Issue #11347: Use --as-needed when linking libpython3.so. +- Issue #11347: Use --no-as-needed when linking libpython3.so. - Issue #11411: Fix 'make DESTDIR=' with a relative destination. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 07:43:44 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 May 2011 07:43:44 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merged Message-ID: http://hg.python.org/cpython/rev/9f95dcface80 changeset: 69966:9f95dcface80 parent: 69964:4bc0d1b45898 parent: 69965:916c6239c7a7 user: Martin v. L?wis date: Mon May 09 07:42:48 2011 +0200 summary: merged files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -578,7 +578,7 @@ Build ----- -- Issue #11347: Use --as-needed when linking libpython3.so. +- Issue #11347: Use --no-as-needed when linking libpython3.so. - Issue #11411: Fix 'make DESTDIR=' with a relative destination. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 08:16:53 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 May 2011 08:16:53 +0200 Subject: [Python-checkins] cpython (3.1): Stop trying to use _xmlplus in the xml module. Closes #11164. Message-ID: http://hg.python.org/cpython/rev/61798f076676 changeset: 69967:61798f076676 branch: 3.1 parent: 69959:677ee366c9f5 user: Martin v. L?wis date: Mon May 09 08:05:43 2011 +0200 summary: Stop trying to use _xmlplus in the xml module. Closes #11164. Patch by Arfrever Frehtes Taifersar Arahesis. files: Doc/distutils/introduction.rst | 2 +- Doc/library/modulefinder.rst | 3 +- Doc/library/xml.dom.minidom.rst | 8 +-- Doc/library/xml.dom.rst | 7 --- Lib/modulefinder.py | 7 +- Lib/test/test_minidom.py | 20 --------- Lib/test/test_sax.py | 45 --------------------- Lib/xml/__init__.py | 21 --------- Misc/NEWS | 2 + 9 files changed, 10 insertions(+), 105 deletions(-) diff --git a/Doc/distutils/introduction.rst b/Doc/distutils/introduction.rst --- a/Doc/distutils/introduction.rst +++ b/Doc/distutils/introduction.rst @@ -187,7 +187,7 @@ module distribution a collection of Python modules distributed together as a single downloadable resource and meant to be installed *en masse*. Examples of some well-known - module distributions are Numeric Python, PyXML, PIL (the Python Imaging + module distributions are NumPy, SciPy, PIL (the Python Imaging Library), or mxBase. (This would be called a *package*, except that term is already taken in the Python context: a single module distribution may contain zero, one, or many Python packages.) diff --git a/Doc/library/modulefinder.rst b/Doc/library/modulefinder.rst --- a/Doc/library/modulefinder.rst +++ b/Doc/library/modulefinder.rst @@ -22,8 +22,7 @@ .. function:: ReplacePackage(oldname, newname) Allows specifying that the module named *oldname* is in fact the package named - *newname*. The most common usage would be to handle how the :mod:`_xmlplus` - package replaces the :mod:`xml` package. + *newname*. .. class:: ModuleFinder(path=None, debug=0, excludes=[], replace_paths=[]) diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -57,12 +57,8 @@ You can also create a :class:`Document` by calling a method on a "DOM Implementation" object. You can get this object either by calling the :func:`getDOMImplementation` function in the :mod:`xml.dom` package or the -:mod:`xml.dom.minidom` module. Using the implementation from the -:mod:`xml.dom.minidom` module will always return a :class:`Document` instance -from the minidom implementation, while the version from :mod:`xml.dom` may -provide an alternate implementation (this is likely if you have the `PyXML -package `_ installed). Once you have a -:class:`Document`, you can add child nodes to it to populate the DOM:: +:mod:`xml.dom.minidom` module. Once you have a :class:`Document`, you +can add child nodes to it to populate the DOM:: from xml.dom.minidom import getDOMImplementation diff --git a/Doc/library/xml.dom.rst b/Doc/library/xml.dom.rst --- a/Doc/library/xml.dom.rst +++ b/Doc/library/xml.dom.rst @@ -30,13 +30,6 @@ their terminology. The Python mapping of the API is substantially based on the DOM Level 2 recommendation. -.. XXX PyXML is dead... -.. The mapping of the Level 3 specification, currently - only available in draft form, is being developed by the `Python XML Special - Interest Group `_ as part of the `PyXML - package `_. Refer to the documentation bundled - with that package for information on the current state of DOM Level 3 support. - .. What if your needs are somewhere between SAX and the DOM? Perhaps you cannot afford to load the entire tree in memory but you find the SAX model somewhat cumbersome and low-level. There is also a module diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py --- a/Lib/modulefinder.py +++ b/Lib/modulefinder.py @@ -35,9 +35,10 @@ replacePackageMap = {} -# This ReplacePackage mechanism allows modulefinder to work around the -# way the _xmlplus package injects itself under the name "xml" into -# sys.modules at runtime by calling ReplacePackage("_xmlplus", "xml") +# This ReplacePackage mechanism allows modulefinder to work around +# situations in which a package injects itself under the name +# of another package into sys.modules at runtime by calling +# ReplacePackage("real_package_name", "faked_package_name") # before running ModuleFinder. def ReplacePackage(oldname, newname): diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -51,26 +51,6 @@ return doc class MinidomTest(unittest.TestCase): - def tearDown(self): - try: - Node.allnodes - except AttributeError: - # We don't actually have the minidom from the standard library, - # but are picking up the PyXML version from site-packages. - pass - else: - self.confirm(len(Node.allnodes) == 0, - "assertion: len(Node.allnodes) == 0") - if len(Node.allnodes): - print("Garbage left over:") - if verbose: - print(list(Node.allnodes.items())[0:10]) - else: - # Don't print specific nodes if repeatable results - # are needed - print(len(Node.allnodes)) - Node.allnodes = {} - def confirm(self, test, testname = "Test"): self.assertTrue(test, testname) diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -694,51 +694,6 @@ self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr") - # During the development of Python 2.5, an attempt to move the "xml" - # package implementation to a new package ("xmlcore") proved painful. - # The goal of this change was to allow applications to be able to - # obtain and rely on behavior in the standard library implementation - # of the XML support without needing to be concerned about the - # availability of the PyXML implementation. - # - # While the existing import hackery in Lib/xml/__init__.py can cause - # PyXML's _xmlpus package to supplant the "xml" package, that only - # works because either implementation uses the "xml" package name for - # imports. - # - # The move resulted in a number of problems related to the fact that - # the import machinery's "package context" is based on the name that's - # being imported rather than the __name__ of the actual package - # containment; it wasn't possible for the "xml" package to be replaced - # by a simple module that indirected imports to the "xmlcore" package. - # - # The following two tests exercised bugs that were introduced in that - # attempt. Keeping these tests around will help detect problems with - # other attempts to provide reliable access to the standard library's - # implementation of the XML support. - - def test_sf_1511497(self): - # Bug report: http://www.python.org/sf/1511497 - import sys - old_modules = sys.modules.copy() - for modname in list(sys.modules.keys()): - if modname.startswith("xml."): - del sys.modules[modname] - try: - import xml.sax.expatreader - module = xml.sax.expatreader - self.assertEqual(module.__name__, "xml.sax.expatreader") - finally: - sys.modules.update(old_modules) - - def test_sf_1513611(self): - # Bug report: http://www.python.org/sf/1513611 - sio = StringIO("invalid") - parser = make_parser() - from xml.sax import SAXParseException - self.assertRaises(SAXParseException, parser.parse, sio) - - def test_main(): run_unittest(MakeParserTest, SaxutilsTest, diff --git a/Lib/xml/__init__.py b/Lib/xml/__init__.py --- a/Lib/xml/__init__.py +++ b/Lib/xml/__init__.py @@ -18,24 +18,3 @@ __all__ = ["dom", "parsers", "sax", "etree"] - -_MINIMUM_XMLPLUS_VERSION = (0, 8, 4) - - -try: - import _xmlplus -except ImportError: - pass -else: - try: - v = _xmlplus.version_info - except AttributeError: - # _xmlplus is too old; ignore it - pass - else: - if v >= _MINIMUM_XMLPLUS_VERSION: - import sys - _xmlplus.__path__.extend(__path__) - sys.modules[__name__] = _xmlplus - else: - del v diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,8 @@ Library ------- +- Issue #11164: Stop trying to use _xmlplus in the xml module. + - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Kasun Herath. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 08:16:54 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 May 2011 08:16:54 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): merge 11164 Message-ID: http://hg.python.org/cpython/rev/6e31b560f0f1 changeset: 69968:6e31b560f0f1 branch: 3.2 parent: 69965:916c6239c7a7 parent: 69967:61798f076676 user: Martin v. L?wis date: Mon May 09 08:10:38 2011 +0200 summary: merge 11164 files: Doc/distutils/introduction.rst | 2 +- Doc/library/modulefinder.rst | 3 +- Doc/library/xml.dom.minidom.rst | 8 +-- Doc/library/xml.dom.rst | 7 --- Lib/modulefinder.py | 7 +- Lib/test/test_minidom.py | 20 --------- Lib/test/test_sax.py | 45 --------------------- Lib/xml/__init__.py | 21 --------- Misc/NEWS | 2 + 9 files changed, 10 insertions(+), 105 deletions(-) diff --git a/Doc/distutils/introduction.rst b/Doc/distutils/introduction.rst --- a/Doc/distutils/introduction.rst +++ b/Doc/distutils/introduction.rst @@ -187,7 +187,7 @@ module distribution a collection of Python modules distributed together as a single downloadable resource and meant to be installed *en masse*. Examples of some well-known - module distributions are Numeric Python, PyXML, PIL (the Python Imaging + module distributions are NumPy, SciPy, PIL (the Python Imaging Library), or mxBase. (This would be called a *package*, except that term is already taken in the Python context: a single module distribution may contain zero, one, or many Python packages.) diff --git a/Doc/library/modulefinder.rst b/Doc/library/modulefinder.rst --- a/Doc/library/modulefinder.rst +++ b/Doc/library/modulefinder.rst @@ -25,8 +25,7 @@ .. function:: ReplacePackage(oldname, newname) Allows specifying that the module named *oldname* is in fact the package named - *newname*. The most common usage would be to handle how the :mod:`_xmlplus` - package replaces the :mod:`xml` package. + *newname*. .. class:: ModuleFinder(path=None, debug=0, excludes=[], replace_paths=[]) diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -60,12 +60,8 @@ You can also create a :class:`Document` by calling a method on a "DOM Implementation" object. You can get this object either by calling the :func:`getDOMImplementation` function in the :mod:`xml.dom` package or the -:mod:`xml.dom.minidom` module. Using the implementation from the -:mod:`xml.dom.minidom` module will always return a :class:`Document` instance -from the minidom implementation, while the version from :mod:`xml.dom` may -provide an alternate implementation (this is likely if you have the `PyXML -package `_ installed). Once you have a -:class:`Document`, you can add child nodes to it to populate the DOM:: +:mod:`xml.dom.minidom` module. Once you have a :class:`Document`, you +can add child nodes to it to populate the DOM:: from xml.dom.minidom import getDOMImplementation diff --git a/Doc/library/xml.dom.rst b/Doc/library/xml.dom.rst --- a/Doc/library/xml.dom.rst +++ b/Doc/library/xml.dom.rst @@ -30,13 +30,6 @@ their terminology. The Python mapping of the API is substantially based on the DOM Level 2 recommendation. -.. XXX PyXML is dead... -.. The mapping of the Level 3 specification, currently - only available in draft form, is being developed by the `Python XML Special - Interest Group `_ as part of the `PyXML - package `_. Refer to the documentation bundled - with that package for information on the current state of DOM Level 3 support. - .. What if your needs are somewhere between SAX and the DOM? Perhaps you cannot afford to load the entire tree in memory but you find the SAX model somewhat cumbersome and low-level. There is also a module diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py --- a/Lib/modulefinder.py +++ b/Lib/modulefinder.py @@ -35,9 +35,10 @@ replacePackageMap = {} -# This ReplacePackage mechanism allows modulefinder to work around the -# way the _xmlplus package injects itself under the name "xml" into -# sys.modules at runtime by calling ReplacePackage("_xmlplus", "xml") +# This ReplacePackage mechanism allows modulefinder to work around +# situations in which a package injects itself under the name +# of another package into sys.modules at runtime by calling +# ReplacePackage("real_package_name", "faked_package_name") # before running ModuleFinder. def ReplacePackage(oldname, newname): diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -45,26 +45,6 @@ return doc class MinidomTest(unittest.TestCase): - def tearDown(self): - try: - Node.allnodes - except AttributeError: - # We don't actually have the minidom from the standard library, - # but are picking up the PyXML version from site-packages. - pass - else: - self.confirm(len(Node.allnodes) == 0, - "assertion: len(Node.allnodes) == 0") - if len(Node.allnodes): - print("Garbage left over:") - if verbose: - print(list(Node.allnodes.items())[0:10]) - else: - # Don't print specific nodes if repeatable results - # are needed - print(len(Node.allnodes)) - Node.allnodes = {} - def confirm(self, test, testname = "Test"): self.assertTrue(test, testname) diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -794,51 +794,6 @@ self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr") - # During the development of Python 2.5, an attempt to move the "xml" - # package implementation to a new package ("xmlcore") proved painful. - # The goal of this change was to allow applications to be able to - # obtain and rely on behavior in the standard library implementation - # of the XML support without needing to be concerned about the - # availability of the PyXML implementation. - # - # While the existing import hackery in Lib/xml/__init__.py can cause - # PyXML's _xmlpus package to supplant the "xml" package, that only - # works because either implementation uses the "xml" package name for - # imports. - # - # The move resulted in a number of problems related to the fact that - # the import machinery's "package context" is based on the name that's - # being imported rather than the __name__ of the actual package - # containment; it wasn't possible for the "xml" package to be replaced - # by a simple module that indirected imports to the "xmlcore" package. - # - # The following two tests exercised bugs that were introduced in that - # attempt. Keeping these tests around will help detect problems with - # other attempts to provide reliable access to the standard library's - # implementation of the XML support. - - def test_sf_1511497(self): - # Bug report: http://www.python.org/sf/1511497 - import sys - old_modules = sys.modules.copy() - for modname in list(sys.modules.keys()): - if modname.startswith("xml."): - del sys.modules[modname] - try: - import xml.sax.expatreader - module = xml.sax.expatreader - self.assertEqual(module.__name__, "xml.sax.expatreader") - finally: - sys.modules.update(old_modules) - - def test_sf_1513611(self): - # Bug report: http://www.python.org/sf/1513611 - sio = StringIO("invalid") - parser = make_parser() - from xml.sax import SAXParseException - self.assertRaises(SAXParseException, parser.parse, sio) - - def test_main(): run_unittest(MakeParserTest, SaxutilsTest, diff --git a/Lib/xml/__init__.py b/Lib/xml/__init__.py --- a/Lib/xml/__init__.py +++ b/Lib/xml/__init__.py @@ -18,24 +18,3 @@ __all__ = ["dom", "parsers", "sax", "etree"] - -_MINIMUM_XMLPLUS_VERSION = (0, 8, 4) - - -try: - import _xmlplus -except ImportError: - pass -else: - try: - v = _xmlplus.version_info - except AttributeError: - # _xmlplus is too old; ignore it - pass - else: - if v >= _MINIMUM_XMLPLUS_VERSION: - import sys - _xmlplus.__path__.extend(__path__) - sys.modules[__name__] = _xmlplus - else: - del v diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,8 @@ Library ------- +- Issue #11164: Stop trying to use _xmlplus in the xml module. + - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Kasun Herath. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 08:16:55 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 May 2011 08:16:55 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge 11164 Message-ID: http://hg.python.org/cpython/rev/e015e8560d64 changeset: 69969:e015e8560d64 parent: 69966:9f95dcface80 parent: 69968:6e31b560f0f1 user: Martin v. L?wis date: Mon May 09 08:12:19 2011 +0200 summary: merge 11164 files: Doc/distutils/introduction.rst | 2 +- Doc/library/modulefinder.rst | 3 +- Doc/library/xml.dom.minidom.rst | 8 +-- Doc/library/xml.dom.rst | 7 --- Lib/modulefinder.py | 7 +- Lib/test/test_minidom.py | 20 --------- Lib/test/test_sax.py | 45 --------------------- Lib/xml/__init__.py | 21 --------- Misc/NEWS | 2 + 9 files changed, 10 insertions(+), 105 deletions(-) diff --git a/Doc/distutils/introduction.rst b/Doc/distutils/introduction.rst --- a/Doc/distutils/introduction.rst +++ b/Doc/distutils/introduction.rst @@ -187,7 +187,7 @@ module distribution a collection of Python modules distributed together as a single downloadable resource and meant to be installed *en masse*. Examples of some well-known - module distributions are Numeric Python, PyXML, PIL (the Python Imaging + module distributions are NumPy, SciPy, PIL (the Python Imaging Library), or mxBase. (This would be called a *package*, except that term is already taken in the Python context: a single module distribution may contain zero, one, or many Python packages.) diff --git a/Doc/library/modulefinder.rst b/Doc/library/modulefinder.rst --- a/Doc/library/modulefinder.rst +++ b/Doc/library/modulefinder.rst @@ -25,8 +25,7 @@ .. function:: ReplacePackage(oldname, newname) Allows specifying that the module named *oldname* is in fact the package named - *newname*. The most common usage would be to handle how the :mod:`_xmlplus` - package replaces the :mod:`xml` package. + *newname*. .. class:: ModuleFinder(path=None, debug=0, excludes=[], replace_paths=[]) diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -60,12 +60,8 @@ You can also create a :class:`Document` by calling a method on a "DOM Implementation" object. You can get this object either by calling the :func:`getDOMImplementation` function in the :mod:`xml.dom` package or the -:mod:`xml.dom.minidom` module. Using the implementation from the -:mod:`xml.dom.minidom` module will always return a :class:`Document` instance -from the minidom implementation, while the version from :mod:`xml.dom` may -provide an alternate implementation (this is likely if you have the `PyXML -package `_ installed). Once you have a -:class:`Document`, you can add child nodes to it to populate the DOM:: +:mod:`xml.dom.minidom` module. Once you have a :class:`Document`, you +can add child nodes to it to populate the DOM:: from xml.dom.minidom import getDOMImplementation diff --git a/Doc/library/xml.dom.rst b/Doc/library/xml.dom.rst --- a/Doc/library/xml.dom.rst +++ b/Doc/library/xml.dom.rst @@ -30,13 +30,6 @@ their terminology. The Python mapping of the API is substantially based on the DOM Level 2 recommendation. -.. XXX PyXML is dead... -.. The mapping of the Level 3 specification, currently - only available in draft form, is being developed by the `Python XML Special - Interest Group `_ as part of the `PyXML - package `_. Refer to the documentation bundled - with that package for information on the current state of DOM Level 3 support. - .. What if your needs are somewhere between SAX and the DOM? Perhaps you cannot afford to load the entire tree in memory but you find the SAX model somewhat cumbersome and low-level. There is also a module diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py --- a/Lib/modulefinder.py +++ b/Lib/modulefinder.py @@ -35,9 +35,10 @@ replacePackageMap = {} -# This ReplacePackage mechanism allows modulefinder to work around the -# way the _xmlplus package injects itself under the name "xml" into -# sys.modules at runtime by calling ReplacePackage("_xmlplus", "xml") +# This ReplacePackage mechanism allows modulefinder to work around +# situations in which a package injects itself under the name +# of another package into sys.modules at runtime by calling +# ReplacePackage("real_package_name", "faked_package_name") # before running ModuleFinder. def ReplacePackage(oldname, newname): diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -42,26 +42,6 @@ return doc class MinidomTest(unittest.TestCase): - def tearDown(self): - try: - Node.allnodes - except AttributeError: - # We don't actually have the minidom from the standard library, - # but are picking up the PyXML version from site-packages. - pass - else: - self.confirm(len(Node.allnodes) == 0, - "assertion: len(Node.allnodes) == 0") - if len(Node.allnodes): - print("Garbage left over:") - if verbose: - print(list(Node.allnodes.items())[0:10]) - else: - # Don't print specific nodes if repeatable results - # are needed - print(len(Node.allnodes)) - Node.allnodes = {} - def confirm(self, test, testname = "Test"): self.assertTrue(test, testname) diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -794,51 +794,6 @@ self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr") - # During the development of Python 2.5, an attempt to move the "xml" - # package implementation to a new package ("xmlcore") proved painful. - # The goal of this change was to allow applications to be able to - # obtain and rely on behavior in the standard library implementation - # of the XML support without needing to be concerned about the - # availability of the PyXML implementation. - # - # While the existing import hackery in Lib/xml/__init__.py can cause - # PyXML's _xmlpus package to supplant the "xml" package, that only - # works because either implementation uses the "xml" package name for - # imports. - # - # The move resulted in a number of problems related to the fact that - # the import machinery's "package context" is based on the name that's - # being imported rather than the __name__ of the actual package - # containment; it wasn't possible for the "xml" package to be replaced - # by a simple module that indirected imports to the "xmlcore" package. - # - # The following two tests exercised bugs that were introduced in that - # attempt. Keeping these tests around will help detect problems with - # other attempts to provide reliable access to the standard library's - # implementation of the XML support. - - def test_sf_1511497(self): - # Bug report: http://www.python.org/sf/1511497 - import sys - old_modules = sys.modules.copy() - for modname in list(sys.modules.keys()): - if modname.startswith("xml."): - del sys.modules[modname] - try: - import xml.sax.expatreader - module = xml.sax.expatreader - self.assertEqual(module.__name__, "xml.sax.expatreader") - finally: - sys.modules.update(old_modules) - - def test_sf_1513611(self): - # Bug report: http://www.python.org/sf/1513611 - sio = StringIO("invalid") - parser = make_parser() - from xml.sax import SAXParseException - self.assertRaises(SAXParseException, parser.parse, sio) - - def test_main(): run_unittest(MakeParserTest, SaxutilsTest, diff --git a/Lib/xml/__init__.py b/Lib/xml/__init__.py --- a/Lib/xml/__init__.py +++ b/Lib/xml/__init__.py @@ -18,24 +18,3 @@ __all__ = ["dom", "parsers", "sax", "etree"] - -_MINIMUM_XMLPLUS_VERSION = (0, 8, 4) - - -try: - import _xmlplus -except ImportError: - pass -else: - try: - v = _xmlplus.version_info - except AttributeError: - # _xmlplus is too old; ignore it - pass - else: - if v >= _MINIMUM_XMLPLUS_VERSION: - import sys - _xmlplus.__path__.extend(__path__) - sys.modules[__name__] = _xmlplus - else: - del v diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,8 @@ Library ------- +- Issue #11164: Stop trying to use _xmlplus in the xml module. + - Issue #11888: Add log2 function to math module. Patch written by Mark Dickinson. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 08:19:50 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 May 2011 08:19:50 +0200 Subject: [Python-checkins] cpython (2.7): Issue 11164: Remove obsolete allnodes test from minidom test. Message-ID: http://hg.python.org/cpython/rev/6c7984bae459 changeset: 69970:6c7984bae459 branch: 2.7 parent: 69958:3cbbb2a7c56d user: Martin v. L?wis date: Mon May 09 08:19:13 2011 +0200 summary: Issue 11164: Remove obsolete allnodes test from minidom test. Patch by Arfrever Frehtes Taifersar Arahesis. files: Lib/test/test_minidom.py | 20 -------------------- Misc/NEWS | 2 ++ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -46,26 +46,6 @@ return doc class MinidomTest(unittest.TestCase): - def tearDown(self): - try: - Node.allnodes - except AttributeError: - # We don't actually have the minidom from the standard library, - # but are picking up the PyXML version from site-packages. - pass - else: - self.confirm(len(Node.allnodes) == 0, - "assertion: len(Node.allnodes) == 0") - if len(Node.allnodes): - print "Garbage left over:" - if verbose: - print Node.allnodes.items()[0:10] - else: - # Don't print specific nodes if repeatable results - # are needed - print len(Node.allnodes) - Node.allnodes = {} - def confirm(self, test, testname = "Test"): self.assertTrue(test, testname) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -77,6 +77,8 @@ Library ------- +- Issue #11164: Remove obsolete allnodes test from minidom test. + - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Kasun Herath. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 09:05:13 2011 From: python-checkins at python.org (mark.dickinson) Date: Mon, 09 May 2011 09:05:13 +0200 Subject: [Python-checkins] cpython: Fix cut-and-paste typo in comment: log10 -> log2. Message-ID: http://hg.python.org/cpython/rev/12c65eb7d6de changeset: 69971:12c65eb7d6de parent: 69969:e015e8560d64 user: Mark Dickinson date: Mon May 09 08:05:00 2011 +0100 summary: Fix cut-and-paste typo in comment: log10 -> log2. files: Modules/mathmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -622,7 +622,7 @@ } else { errno = EDOM; - return Py_NAN; /* log10(-inf) = nan, invalid-operation */ + return Py_NAN; /* log2(-inf) = nan, invalid-operation */ } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 09:19:01 2011 From: python-checkins at python.org (mark.dickinson) Date: Mon, 09 May 2011 09:19:01 +0200 Subject: [Python-checkins] cpython: Fix nonunique test ids in math_testcases.txt. Message-ID: http://hg.python.org/cpython/rev/fafe6f814d55 changeset: 69972:fafe6f814d55 user: Mark Dickinson date: Mon May 09 08:18:57 2011 +0100 summary: Fix nonunique test ids in math_testcases.txt. files: Lib/test/math_testcases.txt | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/math_testcases.txt b/Lib/test/math_testcases.txt --- a/Lib/test/math_testcases.txt +++ b/Lib/test/math_testcases.txt @@ -551,9 +551,9 @@ log20110 log2 2048.0 -> 11.0 log20200 log2 0.5 -> -1.0 -log20200 log2 0.25 -> -2.0 -log20200 log2 0.125 -> -3.0 -log20200 log2 0.0625 -> -4.0 +log20201 log2 0.25 -> -2.0 +log20202 log2 0.125 -> -3.0 +log20203 log2 0.0625 -> -4.0 -- values close to 1.0 log20300 log2 1.0000000000000002 -> 3.2034265038149171e-16 @@ -573,7 +573,7 @@ log20410 log2 1e-308 -> -1023.1538532253076 log20411 log2 2.2250738585072014e-308 -> -1022.0 log20412 log2 4.4501477170144028e-308 -> -1021.0 -log20412 log2 1e-307 -> -1019.8319251304202 +log20413 log2 1e-307 -> -1019.8319251304202 -- huge values log20500 log2 1.7976931348623157e+308 -> 1024.0 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 09:40:28 2011 From: python-checkins at python.org (mark.dickinson) Date: Mon, 09 May 2011 09:40:28 +0200 Subject: [Python-checkins] cpython: Grammatical fix for a comment for log2, to avoid referring to an *algorithm* as Message-ID: http://hg.python.org/cpython/rev/627780933948 changeset: 69973:627780933948 user: Mark Dickinson date: Mon May 09 08:40:20 2011 +0100 summary: Grammatical fix for a comment for log2, to avoid referring to an *algorithm* as monotonic. files: Modules/mathmodule.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -581,8 +581,10 @@ log2: log to base 2. Uses an algorithm that should: + (a) produce exact results for powers of 2, and - (b) be monotonic, assuming that the system log is monotonic. + (b) give a monotonic log2 (for positive finite floats), + assuming that the system log is monotonic. */ static double -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 12:24:19 2011 From: python-checkins at python.org (gerhard.haering) Date: Mon, 09 May 2011 12:24:19 +0200 Subject: [Python-checkins] cpython: #10811: Fix recursive usage of cursors. Instead of crashing, raise a Message-ID: http://hg.python.org/cpython/rev/c6523d6faef4 changeset: 69974:c6523d6faef4 user: Gerhard Haering date: Mon May 09 12:24:09 2011 +0200 summary: #10811: Fix recursive usage of cursors. Instead of crashing, raise a ProgrammingError now. files: Lib/sqlite3/test/regression.py | 23 +++++++++++++++++ Modules/_sqlite/cursor.c | 29 ++++++++++++++------- Modules/_sqlite/cursor.h | 1 + 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/Lib/sqlite3/test/regression.py b/Lib/sqlite3/test/regression.py --- a/Lib/sqlite3/test/regression.py +++ b/Lib/sqlite3/test/regression.py @@ -281,6 +281,29 @@ # Lone surrogate cannot be encoded to the default encoding (utf8) "\uDC80", collation_cb) + def CheckRecursiveCursorUse(self): + """ + http://bugs.python.org/issue10811 + + Recursively using a cursor, such as when reusing it from a generator led to segfaults. + Now we catch recursive cursor usage and raise a ProgrammingError. + """ + con = sqlite.connect(":memory:") + + cur = con.cursor() + cur.execute("create table a (bar)") + cur.execute("create table b (baz)") + + def foo(): + cur.execute("insert into a (bar) values (?)", (1,)) + yield 1 + + try: + cur.executemany("insert into b (baz) values (?)", ((i,) for i in foo())) + self.fail("should have raised ProgrammingError") + except sqlite.ProgrammingError: + pass + def suite(): regression_suite = unittest.makeSuite(RegressionTests, "Check") return unittest.TestSuite((regression_suite,)) diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -430,9 +430,14 @@ if (cur->closed) { PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor."); return 0; - } else { - return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection); } + + if (cur->locked) { + PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed."); + return 0; + } + + return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection); } PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args) @@ -455,9 +460,10 @@ int allow_8bit_chars; if (!check_cursor(self)) { - return NULL; + goto error; } + self->locked = 1; self->reset = 0; /* Make shooting yourself in the foot with not utf-8 decodable 8-bit-strings harder */ @@ -470,12 +476,12 @@ if (multiple) { /* executemany() */ if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) { - return NULL; + goto error; } if (!PyUnicode_Check(operation)) { PyErr_SetString(PyExc_ValueError, "operation parameter must be str"); - return NULL; + goto error; } if (PyIter_Check(second_argument)) { @@ -486,23 +492,23 @@ /* sequence */ parameters_iter = PyObject_GetIter(second_argument); if (!parameters_iter) { - return NULL; + goto error; } } } else { /* execute() */ if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) { - return NULL; + goto error; } if (!PyUnicode_Check(operation)) { PyErr_SetString(PyExc_ValueError, "operation parameter must be str"); - return NULL; + goto error; } parameters_list = PyList_New(0); if (!parameters_list) { - return NULL; + goto error; } if (second_argument == NULL) { @@ -742,7 +748,8 @@ * ROLLBACK could have happened */ #ifdef SQLITE_VERSION_NUMBER #if SQLITE_VERSION_NUMBER >= 3002002 - self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db); + if (self->connection && self->connection->db) + self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db); #endif #endif @@ -750,6 +757,8 @@ Py_XDECREF(parameters_iter); Py_XDECREF(parameters_list); + self->locked = 0; + if (PyErr_Occurred()) { self->rowcount = -1L; return NULL; diff --git a/Modules/_sqlite/cursor.h b/Modules/_sqlite/cursor.h --- a/Modules/_sqlite/cursor.h +++ b/Modules/_sqlite/cursor.h @@ -42,6 +42,7 @@ pysqlite_Statement* statement; int closed; int reset; + int locked; int initialized; /* the next row to be returned, NULL if no next row available */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 12:46:32 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 09 May 2011 12:46:32 +0200 Subject: [Python-checkins] cpython: Issue #11888: Use system log2() when available Message-ID: http://hg.python.org/cpython/rev/565f43f6bed4 changeset: 69975:565f43f6bed4 user: Victor Stinner date: Mon May 09 12:45:41 2011 +0200 summary: Issue #11888: Use system log2() when available I expect the system libc to use more accurate functions than Python. The GNU libc uses for example FYL2X and FYL2XP1 hardware instructions on Intel FPU. files: Modules/mathmodule.c | 4 ++++ configure | 2 +- configure.in | 4 ++-- pyconfig.h.in | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -602,6 +602,9 @@ } if (x > 0.0) { +#ifdef HAVE_LOG2 + return log2(x); +#else double m; int e; m = frexp(x, &e); @@ -617,6 +620,7 @@ else { return log(m) / log(2.0) + e; } +#endif } else if (x == 0.0) { errno = EDOM; diff --git a/configure b/configure --- a/configure +++ b/configure @@ -11864,7 +11864,7 @@ fi done -for ac_func in hypot lgamma log1p round tgamma +for ac_func in hypot lgamma log1p log2 round tgamma 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" diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -2512,7 +2512,7 @@ futimens futimes \ gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ - initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ + initgroups kill killpg lchmod lchown lockf log2 linkat lstat lutimes mbrtowc mkdirat mkfifo \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \ posix_fallocate posix_fadvise pread \ pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \ @@ -3368,7 +3368,7 @@ LIBS="$LIBS $LIBM" AC_CHECK_FUNCS([acosh asinh atanh copysign erf erfc expm1 finite gamma]) -AC_CHECK_FUNCS([hypot lgamma log1p round tgamma]) +AC_CHECK_FUNCS([hypot lgamma log1p log2 round tgamma]) AC_CHECK_DECLS([isinf, isnan, isfinite], [], [], [[#include ]]) # On FreeBSD 6.2, it appears that tanh(-0.) returns 0. instead of diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -476,6 +476,9 @@ /* Define to 1 if you have the `log1p' function. */ #undef HAVE_LOG1P +/* Define to 1 if you have the `log2' function. */ +#undef HAVE_LOG2 + /* Define this if you have the type long double. */ #undef HAVE_LONG_DOUBLE -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 14:46:18 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 09 May 2011 14:46:18 +0200 Subject: [Python-checkins] cpython: Issue #10811: Use TestCase.assertRaises() in the new test Message-ID: http://hg.python.org/cpython/rev/2fdabf0dc8f7 changeset: 69976:2fdabf0dc8f7 user: Victor Stinner date: Mon May 09 12:50:41 2011 +0200 summary: Issue #10811: Use TestCase.assertRaises() in the new test files: Lib/sqlite3/test/regression.py | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Lib/sqlite3/test/regression.py b/Lib/sqlite3/test/regression.py --- a/Lib/sqlite3/test/regression.py +++ b/Lib/sqlite3/test/regression.py @@ -298,11 +298,10 @@ cur.execute("insert into a (bar) values (?)", (1,)) yield 1 - try: - cur.executemany("insert into b (baz) values (?)", ((i,) for i in foo())) - self.fail("should have raised ProgrammingError") - except sqlite.ProgrammingError: - pass + with self.assertRaises(sqlite.ProgrammingError): + cur.executemany("insert into b (baz) values (?)", + ((i,) for i in foo())) + def suite(): regression_suite = unittest.makeSuite(RegressionTests, "Check") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 14:46:19 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 09 May 2011 14:46:19 +0200 Subject: [Python-checkins] cpython: faulthandler: make quiet a gcc 4.6 warning (z was unused) Message-ID: http://hg.python.org/cpython/rev/7a29f76db5c1 changeset: 69977:7a29f76db5c1 user: Victor Stinner date: Mon May 09 14:44:26 2011 +0200 summary: faulthandler: make quiet a gcc 4.6 warning (z was unused) files: Modules/faulthandler.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -805,9 +805,12 @@ PowerPC. Use volatile to disable compile-time optimizations. */ volatile int x = 1, y = 0, z; z = x / y; - /* if the division by zero didn't raise a SIGFPE, raise it manually */ + /* if the division by zero didn't raise a SIGFPE (e.g. on PowerPC), + raise it manually */ raise(SIGFPE); - Py_RETURN_NONE; + /* use z to make quiet a compiler warning, but this line + is never reached */ + return PyLong_FromLong(z); } static PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 14:46:25 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 09 May 2011 14:46:25 +0200 Subject: [Python-checkins] cpython: Issue #8407: Use an explicit cast for FreeBSD Message-ID: http://hg.python.org/cpython/rev/2e0d3092249b changeset: 69978:2e0d3092249b user: Victor Stinner date: Mon May 09 14:45:38 2011 +0200 summary: Issue #8407: Use an explicit cast for FreeBSD pthread_t is a pointer, not an integer, on FreeBSD. It should fix the following gcc warning: passing argument 1 of ?pthread_kill? makes pointer from integer without a cast files: Modules/signalmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -688,7 +688,7 @@ if (!PyArg_ParseTuple(args, "li:pthread_kill", &tid, &signum)) return NULL; - err = pthread_kill(tid, signum); + err = pthread_kill((pthread_t)tid, signum); if (err != 0) { errno = err; PyErr_SetFromErrno(PyExc_OSError); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 15:02:49 2011 From: python-checkins at python.org (mark.dickinson) Date: Mon, 09 May 2011 15:02:49 +0200 Subject: [Python-checkins] cpython: Issue #11188: In log2 tests, create powers of 2 using ldexp(1, n) instead of Message-ID: http://hg.python.org/cpython/rev/1f23d63b578c changeset: 69979:1f23d63b578c user: Mark Dickinson date: Mon May 09 14:02:45 2011 +0100 summary: Issue #11188: In log2 tests, create powers of 2 using ldexp(1, n) instead of the less reliable 2.0**n. files: Lib/test/test_math.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -653,8 +653,8 @@ def testLog2(self): self.assertRaises(TypeError, math.log2) # Check that we get exact equality for log2 of powers of 2. - actual = [math.log2(2.0**n) for n in range(-324, 1024)] - expected = [float(n) for n in range(-324, 1024)] + actual = [math.log2(math.ldexp(1.0, n)) for n in range(-1074, 1024)] + expected = [float(n) for n in range(-1074, 1024)] self.assertEqual(actual, expected) # Check some integer values -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 17:10:41 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 09 May 2011 17:10:41 +0200 Subject: [Python-checkins] cpython: Issue #11743: Rewrite multiprocessing connection classes in pure Python. Message-ID: http://hg.python.org/cpython/rev/1ac03e071d65 changeset: 69980:1ac03e071d65 user: Antoine Pitrou date: Mon May 09 17:04:27 2011 +0200 summary: Issue #11743: Rewrite multiprocessing connection classes in pure Python. files: Lib/multiprocessing/connection.py | 315 +++++- Lib/multiprocessing/forking.py | 5 +- Lib/multiprocessing/reduction.py | 13 +- Lib/test/test_multiprocessing.py | 12 +- Misc/NEWS | 2 + Modules/_multiprocessing/connection.h | 527 ---------- Modules/_multiprocessing/multiprocessing.c | 23 - Modules/_multiprocessing/multiprocessing.h | 24 +- Modules/_multiprocessing/pipe_connection.c | 149 -- Modules/_multiprocessing/socket_connection.c | 202 --- Modules/_multiprocessing/win32_functions.c | 166 +++ PC/VC6/_multiprocessing.dsp | 8 - PC/VS8.0/_multiprocessing.vcproj | 12 - PCbuild/_multiprocessing.vcproj | 12 - setup.py | 3 - 15 files changed, 490 insertions(+), 983 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -34,19 +34,27 @@ __all__ = [ 'Client', 'Listener', 'Pipe' ] +import io import os import sys +import pickle +import select import socket +import struct import errno import time import tempfile import itertools import _multiprocessing -from multiprocessing import current_process, AuthenticationError +from multiprocessing import current_process, AuthenticationError, BufferTooShort from multiprocessing.util import get_temp_dir, Finalize, sub_debug, debug -from multiprocessing.forking import duplicate, close - +try: + from _multiprocessing import win32 +except ImportError: + if sys.platform == 'win32': + raise + win32 = None # # @@ -111,6 +119,281 @@ raise ValueError('address type of %r unrecognized' % address) # +# Connection classes +# + +class _ConnectionBase: + _handle = None + + def __init__(self, handle, readable=True, writable=True): + handle = handle.__index__() + if handle < 0: + raise ValueError("invalid handle") + if not readable and not writable: + raise ValueError( + "at least one of `readable` and `writable` must be True") + self._handle = handle + self._readable = readable + self._writable = writable + + def __del__(self): + if self._handle is not None: + self._close() + + def _check_closed(self): + if self._handle is None: + raise IOError("handle is closed") + + def _check_readable(self): + if not self._readable: + raise IOError("connection is write-only") + + def _check_writable(self): + if not self._writable: + raise IOError("connection is read-only") + + def _bad_message_length(self): + if self._writable: + self._readable = False + else: + self.close() + raise IOError("bad message length") + + @property + def closed(self): + """True if the connection is closed""" + return self._handle is None + + @property + def readable(self): + """True if the connection is readable""" + return self._readable + + @property + def writable(self): + """True if the connection is writable""" + return self._writable + + def fileno(self): + """File descriptor or handle of the connection""" + self._check_closed() + return self._handle + + def close(self): + """Close the connection""" + if self._handle is not None: + try: + self._close() + finally: + self._handle = None + + def send_bytes(self, buf, offset=0, size=None): + """Send the bytes data from a bytes-like object""" + self._check_closed() + self._check_writable() + m = memoryview(buf) + # HACK for byte-indexing of non-bytewise buffers (e.g. array.array) + if m.itemsize > 1: + m = memoryview(bytes(m)) + n = len(m) + if offset < 0: + raise ValueError("offset is negative") + if n < offset: + raise ValueError("buffer length < offset") + if size is None: + size = n - offset + elif size < 0: + raise ValueError("size is negative") + elif offset + size > n: + raise ValueError("buffer length < offset + size") + self._send_bytes(m[offset:offset + size]) + + def send(self, obj): + """Send a (picklable) object""" + self._check_closed() + self._check_writable() + buf = pickle.dumps(obj, protocol=pickle.HIGHEST_PROTOCOL) + self._send_bytes(memoryview(buf)) + + def recv_bytes(self, maxlength=None): + """ + Receive bytes data as a bytes object. + """ + self._check_closed() + self._check_readable() + if maxlength is not None and maxlength < 0: + raise ValueError("negative maxlength") + buf = self._recv_bytes(maxlength) + if buf is None: + self._bad_message_length() + return buf.getvalue() + + def recv_bytes_into(self, buf, offset=0): + """ + Receive bytes data into a writeable buffer-like object. + Return the number of bytes read. + """ + self._check_closed() + self._check_readable() + with memoryview(buf) as m: + # Get bytesize of arbitrary buffer + itemsize = m.itemsize + bytesize = itemsize * len(m) + if offset < 0: + raise ValueError("negative offset") + elif offset > bytesize: + raise ValueError("offset too large") + result = self._recv_bytes() + size = result.tell() + if bytesize < offset + size: + raise BufferTooShort(result.getvalue()) + # Message can fit in dest + result.seek(0) + result.readinto(m[offset // itemsize : + (offset + size) // itemsize]) + return size + + def recv(self): + """Receive a (picklable) object""" + self._check_closed() + self._check_readable() + buf = self._recv_bytes() + return pickle.loads(buf.getbuffer()) + + def poll(self, timeout=0.0): + """Whether there is any input available to be read""" + self._check_closed() + self._check_readable() + if timeout < 0.0: + timeout = None + return self._poll(timeout) + + +if win32: + + class PipeConnection(_ConnectionBase): + """ + Connection class based on a Windows named pipe. + """ + + def _close(self): + win32.CloseHandle(self._handle) + + def _send_bytes(self, buf): + nwritten = win32.WriteFile(self._handle, buf) + assert nwritten == len(buf) + + def _recv_bytes(self, maxsize=None): + buf = io.BytesIO() + bufsize = 512 + if maxsize is not None: + bufsize = min(bufsize, maxsize) + try: + firstchunk, complete = win32.ReadFile(self._handle, bufsize) + except IOError as e: + if e.errno == win32.ERROR_BROKEN_PIPE: + raise EOFError + raise + lenfirstchunk = len(firstchunk) + buf.write(firstchunk) + if complete: + return buf + navail, nleft = win32.PeekNamedPipe(self._handle) + if maxsize is not None and lenfirstchunk + nleft > maxsize: + return None + lastchunk, complete = win32.ReadFile(self._handle, nleft) + assert complete + buf.write(lastchunk) + return buf + + def _poll(self, timeout): + navail, nleft = win32.PeekNamedPipe(self._handle) + if navail > 0: + return True + elif timeout == 0.0: + return False + # Setup a polling loop (translated straight from old + # pipe_connection.c) + if timeout < 0.0: + deadline = None + else: + deadline = time.time() + timeout + delay = 0.001 + max_delay = 0.02 + while True: + time.sleep(delay) + navail, nleft = win32.PeekNamedPipe(self._handle) + if navail > 0: + return True + if deadline and time.time() > deadline: + return False + if delay < max_delay: + delay += 0.001 + + +class Connection(_ConnectionBase): + """ + Connection class based on an arbitrary file descriptor (Unix only), or + a socket handle (Windows). + """ + + if win32: + def _close(self): + win32.closesocket(self._handle) + _write = win32.send + _read = win32.recv + else: + def _close(self): + os.close(self._handle) + _write = os.write + _read = os.read + + def _send(self, buf, write=_write): + remaining = len(buf) + while True: + n = write(self._handle, buf) + remaining -= n + if remaining == 0: + break + buf = buf[n:] + + def _recv(self, size, read=_read): + buf = io.BytesIO() + remaining = size + while remaining > 0: + chunk = read(self._handle, remaining) + n = len(chunk) + if n == 0: + if remaining == size: + raise EOFError + else: + raise IOError("got end of file during message") + buf.write(chunk) + remaining -= n + return buf + + def _send_bytes(self, buf): + # For wire compatibility with 3.2 and lower + n = len(buf) + self._send(struct.pack("=i", len(buf))) + # The condition is necessary to avoid "broken pipe" errors + # when sending a 0-length buffer if the other end closed the pipe. + if n > 0: + self._send(buf) + + def _recv_bytes(self, maxsize=None): + buf = self._recv(4) + size, = struct.unpack("=i", buf.getvalue()) + if maxsize is not None and size > maxsize: + return None + return self._recv(size) + + def _poll(self, timeout): + r = select.select([self._handle], [], [], timeout)[0] + return bool(r) + + +# # Public functions # @@ -186,21 +469,19 @@ ''' if duplex: s1, s2 = socket.socketpair() - c1 = _multiprocessing.Connection(os.dup(s1.fileno())) - c2 = _multiprocessing.Connection(os.dup(s2.fileno())) + c1 = Connection(os.dup(s1.fileno())) + c2 = Connection(os.dup(s2.fileno())) s1.close() s2.close() else: fd1, fd2 = os.pipe() - c1 = _multiprocessing.Connection(fd1, writable=False) - c2 = _multiprocessing.Connection(fd2, readable=False) + c1 = Connection(fd1, writable=False) + c2 = Connection(fd2, readable=False) return c1, c2 else: - from _multiprocessing import win32 - def Pipe(duplex=True): ''' Returns pair of connection objects at either end of a pipe @@ -234,8 +515,8 @@ if e.args[0] != win32.ERROR_PIPE_CONNECTED: raise - c1 = _multiprocessing.PipeConnection(h1, writable=duplex) - c2 = _multiprocessing.PipeConnection(h2, readable=duplex) + c1 = PipeConnection(h1, writable=duplex) + c2 = PipeConnection(h2, readable=duplex) return c1, c2 @@ -266,7 +547,7 @@ def accept(self): s, self._last_accepted = self._socket.accept() fd = duplicate(s.fileno()) - conn = _multiprocessing.Connection(fd) + conn = Connection(fd) s.close() return conn @@ -298,7 +579,7 @@ raise fd = duplicate(s.fileno()) - conn = _multiprocessing.Connection(fd) + conn = Connection(fd) return conn # @@ -345,7 +626,7 @@ except WindowsError as e: if e.args[0] != win32.ERROR_PIPE_CONNECTED: raise - return _multiprocessing.PipeConnection(handle) + return PipeConnection(handle) @staticmethod def _finalize_pipe_listener(queue, address): @@ -377,7 +658,7 @@ win32.SetNamedPipeHandleState( h, win32.PIPE_READMODE_MESSAGE, None, None ) - return _multiprocessing.PipeConnection(h) + return PipeConnection(h) # # Authentication stuff @@ -451,3 +732,7 @@ global xmlrpclib import xmlrpc.client as xmlrpclib return ConnectionWrapper(Client(*args, **kwds), _xml_dumps, _xml_loads) + + +# Late import because of circular import +from multiprocessing.forking import duplicate, close diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -183,7 +183,7 @@ import time from pickle import dump, load, HIGHEST_PROTOCOL - from _multiprocessing import win32, Connection, PipeConnection + from _multiprocessing import win32 from .util import Finalize def dump(obj, file, protocol=None): @@ -411,6 +411,9 @@ # Make (Pipe)Connection picklable # + # Late import because of circular import + from .connection import Connection, PipeConnection + def reduce_connection(conn): if not Popen.thread_is_spawning(): raise RuntimeError( diff --git a/Lib/multiprocessing/reduction.py b/Lib/multiprocessing/reduction.py --- a/Lib/multiprocessing/reduction.py +++ b/Lib/multiprocessing/reduction.py @@ -44,7 +44,7 @@ from multiprocessing import current_process from multiprocessing.forking import Popen, duplicate, close, ForkingPickler from multiprocessing.util import register_after_fork, debug, sub_debug -from multiprocessing.connection import Client, Listener +from multiprocessing.connection import Client, Listener, Connection # @@ -159,7 +159,7 @@ return new_handle # -# Register `_multiprocessing.Connection` with `ForkingPickler` +# Register `Connection` with `ForkingPickler` # def reduce_connection(conn): @@ -168,11 +168,11 @@ def rebuild_connection(reduced_handle, readable, writable): handle = rebuild_handle(reduced_handle) - return _multiprocessing.Connection( + return Connection( handle, readable=readable, writable=writable ) -ForkingPickler.register(_multiprocessing.Connection, reduce_connection) +ForkingPickler.register(Connection, reduce_connection) # # Register `socket.socket` with `ForkingPickler` @@ -201,6 +201,7 @@ # if sys.platform == 'win32': + from multiprocessing.connection import PipeConnection def reduce_pipe_connection(conn): rh = reduce_handle(conn.fileno()) @@ -208,8 +209,8 @@ def rebuild_pipe_connection(reduced_handle, readable, writable): handle = rebuild_handle(reduced_handle) - return _multiprocessing.PipeConnection( + return PipeConnection( handle, readable=readable, writable=writable ) - ForkingPickler.register(_multiprocessing.PipeConnection, reduce_pipe_connection) + ForkingPickler.register(PipeConnection, reduce_pipe_connection) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -1915,9 +1915,15 @@ @unittest.skipIf(WIN32, "skipped on Windows") def test_invalid_handles(self): - conn = _multiprocessing.Connection(44977608) - self.assertRaises(IOError, conn.poll) - self.assertRaises(IOError, _multiprocessing.Connection, -1) + conn = multiprocessing.connection.Connection(44977608) + try: + self.assertRaises((ValueError, IOError), conn.poll) + finally: + # Hack private attribute _handle to avoid printing an error + # in conn.__del__ + conn._handle = None + self.assertRaises((ValueError, IOError), + multiprocessing.connection.Connection, -1) # # Functions used to create test cases from the base ones in this module diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,8 @@ Library ------- +- Issue #11743: Rewrite multiprocessing connection classes in pure Python. + - Issue #11164: Stop trying to use _xmlplus in the xml module. - Issue #11888: Add log2 function to math module. Patch written by Mark diff --git a/Modules/_multiprocessing/connection.h b/Modules/_multiprocessing/connection.h deleted file mode 100644 --- a/Modules/_multiprocessing/connection.h +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Definition of a `Connection` type. - * Used by `socket_connection.c` and `pipe_connection.c`. - * - * connection.h - * - * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt - */ - -#ifndef CONNECTION_H -#define CONNECTION_H - -/* - * Read/write flags - */ - -#define READABLE 1 -#define WRITABLE 2 - -#define CHECK_READABLE(self) \ - if (!(self->flags & READABLE)) { \ - PyErr_SetString(PyExc_IOError, "connection is write-only"); \ - return NULL; \ - } - -#define CHECK_WRITABLE(self) \ - if (!(self->flags & WRITABLE)) { \ - PyErr_SetString(PyExc_IOError, "connection is read-only"); \ - return NULL; \ - } - -/* - * Allocation and deallocation - */ - -static PyObject * -connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - ConnectionObject *self; - HANDLE handle; - BOOL readable = TRUE, writable = TRUE; - - static char *kwlist[] = {"handle", "readable", "writable", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, F_HANDLE "|ii", kwlist, - &handle, &readable, &writable)) - return NULL; - - if (handle == INVALID_HANDLE_VALUE || (Py_ssize_t)handle < 0) { - PyErr_Format(PyExc_IOError, "invalid handle %zd", - (Py_ssize_t)handle); - return NULL; - } - - if (!readable && !writable) { - PyErr_SetString(PyExc_ValueError, - "either readable or writable must be true"); - return NULL; - } - - self = PyObject_New(ConnectionObject, type); - if (self == NULL) - return NULL; - - self->weakreflist = NULL; - self->handle = handle; - self->flags = 0; - - if (readable) - self->flags |= READABLE; - if (writable) - self->flags |= WRITABLE; - assert(self->flags >= 1 && self->flags <= 3); - - return (PyObject*)self; -} - -static void -connection_dealloc(ConnectionObject* self) -{ - if (self->weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject*)self); - - if (self->handle != INVALID_HANDLE_VALUE) { - Py_BEGIN_ALLOW_THREADS - CLOSE(self->handle); - Py_END_ALLOW_THREADS - } - PyObject_Del(self); -} - -/* - * Functions for transferring buffers - */ - -static PyObject * -connection_sendbytes(ConnectionObject *self, PyObject *args) -{ - Py_buffer pbuffer; - char *buffer; - Py_ssize_t length, offset=0, size=PY_SSIZE_T_MIN; - int res; - - if (!PyArg_ParseTuple(args, F_RBUFFER "*|" F_PY_SSIZE_T F_PY_SSIZE_T, - &pbuffer, &offset, &size)) - return NULL; - buffer = pbuffer.buf; - length = pbuffer.len; - - CHECK_WRITABLE(self); /* XXX release buffer in case of failure */ - - if (offset < 0) { - PyBuffer_Release(&pbuffer); - PyErr_SetString(PyExc_ValueError, "offset is negative"); - return NULL; - } - if (length < offset) { - PyBuffer_Release(&pbuffer); - PyErr_SetString(PyExc_ValueError, "buffer length < offset"); - return NULL; - } - - if (size == PY_SSIZE_T_MIN) { - size = length - offset; - } else { - if (size < 0) { - PyBuffer_Release(&pbuffer); - PyErr_SetString(PyExc_ValueError, "size is negative"); - return NULL; - } - if (offset + size > length) { - PyBuffer_Release(&pbuffer); - PyErr_SetString(PyExc_ValueError, - "buffer length < offset + size"); - return NULL; - } - } - - res = conn_send_string(self, buffer + offset, size); - - PyBuffer_Release(&pbuffer); - if (res < 0) { - if (PyErr_Occurred()) - return NULL; - else - return mp_SetError(PyExc_IOError, res); - } - - Py_RETURN_NONE; -} - -static PyObject * -connection_recvbytes(ConnectionObject *self, PyObject *args) -{ - char *freeme = NULL; - Py_ssize_t res, maxlength = PY_SSIZE_T_MAX; - PyObject *result = NULL; - - if (!PyArg_ParseTuple(args, "|" F_PY_SSIZE_T, &maxlength)) - return NULL; - - CHECK_READABLE(self); - - if (maxlength < 0) { - PyErr_SetString(PyExc_ValueError, "maxlength < 0"); - return NULL; - } - - res = conn_recv_string(self, self->buffer, CONNECTION_BUFFER_SIZE, - &freeme, maxlength); - - if (res < 0) { - if (res == MP_BAD_MESSAGE_LENGTH) { - if ((self->flags & WRITABLE) == 0) { - Py_BEGIN_ALLOW_THREADS - CLOSE(self->handle); - Py_END_ALLOW_THREADS - self->handle = INVALID_HANDLE_VALUE; - } else { - self->flags = WRITABLE; - } - } - mp_SetError(PyExc_IOError, res); - } else { - if (freeme == NULL) { - result = PyBytes_FromStringAndSize(self->buffer, res); - } else { - result = PyBytes_FromStringAndSize(freeme, res); - PyMem_Free(freeme); - } - } - - return result; -} - -static PyObject * -connection_recvbytes_into(ConnectionObject *self, PyObject *args) -{ - char *freeme = NULL, *buffer = NULL; - Py_ssize_t res, length, offset = 0; - PyObject *result = NULL; - Py_buffer pbuf; - - CHECK_READABLE(self); - - if (!PyArg_ParseTuple(args, "w*|" F_PY_SSIZE_T, - &pbuf, &offset)) - return NULL; - - buffer = pbuf.buf; - length = pbuf.len; - - if (offset < 0) { - PyErr_SetString(PyExc_ValueError, "negative offset"); - goto _error; - } - - if (offset > length) { - PyErr_SetString(PyExc_ValueError, "offset too large"); - goto _error; - } - - res = conn_recv_string(self, buffer+offset, length-offset, - &freeme, PY_SSIZE_T_MAX); - - if (res < 0) { - if (res == MP_BAD_MESSAGE_LENGTH) { - if ((self->flags & WRITABLE) == 0) { - Py_BEGIN_ALLOW_THREADS - CLOSE(self->handle); - Py_END_ALLOW_THREADS - self->handle = INVALID_HANDLE_VALUE; - } else { - self->flags = WRITABLE; - } - } - mp_SetError(PyExc_IOError, res); - } else { - if (freeme == NULL) { - result = PyInt_FromSsize_t(res); - } else { - result = PyObject_CallFunction(BufferTooShort, - F_RBUFFER "#", - freeme, res); - PyMem_Free(freeme); - if (result) { - PyErr_SetObject(BufferTooShort, result); - Py_DECREF(result); - } - goto _error; - } - } - -_cleanup: - PyBuffer_Release(&pbuf); - return result; - -_error: - result = NULL; - goto _cleanup; -} - -/* - * Functions for transferring objects - */ - -static PyObject * -connection_send_obj(ConnectionObject *self, PyObject *obj) -{ - char *buffer; - int res; - Py_ssize_t length; - PyObject *pickled_string = NULL; - - CHECK_WRITABLE(self); - - pickled_string = PyObject_CallFunctionObjArgs(pickle_dumps, obj, - pickle_protocol, NULL); - if (!pickled_string) - goto failure; - - if (PyBytes_AsStringAndSize(pickled_string, &buffer, &length) < 0) - goto failure; - - res = conn_send_string(self, buffer, (int)length); - - if (res < 0) { - mp_SetError(PyExc_IOError, res); - goto failure; - } - - Py_XDECREF(pickled_string); - Py_RETURN_NONE; - - failure: - Py_XDECREF(pickled_string); - return NULL; -} - -static PyObject * -connection_recv_obj(ConnectionObject *self) -{ - char *freeme = NULL; - Py_ssize_t res; - PyObject *temp = NULL, *result = NULL; - - CHECK_READABLE(self); - - res = conn_recv_string(self, self->buffer, CONNECTION_BUFFER_SIZE, - &freeme, PY_SSIZE_T_MAX); - - if (res < 0) { - if (res == MP_BAD_MESSAGE_LENGTH) { - if ((self->flags & WRITABLE) == 0) { - Py_BEGIN_ALLOW_THREADS - CLOSE(self->handle); - Py_END_ALLOW_THREADS - self->handle = INVALID_HANDLE_VALUE; - } else { - self->flags = WRITABLE; - } - } - mp_SetError(PyExc_IOError, res); - } else { - if (freeme == NULL) { - temp = PyBytes_FromStringAndSize(self->buffer, res); - } else { - temp = PyBytes_FromStringAndSize(freeme, res); - PyMem_Free(freeme); - } - } - - if (temp) - result = PyObject_CallFunctionObjArgs(pickle_loads, - temp, NULL); - Py_XDECREF(temp); - return result; -} - -/* - * Other functions - */ - -static PyObject * -connection_poll(ConnectionObject *self, PyObject *args) -{ - PyObject *timeout_obj = NULL; - double timeout = 0.0; - int res; - - CHECK_READABLE(self); - - if (!PyArg_ParseTuple(args, "|O", &timeout_obj)) - return NULL; - - if (timeout_obj == NULL) { - timeout = 0.0; - } else if (timeout_obj == Py_None) { - timeout = -1.0; /* block forever */ - } else { - timeout = PyFloat_AsDouble(timeout_obj); - if (PyErr_Occurred()) - return NULL; - if (timeout < 0.0) - timeout = 0.0; - } - - Py_BEGIN_ALLOW_THREADS - res = conn_poll(self, timeout, _save); - Py_END_ALLOW_THREADS - - switch (res) { - case TRUE: - Py_RETURN_TRUE; - case FALSE: - Py_RETURN_FALSE; - default: - return mp_SetError(PyExc_IOError, res); - } -} - -static PyObject * -connection_fileno(ConnectionObject* self) -{ - if (self->handle == INVALID_HANDLE_VALUE) { - PyErr_SetString(PyExc_IOError, "handle is invalid"); - return NULL; - } - return PyInt_FromLong((long)self->handle); -} - -static PyObject * -connection_close(ConnectionObject *self) -{ - if (self->handle != INVALID_HANDLE_VALUE) { - Py_BEGIN_ALLOW_THREADS - CLOSE(self->handle); - Py_END_ALLOW_THREADS - self->handle = INVALID_HANDLE_VALUE; - } - - Py_RETURN_NONE; -} - -static PyObject * -connection_repr(ConnectionObject *self) -{ - static char *conn_type[] = {"read-only", "write-only", "read-write"}; - - assert(self->flags >= 1 && self->flags <= 3); - return FROM_FORMAT("<%s %s, handle %zd>", - conn_type[self->flags - 1], - CONNECTION_NAME, (Py_ssize_t)self->handle); -} - -/* - * Getters and setters - */ - -static PyObject * -connection_closed(ConnectionObject *self, void *closure) -{ - return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE)); -} - -static PyObject * -connection_readable(ConnectionObject *self, void *closure) -{ - return PyBool_FromLong((long)(self->flags & READABLE)); -} - -static PyObject * -connection_writable(ConnectionObject *self, void *closure) -{ - return PyBool_FromLong((long)(self->flags & WRITABLE)); -} - -/* - * Tables - */ - -static PyMethodDef connection_methods[] = { - {"send_bytes", (PyCFunction)connection_sendbytes, METH_VARARGS, - "send the byte data from a readable buffer-like object"}, - {"recv_bytes", (PyCFunction)connection_recvbytes, METH_VARARGS, - "receive byte data as a string"}, - {"recv_bytes_into",(PyCFunction)connection_recvbytes_into,METH_VARARGS, - "receive byte data into a writeable buffer-like object\n" - "returns the number of bytes read"}, - - {"send", (PyCFunction)connection_send_obj, METH_O, - "send a (picklable) object"}, - {"recv", (PyCFunction)connection_recv_obj, METH_NOARGS, - "receive a (picklable) object"}, - - {"poll", (PyCFunction)connection_poll, METH_VARARGS, - "whether there is any input available to be read"}, - {"fileno", (PyCFunction)connection_fileno, METH_NOARGS, - "file descriptor or handle of the connection"}, - {"close", (PyCFunction)connection_close, METH_NOARGS, - "close the connection"}, - - {NULL} /* Sentinel */ -}; - -static PyGetSetDef connection_getset[] = { - {"closed", (getter)connection_closed, NULL, - "True if the connection is closed", NULL}, - {"readable", (getter)connection_readable, NULL, - "True if the connection is readable", NULL}, - {"writable", (getter)connection_writable, NULL, - "True if the connection is writable", NULL}, - {NULL} -}; - -/* - * Connection type - */ - -PyDoc_STRVAR(connection_doc, - "Connection type whose constructor signature is\n\n" - " Connection(handle, readable=True, writable=True).\n\n" - "The constructor does *not* duplicate the handle."); - -PyTypeObject CONNECTION_TYPE = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_multiprocessing." CONNECTION_NAME, - /* tp_basicsize */ sizeof(ConnectionObject), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)connection_dealloc, - /* tp_print */ 0, - /* tp_getattr */ 0, - /* tp_setattr */ 0, - /* tp_reserved */ 0, - /* tp_repr */ (reprfunc)connection_repr, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ 0, - /* tp_call */ 0, - /* tp_str */ 0, - /* tp_getattro */ 0, - /* tp_setattro */ 0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_WEAKREFS, - /* tp_doc */ connection_doc, - /* tp_traverse */ 0, - /* tp_clear */ 0, - /* tp_richcompare */ 0, - /* tp_weaklistoffset */ offsetof(ConnectionObject, weakreflist), - /* tp_iter */ 0, - /* tp_iternext */ 0, - /* tp_methods */ connection_methods, - /* tp_members */ 0, - /* tp_getset */ connection_getset, - /* tp_base */ 0, - /* tp_dict */ 0, - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ connection_new, -}; - -#endif /* CONNECTION_H */ diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -49,16 +49,6 @@ case MP_MEMORY_ERROR: PyErr_NoMemory(); break; - case MP_END_OF_FILE: - PyErr_SetNone(PyExc_EOFError); - break; - case MP_EARLY_END_OF_FILE: - PyErr_SetString(PyExc_IOError, - "got end of file during message"); - break; - case MP_BAD_MESSAGE_LENGTH: - PyErr_SetString(PyExc_IOError, "bad message length"); - break; case MP_EXCEPTION_HAS_BEEN_SET: break; default: @@ -257,12 +247,6 @@ BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort"); Py_XDECREF(temp); - /* Add connection type to module */ - if (PyType_Ready(&ConnectionType) < 0) - return NULL; - Py_INCREF(&ConnectionType); - PyModule_AddObject(module, "Connection", (PyObject*)&ConnectionType); - #if defined(MS_WINDOWS) || \ (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)) /* Add SemLock type to module */ @@ -286,13 +270,6 @@ #endif #ifdef MS_WINDOWS - /* Add PipeConnection to module */ - if (PyType_Ready(&PipeConnectionType) < 0) - return NULL; - Py_INCREF(&PipeConnectionType); - PyModule_AddObject(module, "PipeConnection", - (PyObject*)&PipeConnectionType); - /* Initialize win32 class and add to multiprocessing */ temp = create_win32_namespace(); if (!temp) diff --git a/Modules/_multiprocessing/multiprocessing.h b/Modules/_multiprocessing/multiprocessing.h --- a/Modules/_multiprocessing/multiprocessing.h +++ b/Modules/_multiprocessing/multiprocessing.h @@ -118,11 +118,8 @@ #define MP_SUCCESS (0) #define MP_STANDARD_ERROR (-1) #define MP_MEMORY_ERROR (-1001) -#define MP_END_OF_FILE (-1002) -#define MP_EARLY_END_OF_FILE (-1003) -#define MP_BAD_MESSAGE_LENGTH (-1004) -#define MP_SOCKET_ERROR (-1005) -#define MP_EXCEPTION_HAS_BEEN_SET (-1006) +#define MP_SOCKET_ERROR (-1002) +#define MP_EXCEPTION_HAS_BEEN_SET (-1003) PyObject *mp_SetError(PyObject *Type, int num); @@ -135,7 +132,6 @@ extern PyObject *pickle_protocol; extern PyObject *BufferTooShort; extern PyTypeObject SemLockType; -extern PyTypeObject ConnectionType; extern PyTypeObject PipeConnectionType; extern HANDLE sigint_event; @@ -162,25 +158,9 @@ #endif /* - * Connection definition - */ - -#define CONNECTION_BUFFER_SIZE 1024 - -typedef struct { - PyObject_HEAD - HANDLE handle; - int flags; - PyObject *weakreflist; - char buffer[CONNECTION_BUFFER_SIZE]; -} ConnectionObject; - -/* * Miscellaneous */ -#define MAX_MESSAGE_LENGTH 0x7fffffff - #ifndef MIN # define MIN(x, y) ((x) < (y) ? x : y) # define MAX(x, y) ((x) > (y) ? x : y) diff --git a/Modules/_multiprocessing/pipe_connection.c b/Modules/_multiprocessing/pipe_connection.c deleted file mode 100644 --- a/Modules/_multiprocessing/pipe_connection.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * A type which wraps a pipe handle in message oriented mode - * - * pipe_connection.c - * - * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt - */ - -#include "multiprocessing.h" - -#define CLOSE(h) CloseHandle(h) - -/* - * Send string to the pipe; assumes in message oriented mode - */ - -static Py_ssize_t -conn_send_string(ConnectionObject *conn, char *string, size_t length) -{ - DWORD amount_written; - BOOL ret; - - Py_BEGIN_ALLOW_THREADS - ret = WriteFile(conn->handle, string, length, &amount_written, NULL); - Py_END_ALLOW_THREADS - - if (ret == 0 && GetLastError() == ERROR_NO_SYSTEM_RESOURCES) { - PyErr_Format(PyExc_ValueError, "Cannnot send %" PY_FORMAT_SIZE_T "d bytes over connection", length); - return MP_STANDARD_ERROR; - } - - return ret ? MP_SUCCESS : MP_STANDARD_ERROR; -} - -/* - * Attempts to read into buffer, or if buffer too small into *newbuffer. - * - * Returns number of bytes read. Assumes in message oriented mode. - */ - -static Py_ssize_t -conn_recv_string(ConnectionObject *conn, char *buffer, - size_t buflength, char **newbuffer, size_t maxlength) -{ - DWORD left, length, full_length, err; - BOOL ret; - *newbuffer = NULL; - - Py_BEGIN_ALLOW_THREADS - ret = ReadFile(conn->handle, buffer, MIN(buflength, maxlength), - &length, NULL); - Py_END_ALLOW_THREADS - if (ret) - return length; - - err = GetLastError(); - if (err != ERROR_MORE_DATA) { - if (err == ERROR_BROKEN_PIPE) - return MP_END_OF_FILE; - return MP_STANDARD_ERROR; - } - - if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, NULL, &left)) - return MP_STANDARD_ERROR; - - full_length = length + left; - if (full_length > maxlength) - return MP_BAD_MESSAGE_LENGTH; - - *newbuffer = PyMem_Malloc(full_length); - if (*newbuffer == NULL) - return MP_MEMORY_ERROR; - - memcpy(*newbuffer, buffer, length); - - Py_BEGIN_ALLOW_THREADS - ret = ReadFile(conn->handle, *newbuffer+length, left, &length, NULL); - Py_END_ALLOW_THREADS - if (ret) { - assert(length == left); - return full_length; - } else { - PyMem_Free(*newbuffer); - return MP_STANDARD_ERROR; - } -} - -/* - * Check whether any data is available for reading - */ - -static int -conn_poll(ConnectionObject *conn, double timeout, PyThreadState *_save) -{ - DWORD bytes, deadline, delay; - int difference, res; - BOOL block = FALSE; - - if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL)) - return MP_STANDARD_ERROR; - - if (timeout == 0.0) - return bytes > 0; - - if (timeout < 0.0) - block = TRUE; - else - /* XXX does not check for overflow */ - deadline = GetTickCount() + (DWORD)(1000 * timeout + 0.5); - - Sleep(0); - - for (delay = 1 ; ; delay += 1) { - if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL)) - return MP_STANDARD_ERROR; - else if (bytes > 0) - return TRUE; - - if (!block) { - difference = deadline - GetTickCount(); - if (difference < 0) - return FALSE; - if ((int)delay > difference) - delay = difference; - } - - if (delay > 20) - delay = 20; - - Sleep(delay); - - /* check for signals */ - Py_BLOCK_THREADS - res = PyErr_CheckSignals(); - Py_UNBLOCK_THREADS - - if (res) - return MP_EXCEPTION_HAS_BEEN_SET; - } -} - -/* - * "connection.h" defines the PipeConnection type using the definitions above - */ - -#define CONNECTION_NAME "PipeConnection" -#define CONNECTION_TYPE PipeConnectionType - -#include "connection.h" diff --git a/Modules/_multiprocessing/socket_connection.c b/Modules/_multiprocessing/socket_connection.c deleted file mode 100644 --- a/Modules/_multiprocessing/socket_connection.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * A type which wraps a socket - * - * socket_connection.c - * - * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt - */ - -#include "multiprocessing.h" - -#ifdef MS_WINDOWS -# define WRITE(h, buffer, length) send((SOCKET)h, buffer, length, 0) -# define READ(h, buffer, length) recv((SOCKET)h, buffer, length, 0) -# define CLOSE(h) closesocket((SOCKET)h) -#else -# define WRITE(h, buffer, length) write(h, buffer, length) -# define READ(h, buffer, length) read(h, buffer, length) -# define CLOSE(h) close(h) -#endif - -/* - * Send string to file descriptor - */ - -static Py_ssize_t -_conn_sendall(HANDLE h, char *string, size_t length) -{ - char *p = string; - Py_ssize_t res; - - while (length > 0) { - res = WRITE(h, p, length); - if (res < 0) - return MP_SOCKET_ERROR; - length -= res; - p += res; - } - - return MP_SUCCESS; -} - -/* - * Receive string of exact length from file descriptor - */ - -static Py_ssize_t -_conn_recvall(HANDLE h, char *buffer, size_t length) -{ - size_t remaining = length; - Py_ssize_t temp; - char *p = buffer; - - while (remaining > 0) { - temp = READ(h, p, remaining); - if (temp <= 0) { - if (temp == 0) - return remaining == length ? - MP_END_OF_FILE : MP_EARLY_END_OF_FILE; - else - return temp; - } - remaining -= temp; - p += temp; - } - - return MP_SUCCESS; -} - -/* - * Send a string prepended by the string length in network byte order - */ - -static Py_ssize_t -conn_send_string(ConnectionObject *conn, char *string, size_t length) -{ - Py_ssize_t res; - /* The "header" of the message is a 32 bit unsigned number (in - network order) which specifies the length of the "body". If - the message is shorter than about 16kb then it is quicker to - combine the "header" and the "body" of the message and send - them at once. */ - if (length < (16*1024)) { - char *message; - - message = PyMem_Malloc(length+4); - if (message == NULL) - return MP_MEMORY_ERROR; - - *(UINT32*)message = htonl((UINT32)length); - memcpy(message+4, string, length); - Py_BEGIN_ALLOW_THREADS - res = _conn_sendall(conn->handle, message, length+4); - Py_END_ALLOW_THREADS - PyMem_Free(message); - } else { - UINT32 lenbuff; - - if (length > MAX_MESSAGE_LENGTH) - return MP_BAD_MESSAGE_LENGTH; - - lenbuff = htonl((UINT32)length); - Py_BEGIN_ALLOW_THREADS - res = _conn_sendall(conn->handle, (char*)&lenbuff, 4) || - _conn_sendall(conn->handle, string, length); - Py_END_ALLOW_THREADS - } - return res; -} - -/* - * Attempts to read into buffer, or failing that into *newbuffer - * - * Returns number of bytes read. - */ - -static Py_ssize_t -conn_recv_string(ConnectionObject *conn, char *buffer, - size_t buflength, char **newbuffer, size_t maxlength) -{ - int res; - UINT32 ulength; - - *newbuffer = NULL; - - Py_BEGIN_ALLOW_THREADS - res = _conn_recvall(conn->handle, (char*)&ulength, 4); - Py_END_ALLOW_THREADS - if (res < 0) - return res; - - ulength = ntohl(ulength); - if (ulength > maxlength) - return MP_BAD_MESSAGE_LENGTH; - - if (ulength <= buflength) { - Py_BEGIN_ALLOW_THREADS - res = _conn_recvall(conn->handle, buffer, (size_t)ulength); - Py_END_ALLOW_THREADS - return res < 0 ? res : ulength; - } else { - *newbuffer = PyMem_Malloc((size_t)ulength); - if (*newbuffer == NULL) - return MP_MEMORY_ERROR; - Py_BEGIN_ALLOW_THREADS - res = _conn_recvall(conn->handle, *newbuffer, (size_t)ulength); - Py_END_ALLOW_THREADS - return res < 0 ? (Py_ssize_t)res : (Py_ssize_t)ulength; - } -} - -/* - * Check whether any data is available for reading -- neg timeout blocks - */ - -static int -conn_poll(ConnectionObject *conn, double timeout, PyThreadState *_save) -{ - int res; - fd_set rfds; - - /* - * Verify the handle, issue 3321. Not required for windows. - */ - #ifndef MS_WINDOWS - if (((int)conn->handle) < 0 || ((int)conn->handle) >= FD_SETSIZE) { - Py_BLOCK_THREADS - PyErr_SetString(PyExc_IOError, "handle out of range in select()"); - Py_UNBLOCK_THREADS - return MP_EXCEPTION_HAS_BEEN_SET; - } - #endif - - FD_ZERO(&rfds); - FD_SET((SOCKET)conn->handle, &rfds); - - if (timeout < 0.0) { - res = select((int)conn->handle+1, &rfds, NULL, NULL, NULL); - } else { - struct timeval tv; - tv.tv_sec = (long)timeout; - tv.tv_usec = (long)((timeout - tv.tv_sec) * 1e6 + 0.5); - res = select((int)conn->handle+1, &rfds, NULL, NULL, &tv); - } - - if (res < 0) { - return MP_SOCKET_ERROR; - } else if (FD_ISSET(conn->handle, &rfds)) { - return TRUE; - } else { - assert(res == 0); - return FALSE; - } -} - -/* - * "connection.h" defines the Connection type using defs above - */ - -#define CONNECTION_NAME "Connection" -#define CONNECTION_TYPE ConnectionType - -#include "connection.h" diff --git a/Modules/_multiprocessing/win32_functions.c b/Modules/_multiprocessing/win32_functions.c --- a/Modules/_multiprocessing/win32_functions.c +++ b/Modules/_multiprocessing/win32_functions.c @@ -215,6 +215,164 @@ Py_RETURN_NONE; } +static PyObject * +win32_closesocket(PyObject *self, PyObject *args) +{ + HANDLE handle; + int ret; + + if (!PyArg_ParseTuple(args, F_HANDLE ":closesocket" , &handle)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ret = closesocket((SOCKET) handle); + Py_END_ALLOW_THREADS + + if (ret) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError()); + Py_RETURN_NONE; +} + +static PyObject * +win32_recv(PyObject *self, PyObject *args) +{ + HANDLE handle; + int size, nread; + PyObject *buf; + + if (!PyArg_ParseTuple(args, F_HANDLE "i:recv" , &handle, &size)) + return NULL; + + buf = PyBytes_FromStringAndSize(NULL, size); + if (!buf) + return NULL; + + Py_BEGIN_ALLOW_THREADS + nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0); + Py_END_ALLOW_THREADS + + if (nread < 0) { + Py_DECREF(buf); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError()); + } + _PyBytes_Resize(&buf, nread); + return buf; +} + +static PyObject * +win32_send(PyObject *self, PyObject *args) +{ + HANDLE handle; + Py_buffer buf; + int ret; + + if (!PyArg_ParseTuple(args, F_HANDLE "y*:send" , &handle, &buf)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ret = send((SOCKET) handle, buf.buf, buf.len, 0); + Py_END_ALLOW_THREADS + + PyBuffer_Release(&buf); + if (ret < 0) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError()); + return PyLong_FromLong(ret); +} + +static PyObject * +win32_WriteFile(PyObject *self, PyObject *args) +{ + HANDLE handle; + Py_buffer buf; + int written; + BOOL ret; + + if (!PyArg_ParseTuple(args, F_HANDLE "y*:WriteFile" , &handle, &buf)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ret = WriteFile(handle, buf.buf, buf.len, &written, NULL); + Py_END_ALLOW_THREADS + + PyBuffer_Release(&buf); + if (!ret) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + return PyLong_FromLong(written); +} + +static PyObject * +win32_ReadFile(PyObject *self, PyObject *args) +{ + HANDLE handle; + int size; + DWORD nread; + PyObject *buf; + BOOL ret; + + if (!PyArg_ParseTuple(args, F_HANDLE "i:ReadFile" , &handle, &size)) + return NULL; + + buf = PyBytes_FromStringAndSize(NULL, size); + if (!buf) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread, NULL); + Py_END_ALLOW_THREADS + + if (!ret && GetLastError() != ERROR_MORE_DATA) { + Py_DECREF(buf); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + if (_PyBytes_Resize(&buf, nread)) + return NULL; + return Py_BuildValue("NN", buf, PyBool_FromLong(ret)); +} + +static PyObject * +win32_PeekNamedPipe(PyObject *self, PyObject *args) +{ + HANDLE handle; + int size = 0; + PyObject *buf = NULL; + DWORD nread, navail, nleft; + BOOL ret; + + if (!PyArg_ParseTuple(args, F_HANDLE "|i:PeekNamedPipe" , &handle, &size)) + return NULL; + + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "negative size"); + return NULL; + } + + if (size) { + buf = PyBytes_FromStringAndSize(NULL, size); + if (!buf) + return NULL; + Py_BEGIN_ALLOW_THREADS + ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread, + &navail, &nleft); + Py_END_ALLOW_THREADS + if (!ret) { + Py_DECREF(buf); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + if (_PyBytes_Resize(&buf, nread)) + return NULL; + return Py_BuildValue("Nii", buf, navail, nleft); + } + else { + Py_BEGIN_ALLOW_THREADS + ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft); + Py_END_ALLOW_THREADS + if (!ret) { + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + return Py_BuildValue("ii", navail, nleft); + } +} + static PyMethodDef win32_methods[] = { WIN32_FUNCTION(CloseHandle), WIN32_FUNCTION(GetLastError), @@ -223,8 +381,14 @@ WIN32_FUNCTION(ConnectNamedPipe), WIN32_FUNCTION(CreateFile), WIN32_FUNCTION(CreateNamedPipe), + WIN32_FUNCTION(ReadFile), + WIN32_FUNCTION(PeekNamedPipe), WIN32_FUNCTION(SetNamedPipeHandleState), WIN32_FUNCTION(WaitNamedPipe), + WIN32_FUNCTION(WriteFile), + WIN32_FUNCTION(closesocket), + WIN32_FUNCTION(recv), + WIN32_FUNCTION(send), {NULL} }; @@ -244,6 +408,8 @@ Py_INCREF(&Win32Type); WIN32_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS); + WIN32_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE); + WIN32_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); WIN32_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); WIN32_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); WIN32_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); diff --git a/PC/VC6/_multiprocessing.dsp b/PC/VC6/_multiprocessing.dsp --- a/PC/VC6/_multiprocessing.dsp +++ b/PC/VC6/_multiprocessing.dsp @@ -97,18 +97,10 @@ # End Source File # Begin Source File -SOURCE=..\..\Modules\_multiprocessing\pipe_connection.c -# End Source File -# Begin Source File - SOURCE=..\..\Modules\_multiprocessing\semaphore.c # End Source File # Begin Source File -SOURCE=..\..\Modules\_multiprocessing\socket_connection.c -# End Source File -# Begin Source File - SOURCE=..\..\Modules\_multiprocessing\win32_functions.c # End Source File # End Target diff --git a/PC/VS8.0/_multiprocessing.vcproj b/PC/VS8.0/_multiprocessing.vcproj --- a/PC/VS8.0/_multiprocessing.vcproj +++ b/PC/VS8.0/_multiprocessing.vcproj @@ -522,10 +522,6 @@ RelativePath="..\..\Modules\_multiprocessing\multiprocessing.h" > - - - - - - diff --git a/PCbuild/_multiprocessing.vcproj b/PCbuild/_multiprocessing.vcproj --- a/PCbuild/_multiprocessing.vcproj +++ b/PCbuild/_multiprocessing.vcproj @@ -522,10 +522,6 @@ RelativePath="..\Modules\_multiprocessing\multiprocessing.h" > - - - - - - diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -1353,14 +1353,11 @@ if platform == 'win32': multiprocessing_srcs = [ '_multiprocessing/multiprocessing.c', '_multiprocessing/semaphore.c', - '_multiprocessing/pipe_connection.c', - '_multiprocessing/socket_connection.c', '_multiprocessing/win32_functions.c' ] else: multiprocessing_srcs = [ '_multiprocessing/multiprocessing.c', - '_multiprocessing/socket_connection.c' ] if (sysconfig.get_config_var('HAVE_SEM_OPEN') and not sysconfig.get_config_var('POSIX_SEMAPHORES_NOT_ENABLED')): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 17:25:16 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 09 May 2011 17:25:16 +0200 Subject: [Python-checkins] cpython: Issue #3709: a flush_headers method to BaseHTTPRequestHandler which manages the Message-ID: http://hg.python.org/cpython/rev/25298224cb25 changeset: 69981:25298224cb25 user: Senthil Kumaran date: Mon May 09 23:25:02 2011 +0800 summary: Issue #3709: a flush_headers method to BaseHTTPRequestHandler which manages the sending of headers to output stream and flushing the internal headers buffer. Patch contribution by Andrew Schaaf files: Doc/library/http.server.rst | 27 +++++-- Lib/http/server.py | 18 ++++- Lib/test/test_httpservers.py | 75 ++++++++++++++++++----- Misc/NEWS | 4 + 4 files changed, 93 insertions(+), 31 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -179,16 +179,17 @@ .. method:: send_response(code, message=None) - Sends a response header and logs the accepted request. The HTTP response - line is sent, followed by *Server* and *Date* headers. The values for - these two headers are picked up from the :meth:`version_string` and - :meth:`date_time_string` methods, respectively. + Adds a response header to the headers buffer and logs the accepted + request. The HTTP response line is sent, followed by *Server* and + *Date* headers. The values for these two headers are picked up from + the :meth:`version_string` and :meth:`date_time_string` methods, + respectively. .. method:: send_header(keyword, value) - Stores the HTTP header to an internal buffer which will be written to the - output stream when :meth:`end_headers` method is invoked. - *keyword* should specify the header keyword, with *value* + Adds the HTTP header to an internal buffer which will be written to the + output stream when either :meth:`end_headers` or :meth:`flush_headers` + is invoked. *keyword* should specify the header keyword, with *value* specifying its value. .. versionchanged:: 3.2 Storing the headers in an internal buffer @@ -205,11 +206,19 @@ .. method:: end_headers() - Write the buffered HTTP headers to the output stream and send a blank - line, indicating the end of the HTTP headers in the response. + Adds a blank line + (indicating the end of the HTTP headers in the response) + to the headers buffer and calls :meth:`flush_headers()` .. versionchanged:: 3.2 Writing the buffered headers to the output stream. + .. method:: flush_headers() + + Finally send the headers to the output stream and flush the internal + headers buffer. + + .. versionadded:: 3.3 + .. method:: log_request(code='-', size='-') Logs an accepted (successful) request. *code* should specify the numeric diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -355,6 +355,7 @@ """ self.send_response_only(100) + self.flush_headers() return True def handle_one_request(self): @@ -432,7 +433,8 @@ self.wfile.write(content.encode('UTF-8', 'replace')) def send_response(self, code, message=None): - """Send the response header and log the response code. + """Add the response header to the headers buffer and log the + response code. Also send two standard headers with the server software version and the current date. @@ -451,11 +453,14 @@ else: message = '' if self.request_version != 'HTTP/0.9': - self.wfile.write(("%s %d %s\r\n" % - (self.protocol_version, code, message)).encode('latin-1', 'strict')) + if not hasattr(self, '_headers_buffer'): + self._headers_buffer = [] + self._headers_buffer.append(("%s %d %s\r\n" % + (self.protocol_version, code, message)).encode( + 'latin-1', 'strict')) def send_header(self, keyword, value): - """Send a MIME header.""" + """Send a MIME header to the headers buffer.""" if self.request_version != 'HTTP/0.9': if not hasattr(self, '_headers_buffer'): self._headers_buffer = [] @@ -472,6 +477,10 @@ """Send the blank line ending the MIME headers.""" if self.request_version != 'HTTP/0.9': self._headers_buffer.append(b"\r\n") + self.flush_headers() + + def flush_headers(self): + if hasattr(self, '_headers_buffer'): self.wfile.write(b"".join(self._headers_buffer)) self._headers_buffer = [] @@ -1081,6 +1090,7 @@ env.setdefault(k, "") self.send_response(200, "Script output follows") + self.flush_headers() decoded_query = query.replace('+', ' ') diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -461,6 +461,23 @@ self.send_error(417) return False + +class AuditableBytesIO: + + def __init__(self): + self.datas = [] + + def write(self, data): + self.datas.append(data) + + def getData(self): + return b''.join(self.datas) + + @property + def numWrites(self): + return len(self.datas) + + class BaseHTTPRequestHandlerTestCase(unittest.TestCase): """Test the functionality of the BaseHTTPServer. @@ -527,27 +544,49 @@ self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') - def test_header_buffering(self): - - def _readAndReseek(f): - pos = f.tell() - f.seek(0) - data = f.read() - f.seek(pos) - return data + def test_header_buffering_of_send_error(self): input = BytesIO(b'GET / HTTP/1.1\r\n\r\n') - output = BytesIO() - self.handler.rfile = input - self.handler.wfile = output - self.handler.request_version = 'HTTP/1.1' + output = AuditableBytesIO() + handler = SocketlessRequestHandler() + handler.rfile = input + handler.wfile = output + handler.request_version = 'HTTP/1.1' + handler.requestline = '' + handler.command = None - self.handler.send_header('Foo', 'foo') - self.handler.send_header('bar', 'bar') - self.assertEqual(_readAndReseek(output), b'') - self.handler.end_headers() - self.assertEqual(_readAndReseek(output), - b'Foo: foo\r\nbar: bar\r\n\r\n') + handler.send_error(418) + self.assertEqual(output.numWrites, 2) + + def test_header_buffering_of_send_response_only(self): + + input = BytesIO(b'GET / HTTP/1.1\r\n\r\n') + output = AuditableBytesIO() + handler = SocketlessRequestHandler() + handler.rfile = input + handler.wfile = output + handler.request_version = 'HTTP/1.1' + + handler.send_response_only(418) + self.assertEqual(output.numWrites, 0) + handler.end_headers() + self.assertEqual(output.numWrites, 1) + + def test_header_buffering_of_send_header(self): + + input = BytesIO(b'GET / HTTP/1.1\r\n\r\n') + output = AuditableBytesIO() + handler = SocketlessRequestHandler() + handler.rfile = input + handler.wfile = output + handler.request_version = 'HTTP/1.1' + + handler.send_header('Foo', 'foo') + handler.send_header('bar', 'bar') + self.assertEqual(output.numWrites, 0) + handler.end_headers() + self.assertEqual(output.getData(), b'Foo: foo\r\nbar: bar\r\n\r\n') + self.assertEqual(output.numWrites, 1) def test_header_unbuffered_when_continue(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -140,6 +140,10 @@ Library ------- +- Issue #3709: a flush_headers method to BaseHTTPRequestHandler which manages + the sending of headers to output stream and flushing the internal headers + buffer. Patch contribution by Andrew Schaaf + - Issue #11743: Rewrite multiprocessing connection classes in pure Python. - Issue #11164: Stop trying to use _xmlplus in the xml module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 17:42:46 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 17:42:46 +0200 Subject: [Python-checkins] cpython (2.7): Some more tests were incorrectly marked as C specific. Message-ID: http://hg.python.org/cpython/rev/dd088470f090 changeset: 69982:dd088470f090 branch: 2.7 parent: 69970:6c7984bae459 user: Ezio Melotti date: Mon May 09 18:32:18 2011 +0300 summary: Some more tests were incorrectly marked as C specific. files: Lib/test/test_heapq.py | 27 ++++++++++++++------------- 1 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -190,17 +190,8 @@ self.assertEqual(self.module.nlargest(n, data, key=f), sorted(data, key=f, reverse=True)[:n]) - -class TestHeapPython(TestHeap): - module = py_heapq - - - at skipUnless(c_heapq, 'requires _heapq') -class TestHeapC(TestHeap): - module = c_heapq - def test_comparison_operator(self): - # Issue 3501: Make sure heapq works with both __lt__ and __le__ + # Issue 3051: Make sure heapq works with both __lt__ and __le__ def hsort(data, comp): data = map(comp, data) self.module.heapify(data) @@ -221,6 +212,15 @@ self.assertEqual(hsort(data, LE), target) +class TestHeapPython(TestHeap): + module = py_heapq + + + at skipUnless(c_heapq, 'requires _heapq') +class TestHeapC(TestHeap): + module = c_heapq + + #============================================================================== class LenOnly: @@ -316,6 +316,7 @@ return chain(imap(lambda x:x, R(Ig(G(seqn))))) class TestErrorHandling(TestCase): + module = None def test_non_sequence(self): for f in (self.module.heapify, self.module.heappop): @@ -361,12 +362,12 @@ self.assertRaises(ZeroDivisionError, f, 2, E(s)) -class TestErrorHandling_Python(TestErrorHandling): +class TestErrorHandlingPython(TestErrorHandling): module = py_heapq @skipUnless(c_heapq, 'requires _heapq') -class TestErrorHandling_C(TestErrorHandling): +class TestErrorHandlingC(TestErrorHandling): module = c_heapq @@ -375,7 +376,7 @@ def test_main(verbose=None): test_classes = [TestModules, TestHeapPython, TestHeapC, - TestErrorHandling_Python, TestErrorHandling_C] + TestErrorHandlingPython, TestErrorHandlingC] test_support.run_unittest(*test_classes) # verify reference counting -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 17:42:47 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 17:42:47 +0200 Subject: [Python-checkins] cpython (3.1): Some more tests were incorrectly marked as C specific. Message-ID: http://hg.python.org/cpython/rev/4a3d5198a408 changeset: 69983:4a3d5198a408 branch: 3.1 parent: 69967:61798f076676 user: Ezio Melotti date: Mon May 09 18:36:53 2011 +0300 summary: Some more tests were incorrectly marked as C specific. files: Lib/test/test_heapq.py | 22 ++++++++++------------ 1 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -191,17 +191,8 @@ self.assertEqual(list(self.module.nlargest(n, data, key=f)), sorted(data, key=f, reverse=True)[:n]) - -class TestHeapPython(TestHeap): - module = py_heapq - - - at skipUnless(c_heapq, 'requires _heapq') -class TestHeapC(TestHeap): - module = c_heapq - def test_comparison_operator(self): - # Issue 3501: Make sure heapq works with both __lt__ + # Issue 3051: Make sure heapq works with both __lt__ # For python 3.0, __le__ alone is not enough def hsort(data, comp): data = [comp(x) for x in data] @@ -223,6 +214,15 @@ self.assertRaises(TypeError, data, LE) +class TestHeapPython(TestHeap): + module = py_heapq + + + at skipUnless(c_heapq, 'requires _heapq') +class TestHeapC(TestHeap): + module = c_heapq + + #============================================================================== class LenOnly: @@ -377,8 +377,6 @@ def test_main(verbose=None): - from types import BuiltinFunctionType - test_classes = [TestModules, TestHeapPython, TestHeapC, TestErrorHandling] support.run_unittest(*test_classes) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 17:42:48 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 17:42:48 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/ff82f912639c changeset: 69984:ff82f912639c branch: 3.2 parent: 69968:6e31b560f0f1 parent: 69983:4a3d5198a408 user: Ezio Melotti date: Mon May 09 18:40:42 2011 +0300 summary: Merge with 3.1. files: Lib/test/test_heapq.py | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -191,17 +191,8 @@ self.assertEqual(list(self.module.nlargest(n, data, key=f)), sorted(data, key=f, reverse=True)[:n]) - -class TestHeapPython(TestHeap): - module = py_heapq - - - at skipUnless(c_heapq, 'requires _heapq') -class TestHeapC(TestHeap): - module = c_heapq - def test_comparison_operator(self): - # Issue 3501: Make sure heapq works with both __lt__ + # Issue 3051: Make sure heapq works with both __lt__ # For python 3.0, __le__ alone is not enough def hsort(data, comp): data = [comp(x) for x in data] @@ -223,6 +214,15 @@ self.assertRaises(TypeError, data, LE) +class TestHeapPython(TestHeap): + module = py_heapq + + + at skipUnless(c_heapq, 'requires _heapq') +class TestHeapC(TestHeap): + module = c_heapq + + #============================================================================== class LenOnly: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 17:42:53 2011 From: python-checkins at python.org (ezio.melotti) Date: Mon, 09 May 2011 17:42:53 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/b6e625d7c19f changeset: 69985:b6e625d7c19f parent: 69981:25298224cb25 parent: 69984:ff82f912639c user: Ezio Melotti date: Mon May 09 18:42:32 2011 +0300 summary: Merge with 3.2. files: Lib/test/test_heapq.py | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -191,17 +191,8 @@ self.assertEqual(list(self.module.nlargest(n, data, key=f)), sorted(data, key=f, reverse=True)[:n]) - -class TestHeapPython(TestHeap): - module = py_heapq - - - at skipUnless(c_heapq, 'requires _heapq') -class TestHeapC(TestHeap): - module = c_heapq - def test_comparison_operator(self): - # Issue 3501: Make sure heapq works with both __lt__ + # Issue 3051: Make sure heapq works with both __lt__ # For python 3.0, __le__ alone is not enough def hsort(data, comp): data = [comp(x) for x in data] @@ -223,6 +214,15 @@ self.assertRaises(TypeError, data, LE) +class TestHeapPython(TestHeap): + module = py_heapq + + + at skipUnless(c_heapq, 'requires _heapq') +class TestHeapC(TestHeap): + module = c_heapq + + #============================================================================== class LenOnly: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 18:32:18 2011 From: python-checkins at python.org (vinay.sajip) Date: Mon, 09 May 2011 18:32:18 +0200 Subject: [Python-checkins] cpython: Improved Windows test coverage. Message-ID: http://hg.python.org/cpython/rev/05f3497c32c7 changeset: 69986:05f3497c32c7 user: Vinay Sajip date: Mon May 09 17:32:09 2011 +0100 summary: Improved Windows test coverage. files: Lib/test/test_logging.py | 40 +++++++++++++++++++++++++++- 1 files changed, 39 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -58,6 +58,15 @@ import threading except ImportError: threading = None +try: + import win32evtlog +except ImportError: + win32evtlog = None +try: + import win32evtlogutil +except ImportError: + win32evtlogutil = None + win32evtlog = None class BaseTest(unittest.TestCase): @@ -3565,6 +3574,35 @@ rh.close() setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover) + + at unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil required for this test.') +class NTEventLogHandlerTest(BaseTest): + def test_basic(self): + logtype = 'Application' + elh = win32evtlog.OpenEventLog(None, logtype) + num_recs = win32evtlog.GetNumberOfEventLogRecords(elh) + h = logging.handlers.NTEventLogHandler('test_logging') + r = logging.makeLogRecord({'msg': 'Test Log Message'}) + h.handle(r) + h.close() + # Now see if the event is recorded + self.assertTrue(num_recs < win32evtlog.GetNumberOfEventLogRecords(elh)) + flags = win32evtlog.EVENTLOG_BACKWARDS_READ | \ + win32evtlog.EVENTLOG_SEQUENTIAL_READ + found = False + GO_BACK = 100 + events = win32evtlog.ReadEventLog(elh, flags, GO_BACK) + for e in events: + if e.SourceName != 'test_logging': + continue + msg = win32evtlogutil.SafeFormatMessage(e, logtype) + if msg != 'Test Log Message\r\n': + continue + found = True + break + msg = 'Record not found in event log, went back %d records' % GO_BACK + self.assertTrue(found, msg=msg) + # Set the locale to the platform-dependent default. I have no idea # why the test does this, but in any case we save the current locale # first and restore it at the end. @@ -3580,7 +3618,7 @@ BasicConfigTest, LoggerAdapterTest, LoggerTest, SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest, LastResortTest, LogRecordTest, ExceptionTest, - SysLogHandlerTest, HTTPHandlerTest, + SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest, TimedRotatingFileHandlerTest ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 18:51:08 2011 From: python-checkins at python.org (lukasz.langa) Date: Mon, 09 May 2011 18:51:08 +0200 Subject: [Python-checkins] cpython (3.2): Closes #12036: ConfigParser: Document items() added the vars dictionary to the Message-ID: http://hg.python.org/cpython/rev/62e2b74c3bfc changeset: 69987:62e2b74c3bfc branch: 3.2 parent: 69984:ff82f912639c user: ?ukasz Langa date: Mon May 09 18:49:42 2011 +0200 summary: Closes #12036: ConfigParser: Document items() added the vars dictionary to the result files: Doc/library/configparser.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1064,6 +1064,11 @@ given *section*. Optional arguments have the same meaning as for the :meth:`get` method. + .. versionchanged:: 3.2 + + Items present in *vars* no longer appear in the result. The previous + behaviour mixed actual parser options with variables provided for + interpolation. .. method:: set(section, option, value) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 18:51:08 2011 From: python-checkins at python.org (lukasz.langa) Date: Mon, 09 May 2011 18:51:08 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged solution for #12036 from 3.2 Message-ID: http://hg.python.org/cpython/rev/2d984cc4afb0 changeset: 69988:2d984cc4afb0 parent: 69986:05f3497c32c7 parent: 69987:62e2b74c3bfc user: ?ukasz Langa date: Mon May 09 18:50:47 2011 +0200 summary: Merged solution for #12036 from 3.2 files: Doc/library/configparser.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1064,6 +1064,11 @@ given *section*. Optional arguments have the same meaning as for the :meth:`get` method. + .. versionchanged:: 3.2 + + Items present in *vars* no longer appear in the result. The previous + behaviour mixed actual parser options with variables provided for + interpolation. .. method:: set(section, option, value) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 20:55:08 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 09 May 2011 20:55:08 +0200 Subject: [Python-checkins] cpython: Remove dead code from _multiprocessing Message-ID: http://hg.python.org/cpython/rev/5dbc23e48fb0 changeset: 69989:5dbc23e48fb0 user: Antoine Pitrou date: Mon May 09 20:55:03 2011 +0200 summary: Remove dead code from _multiprocessing files: Modules/_multiprocessing/multiprocessing.c | 12 +-- Modules/_multiprocessing/multiprocessing.h | 45 ---------- Modules/_multiprocessing/semaphore.c | 4 +- 3 files changed, 3 insertions(+), 58 deletions(-) diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -16,7 +16,6 @@ PyObject *create_win32_namespace(void); -PyObject *pickle_dumps, *pickle_loads, *pickle_protocol; PyObject *ProcessError, *BufferTooShort; /* @@ -177,7 +176,7 @@ if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0) return NULL; - return Py_BuildValue("N" F_PY_SSIZE_T, + return Py_BuildValue("Nn", PyLong_FromVoidPtr(buffer), buffer_len); } @@ -231,15 +230,6 @@ if (!module) return NULL; - /* Get copy of objects from pickle */ - temp = PyImport_ImportModule(PICKLE_MODULE); - if (!temp) - return NULL; - pickle_dumps = PyObject_GetAttrString(temp, "dumps"); - pickle_loads = PyObject_GetAttrString(temp, "loads"); - pickle_protocol = PyObject_GetAttrString(temp, "HIGHEST_PROTOCOL"); - Py_XDECREF(temp); - /* Get copy of BufferTooShort */ temp = PyImport_ImportModule("multiprocessing"); if (!temp) diff --git a/Modules/_multiprocessing/multiprocessing.h b/Modules/_multiprocessing/multiprocessing.h --- a/Modules/_multiprocessing/multiprocessing.h +++ b/Modules/_multiprocessing/multiprocessing.h @@ -64,20 +64,6 @@ /* - * Make sure Py_ssize_t available - */ - -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) - typedef int Py_ssize_t; -# define PY_SSIZE_T_MAX INT_MAX -# define PY_SSIZE_T_MIN INT_MIN -# define F_PY_SSIZE_T "i" -# define PyInt_FromSsize_t(n) PyInt_FromLong((long)n) -#else -# define F_PY_SSIZE_T "n" -#endif - -/* * Format codes */ @@ -105,12 +91,6 @@ # define T_SEM_HANDLE T_POINTER #endif -#if PY_VERSION_HEX >= 0x03000000 -# define F_RBUFFER "y" -#else -# define F_RBUFFER "s" -#endif - /* * Error codes which can be returned by functions called without GIL */ @@ -127,37 +107,12 @@ * Externs - not all will really exist on all platforms */ -extern PyObject *pickle_dumps; -extern PyObject *pickle_loads; -extern PyObject *pickle_protocol; extern PyObject *BufferTooShort; extern PyTypeObject SemLockType; extern PyTypeObject PipeConnectionType; extern HANDLE sigint_event; /* - * Py3k compatibility - */ - -#if PY_VERSION_HEX >= 0x03000000 -# define PICKLE_MODULE "pickle" -# define FROM_FORMAT PyUnicode_FromFormat -# define PyInt_FromLong PyLong_FromLong -# define PyInt_FromSsize_t PyLong_FromSsize_t -#else -# define PICKLE_MODULE "cPickle" -# define FROM_FORMAT PyString_FromFormat -#endif - -#ifndef PyVarObject_HEAD_INIT -# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, -#endif - -#ifndef Py_TPFLAGS_HAVE_WEAKREFS -# define Py_TPFLAGS_HAVE_WEAKREFS 0 -#endif - -/* * Miscellaneous */ diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c --- a/Modules/_multiprocessing/semaphore.c +++ b/Modules/_multiprocessing/semaphore.c @@ -481,7 +481,7 @@ static PyObject * semlock_count(SemLockObject *self) { - return PyInt_FromLong((long)self->count); + return PyLong_FromLong((long)self->count); } static PyObject * @@ -505,7 +505,7 @@ the number of waiting threads */ if (sval < 0) sval = 0; - return PyInt_FromLong((long)sval); + return PyLong_FromLong((long)sval); #endif } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 21:00:47 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 09 May 2011 21:00:47 +0200 Subject: [Python-checkins] cpython: os.dup()-then-close() can be replaced with detach() Message-ID: http://hg.python.org/cpython/rev/ac4b7b1a442e changeset: 69990:ac4b7b1a442e user: Antoine Pitrou date: Mon May 09 21:00:28 2011 +0200 summary: os.dup()-then-close() can be replaced with detach() files: Lib/multiprocessing/connection.py | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -469,10 +469,8 @@ ''' if duplex: s1, s2 = socket.socketpair() - c1 = Connection(os.dup(s1.fileno())) - c2 = Connection(os.dup(s2.fileno())) - s1.close() - s2.close() + c1 = Connection(s1.detach()) + c2 = Connection(s2.detach()) else: fd1, fd2 = os.pipe() c1 = Connection(fd1, writable=False) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 21:17:25 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 09 May 2011 21:17:25 +0200 Subject: [Python-checkins] cpython: Issue #12041: Make test_wait3 more robust. Message-ID: http://hg.python.org/cpython/rev/9e473917cbfb changeset: 69991:9e473917cbfb user: Antoine Pitrou date: Mon May 09 21:17:02 2011 +0200 summary: Issue #12041: Make test_wait3 more robust. files: Lib/test/fork_wait.py | 10 ++++++---- Lib/test/test_wait3.py | 7 +++++-- Misc/NEWS | 2 ++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Lib/test/fork_wait.py b/Lib/test/fork_wait.py --- a/Lib/test/fork_wait.py +++ b/Lib/test/fork_wait.py @@ -43,6 +43,7 @@ self.assertEqual(spid, cpid) self.assertEqual(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8)) + @support.reap_threads def test_wait(self): for i in range(NUM_THREADS): _thread.start_new(self.f, (i,)) @@ -69,7 +70,8 @@ os._exit(n) else: # Parent - self.wait_impl(cpid) - # Tell threads to die - self.stop = 1 - time.sleep(2*SHORTSLEEP) # Wait for threads to die + try: + self.wait_impl(cpid) + finally: + # Tell threads to die + self.stop = 1 diff --git a/Lib/test/test_wait3.py b/Lib/test/test_wait3.py --- a/Lib/test/test_wait3.py +++ b/Lib/test/test_wait3.py @@ -19,13 +19,16 @@ class Wait3Test(ForkWait): def wait_impl(self, cpid): - for i in range(10): + # This many iterations can be required, since some previously run + # tests (e.g. test_ctypes) could have spawned a lot of children + # very quickly. + for i in range(30): # wait3() shouldn't hang, but some of the buildbots seem to hang # in the forking tests. This is an attempt to fix the problem. spid, status, rusage = os.wait3(os.WNOHANG) if spid == cpid: break - time.sleep(1.0) + time.sleep(0.1) self.assertEqual(spid, cpid) self.assertEqual(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -619,6 +619,8 @@ Tests ----- +- Issue #12041: Make test_wait3 more robust. + - Issue #11873: Change regex in test_compileall to fix occasional failures when when the randomly generated temporary path happened to match the regex. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 9 23:05:59 2011 From: python-checkins at python.org (vinay.sajip) Date: Mon, 09 May 2011 23:05:59 +0200 Subject: [Python-checkins] cpython: Update incorrect comment. Message-ID: http://hg.python.org/cpython/rev/2d4ef202d4ed changeset: 69992:2d4ef202d4ed user: Vinay Sajip date: Mon May 09 22:05:50 2011 +0100 summary: Update incorrect comment. files: Lib/test/test_logging.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1485,7 +1485,7 @@ self.handled.set() def test_output(self): - # The log message sent to the SysLogHandler is properly received. + # The log message sent to the HTTPHandler is properly received. logger = logging.getLogger("http") for method in ('GET', 'POST'): self.h_hdlr.method = method -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 00:21:49 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 00:21:49 +0200 Subject: [Python-checkins] cpython (3.1): Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, Message-ID: http://hg.python.org/cpython/rev/fa3227c3cf87 changeset: 69993:fa3227c3cf87 branch: 3.1 parent: 69983:4a3d5198a408 user: Victor Stinner date: Tue May 10 00:19:53 2011 +0200 summary: Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, clear the end-of-file indicator after CTRL+d. files: Misc/NEWS | 3 +++ Parser/myreadline.c | 1 + 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, + clear the end-of-file indicator after CTRL+d. + - Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. Fix a crash if a class override its __class__ attribute (e.g. a proxy of the diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -73,6 +73,7 @@ } #endif /* MS_WINDOWS */ if (feof(fp)) { + clearerr(fp); return -1; /* EOF */ } #ifdef EINTR -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 00:21:52 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 00:21:52 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, clear Message-ID: http://hg.python.org/cpython/rev/b5914bfb4d04 changeset: 69994:b5914bfb4d04 branch: 3.2 parent: 69987:62e2b74c3bfc parent: 69993:fa3227c3cf87 user: Victor Stinner date: Tue May 10 00:20:35 2011 +0200 summary: Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, clear the end-of-file indicator after CTRL+d. files: Misc/NEWS | 3 +++ Parser/myreadline.c | 1 + 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, + clear the end-of-file indicator after CTRL+d. + - Issue #1856: Avoid crashes and lockups when daemon threads run while the interpreter is shutting down; instead, these threads are now killed when they try to take the GIL. diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -73,6 +73,7 @@ } #endif /* MS_WINDOWS */ if (feof(fp)) { + clearerr(fp); return -1; /* EOF */ } #ifdef EINTR -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 00:21:53 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 00:21:53 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #1195: Fix input() if it is interrupted by CTRL+d and then Message-ID: http://hg.python.org/cpython/rev/3ff5d28ab630 changeset: 69995:3ff5d28ab630 parent: 69992:2d4ef202d4ed parent: 69994:b5914bfb4d04 user: Victor Stinner date: Tue May 10 00:21:26 2011 +0200 summary: (Merge 3.2) Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, clear the end-of-file indicator after CTRL+d. files: Misc/NEWS | 3 +++ Parser/myreadline.c | 1 + 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, + clear the end-of-file indicator after CTRL+d. + - Issue #1856: Avoid crashes and lockups when daemon threads run while the interpreter is shutting down; instead, these threads are now killed when they try to take the GIL. diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -73,6 +73,7 @@ } #endif /* MS_WINDOWS */ if (feof(fp)) { + clearerr(fp); return -1; /* EOF */ } #ifdef EINTR -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 00:23:28 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 00:23:28 +0200 Subject: [Python-checkins] cpython (2.7): (Merge 3.1) Issue #1195: Fix input() if it is interrupted by CTRL+d and then Message-ID: http://hg.python.org/cpython/rev/c9f07c69b138 changeset: 69996:c9f07c69b138 branch: 2.7 parent: 69982:dd088470f090 user: Victor Stinner date: Tue May 10 00:22:59 2011 +0200 summary: (Merge 3.1) Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, clear the end-of-file indicator after CTRL+d. files: Misc/NEWS | 3 +++ Parser/myreadline.c | 1 + 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, + clear the end-of-file indicator after CTRL+d. + - 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). diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -77,6 +77,7 @@ } #endif /* MS_WINDOWS */ if (feof(fp)) { + clearerr(fp); return -1; /* EOF */ } #ifdef EINTR -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 00:50:06 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 00:50:06 +0200 Subject: [Python-checkins] cpython (3.1): Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional Message-ID: http://hg.python.org/cpython/rev/b7abf0590e1c changeset: 69997:b7abf0590e1c branch: 3.1 parent: 69993:fa3227c3cf87 user: Victor Stinner date: Tue May 10 00:38:00 2011 +0200 summary: Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional OpenSSL is now compiled with OPENSSL_NO_SSL2 defined (without the SSLv2 protocol) on Debian: fix the ssl module on Debian Testing and Debian Sid. Optimize also ssl.get_protocol_name(): speed does matter! files: Doc/library/ssl.rst | 3 +++ Lib/ssl.py | 25 +++++++++++++------------ Lib/test/test_ssl.py | 26 +++++++++++++++----------- Misc/NEWS | 2 ++ Modules/_ssl.c | 8 +++++++- 5 files changed, 40 insertions(+), 24 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -219,6 +219,9 @@ Selects SSL version 2 as the channel encryption protocol. + This protocol is not available if OpenSSL is compiled with OPENSSL_NO_SSL2 + flag. + .. warning:: SSL version 2 is insecure. Its use is highly discouraged. diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -60,8 +60,6 @@ from _ssl import SSLError from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED -from _ssl import (PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, - PROTOCOL_TLSv1) from _ssl import RAND_status, RAND_egd, RAND_add from _ssl import ( SSL_ERROR_ZERO_RETURN, @@ -74,6 +72,18 @@ SSL_ERROR_EOF, SSL_ERROR_INVALID_ERROR_CODE, ) +from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 +_PROTOCOL_NAMES = { + PROTOCOL_TLSv1: "TLSv1", + PROTOCOL_SSLv23: "SSLv23", + PROTOCOL_SSLv3: "SSLv3", +} +try: + from _ssl import PROTOCOL_SSLv2 +except ImportError: + pass +else: + _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2" from socket import getnameinfo as _getnameinfo from socket import error as socket_error @@ -427,13 +437,4 @@ return DER_cert_to_PEM_cert(dercert) def get_protocol_name(protocol_code): - if protocol_code == PROTOCOL_TLSv1: - return "TLSv1" - elif protocol_code == PROTOCOL_SSLv23: - return "SSLv23" - elif protocol_code == PROTOCOL_SSLv2: - return "SSLv2" - elif protocol_code == PROTOCOL_SSLv3: - return "SSLv3" - else: - return "" + return _PROTOCOL_NAMES.get(protocol_code, '') diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -40,7 +40,7 @@ class BasicTests(unittest.TestCase): def test_constants(self): - ssl.PROTOCOL_SSLv2 + #ssl.PROTOCOL_SSLv2 ssl.PROTOCOL_SSLv23 ssl.PROTOCOL_SSLv3 ssl.PROTOCOL_TLSv1 @@ -838,6 +838,7 @@ finally: t.join() + @unittest.skipUnless(hasattr(ssl, 'PROTOCOL_SSLv2'), "need SSLv2") def test_protocol_sslv2(self): """Connecting to an SSLv2 server with various client options""" if support.verbose: @@ -857,14 +858,15 @@ sys.stdout.write("\ntest_protocol_sslv23 disabled, " "as it fails on OpenSSL 1.0.0+") return - try: - try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True) - except (ssl.SSLError, socket.error) as x: - # this fails on some older versions of OpenSSL (0.9.7l, for instance) - if support.verbose: - sys.stdout.write( - " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" - % str(x)) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try: + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True) + except (ssl.SSLError, socket.error) as x: + # this fails on some older versions of OpenSSL (0.9.7l, for instance) + if support.verbose: + sys.stdout.write( + " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" + % str(x)) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True) @@ -886,7 +888,8 @@ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False) @@ -899,7 +902,8 @@ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,8 @@ Library ------- +- Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. + - Issue #11164: Stop trying to use _xmlplus in the xml module. - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -63,8 +63,10 @@ }; enum py_ssl_version { +#ifndef OPENSSL_NO_SSL2 PY_SSL_VERSION_SSL2, - PY_SSL_VERSION_SSL3, +#endif + PY_SSL_VERSION_SSL3=1, PY_SSL_VERSION_SSL23, PY_SSL_VERSION_TLS1 }; @@ -306,8 +308,10 @@ self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */ else if (proto_version == PY_SSL_VERSION_SSL3) self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */ +#ifndef OPENSSL_NO_SSL2 else if (proto_version == PY_SSL_VERSION_SSL2) self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */ +#endif else if (proto_version == PY_SSL_VERSION_SSL23) self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ PySSL_END_ALLOW_THREADS @@ -1787,8 +1791,10 @@ PY_SSL_CERT_REQUIRED); /* protocol versions */ +#ifndef OPENSSL_NO_SSL2 PyModule_AddIntConstant(m, "PROTOCOL_SSLv2", PY_SSL_VERSION_SSL2); +#endif PyModule_AddIntConstant(m, "PROTOCOL_SSLv3", PY_SSL_VERSION_SSL3); PyModule_AddIntConstant(m, "PROTOCOL_SSLv23", -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 00:50:09 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 00:50:09 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (Merge 3.1) Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional Message-ID: http://hg.python.org/cpython/rev/20beec22764f changeset: 69998:20beec22764f branch: 3.2 parent: 69994:b5914bfb4d04 parent: 69997:b7abf0590e1c user: Victor Stinner date: Tue May 10 00:48:41 2011 +0200 summary: (Merge 3.1) Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional OpenSSL is now compiled with OPENSSL_NO_SSL2 defined (without the SSLv2 protocol) on Debian: fix the ssl module on Debian Testing and Debian Sid. Optimize also ssl.get_protocol_name(): speed does matter! files: Doc/library/ssl.rst | 3 + Lib/ssl.py | 25 +++++++------ Lib/test/test_ssl.py | 56 ++++++++++++++++++------------- Misc/NEWS | 2 + Modules/_ssl.c | 8 ++++- 5 files changed, 58 insertions(+), 36 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -289,6 +289,9 @@ Selects SSL version 2 as the channel encryption protocol. + This protocol is not available if OpenSSL is compiled with OPENSSL_NO_SSL2 + flag. + .. warning:: SSL version 2 is insecure. Its use is highly discouraged. diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -62,8 +62,6 @@ from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION from _ssl import _SSLContext, SSLError from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED -from _ssl import (PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, - PROTOCOL_TLSv1) from _ssl import OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1 from _ssl import RAND_status, RAND_egd, RAND_add from _ssl import ( @@ -78,6 +76,18 @@ SSL_ERROR_INVALID_ERROR_CODE, ) from _ssl import HAS_SNI +from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 +_PROTOCOL_NAMES = { + PROTOCOL_TLSv1: "TLSv1", + PROTOCOL_SSLv23: "SSLv23", + PROTOCOL_SSLv3: "SSLv3", +} +try: + from _ssl import PROTOCOL_SSLv2 +except ImportError: + pass +else: + _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2" from socket import getnameinfo as _getnameinfo from socket import error as socket_error @@ -552,13 +562,4 @@ return DER_cert_to_PEM_cert(dercert) def get_protocol_name(protocol_code): - if protocol_code == PROTOCOL_TLSv1: - return "TLSv1" - elif protocol_code == PROTOCOL_SSLv23: - return "SSLv23" - elif protocol_code == PROTOCOL_SSLv2: - return "SSLv2" - elif protocol_code == PROTOCOL_SSLv3: - return "SSLv3" - else: - return "" + return _PROTOCOL_NAMES.get(protocol_code, '') diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -21,9 +21,11 @@ ssl = support.import_module("ssl") PROTOCOLS = [ - ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, + ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1 ] +if hasattr(ssl, 'PROTOCOL_SSLv2'): + PROTOCOLS.append(ssl.PROTOCOL_SSLv2) HOST = support.HOST @@ -67,22 +69,25 @@ # Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2 def skip_if_broken_ubuntu_ssl(func): - @functools.wraps(func) - def f(*args, **kwargs): - try: - ssl.SSLContext(ssl.PROTOCOL_SSLv2) - except ssl.SSLError: - if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and - platform.linux_distribution() == ('debian', 'squeeze/sid', '')): - raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour") - return func(*args, **kwargs) - return f + if hasattr(ssl, 'PROTOCOL_SSLv2'): + @functools.wraps(func) + def f(*args, **kwargs): + try: + ssl.SSLContext(ssl.PROTOCOL_SSLv2) + except ssl.SSLError: + if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and + platform.linux_distribution() == ('debian', 'squeeze/sid', '')): + raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour") + return func(*args, **kwargs) + return f + else: + return func class BasicSocketTests(unittest.TestCase): def test_constants(self): - ssl.PROTOCOL_SSLv2 + #ssl.PROTOCOL_SSLv2 ssl.PROTOCOL_SSLv23 ssl.PROTOCOL_SSLv3 ssl.PROTOCOL_TLSv1 @@ -310,7 +315,8 @@ @skip_if_broken_ubuntu_ssl def test_constructor(self): - ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv2) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv2) ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv3) ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) @@ -1199,6 +1205,7 @@ t.join() @skip_if_broken_ubuntu_ssl + @unittest.skipUnless(hasattr(ssl, 'PROTOCOL_SSLv2'), "need SSLv2") def test_protocol_sslv2(self): """Connecting to an SSLv2 server with various client options""" if support.verbose: @@ -1224,14 +1231,15 @@ """Connecting to an SSLv23 server with various client options""" if support.verbose: sys.stdout.write("\n") - try: - try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True) - except (ssl.SSLError, socket.error) as x: - # this fails on some older versions of OpenSSL (0.9.7l, for instance) - if support.verbose: - sys.stdout.write( - " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" - % str(x)) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try: + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True) + except (ssl.SSLError, socket.error) as x: + # this fails on some older versions of OpenSSL (0.9.7l, for instance) + if support.verbose: + sys.stdout.write( + " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" + % str(x)) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True) @@ -1262,7 +1270,8 @@ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False) if no_sslv2_implies_sslv3_hello(): @@ -1278,7 +1287,8 @@ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -618,6 +618,8 @@ Library ------- +- Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. + - Issue #10916: mmap should not segfault when a file is mapped using 0 as length and a non-zero offset, and an attempt to read past the end of file is made (IndexError is raised instead). Patch by Ross Lagerwall. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -63,8 +63,10 @@ }; enum py_ssl_version { +#ifndef OPENSSL_NO_SSL2 PY_SSL_VERSION_SSL2, - PY_SSL_VERSION_SSL3, +#endif + PY_SSL_VERSION_SSL3=1, PY_SSL_VERSION_SSL23, PY_SSL_VERSION_TLS1 }; @@ -1450,8 +1452,10 @@ ctx = SSL_CTX_new(TLSv1_method()); else if (proto_version == PY_SSL_VERSION_SSL3) ctx = SSL_CTX_new(SSLv3_method()); +#ifndef OPENSSL_NO_SSL2 else if (proto_version == PY_SSL_VERSION_SSL2) ctx = SSL_CTX_new(SSLv2_method()); +#endif else if (proto_version == PY_SSL_VERSION_SSL23) ctx = SSL_CTX_new(SSLv23_method()); else @@ -2110,8 +2114,10 @@ PY_SSL_CERT_REQUIRED); /* protocol versions */ +#ifndef OPENSSL_NO_SSL2 PyModule_AddIntConstant(m, "PROTOCOL_SSLv2", PY_SSL_VERSION_SSL2); +#endif PyModule_AddIntConstant(m, "PROTOCOL_SSLv3", PY_SSL_VERSION_SSL3); PyModule_AddIntConstant(m, "PROTOCOL_SSLv23", -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 00:50:10 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 00:50:10 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Empty merge, the fix was already applied to 3.3 Message-ID: http://hg.python.org/cpython/rev/79f862ec8d5c changeset: 69999:79f862ec8d5c parent: 69995:3ff5d28ab630 parent: 69998:20beec22764f user: Victor Stinner date: Tue May 10 00:49:53 2011 +0200 summary: (Merge 3.2) Empty merge, the fix was already applied to 3.3 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 01:30:10 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 01:30:10 +0200 Subject: [Python-checkins] cpython: faulthandler: improve_sigabrt() on Visual Studio Message-ID: http://hg.python.org/cpython/rev/0b8c7cf25d10 changeset: 70000:0b8c7cf25d10 user: Victor Stinner date: Tue May 10 01:30:03 2011 +0200 summary: faulthandler: improve_sigabrt() on Visual Studio Use _set_abort_behavior() + abort() instead of raise(SIGABRT) which may write an error message and/or open a popup asking to report the fault. files: Modules/faulthandler.c | 12 +++++------- 1 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -816,14 +816,12 @@ static PyObject * faulthandler_sigabrt(PyObject *self, PyObject *args) { -#if _MSC_VER - /* If Python is compiled in debug mode with Visual Studio, abort() opens - a popup asking the user how to handle the assertion. Use raise(SIGABRT) - instead. */ - raise(SIGABRT); -#else +#ifdef _MSC_VER + /* Visual Studio: configure abort() to not display an error message nor + open a popup asking to report the fault. */ + _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); +#endif abort(); -#endif Py_RETURN_NONE; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 01:52:28 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 01:52:28 +0200 Subject: [Python-checkins] cpython (2.7): (Merge 3.1) Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional Message-ID: http://hg.python.org/cpython/rev/3c87a13980be changeset: 70001:3c87a13980be branch: 2.7 parent: 69996:c9f07c69b138 user: Victor Stinner date: Tue May 10 01:52:03 2011 +0200 summary: (Merge 3.1) Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional OpenSSL is now compiled with OPENSSL_NO_SSL2 defined (without the SSLv2 protocol) on Debian: fix the ssl module on Debian Testing and Debian Sid. Optimize also ssl.get_protocol_name(): speed does matter! files: Doc/library/ssl.rst | 3 + Lib/ssl.py | 24 ++++++++------- Lib/test/test_ssl.py | 49 +++++++++++++++++-------------- Misc/NEWS | 2 + Modules/_ssl.c | 8 ++++- 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -237,6 +237,9 @@ Selects SSL version 2 as the channel encryption protocol. + This protocol is not available if OpenSSL is compiled with OPENSSL_NO_SSL2 + flag. + .. warning:: SSL version 2 is insecure. Its use is highly discouraged. diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -62,7 +62,6 @@ from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION from _ssl import SSLError from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED -from _ssl import PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 from _ssl import RAND_status, RAND_egd, RAND_add from _ssl import \ SSL_ERROR_ZERO_RETURN, \ @@ -74,6 +73,18 @@ SSL_ERROR_WANT_CONNECT, \ SSL_ERROR_EOF, \ SSL_ERROR_INVALID_ERROR_CODE +from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 +_PROTOCOL_NAMES = { + PROTOCOL_TLSv1: "TLSv1", + PROTOCOL_SSLv23: "SSLv23", + PROTOCOL_SSLv3: "SSLv3", +} +try: + from _ssl import PROTOCOL_SSLv2 +except ImportError: + pass +else: + _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2" from socket import socket, _fileobject, _delegate_methods, error as socket_error from socket import getnameinfo as _getnameinfo @@ -425,16 +436,7 @@ return DER_cert_to_PEM_cert(dercert) def get_protocol_name(protocol_code): - if protocol_code == PROTOCOL_TLSv1: - return "TLSv1" - elif protocol_code == PROTOCOL_SSLv23: - return "SSLv23" - elif protocol_code == PROTOCOL_SSLv2: - return "SSLv2" - elif protocol_code == PROTOCOL_SSLv3: - return "SSLv3" - else: - return "" + return _PROTOCOL_NAMES.get(protocol_code, '') # a replacement for the old socket.ssl function diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -58,32 +58,35 @@ # Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2 def skip_if_broken_ubuntu_ssl(func): - # We need to access the lower-level wrapper in order to create an - # implicit SSL context without trying to connect or listen. - try: - import _ssl - except ImportError: - # The returned function won't get executed, just ignore the error - pass - @functools.wraps(func) - def f(*args, **kwargs): + if hasattr(ssl, 'PROTOCOL_SSLv2'): + # We need to access the lower-level wrapper in order to create an + # implicit SSL context without trying to connect or listen. try: - s = socket.socket(socket.AF_INET) - _ssl.sslwrap(s._sock, 0, None, None, - ssl.CERT_NONE, ssl.PROTOCOL_SSLv2, None, None) - except ssl.SSLError as e: - if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and - platform.linux_distribution() == ('debian', 'squeeze/sid', '') - and 'Invalid SSL protocol variant specified' in str(e)): - raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour") - return func(*args, **kwargs) - return f + import _ssl + except ImportError: + # The returned function won't get executed, just ignore the error + pass + @functools.wraps(func) + def f(*args, **kwargs): + try: + s = socket.socket(socket.AF_INET) + _ssl.sslwrap(s._sock, 0, None, None, + ssl.CERT_NONE, ssl.PROTOCOL_SSLv2, None, None) + except ssl.SSLError as e: + if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and + platform.linux_distribution() == ('debian', 'squeeze/sid', '') + and 'Invalid SSL protocol variant specified' in str(e)): + raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour") + return func(*args, **kwargs) + return f + else: + return func class BasicSocketTests(unittest.TestCase): def test_constants(self): - ssl.PROTOCOL_SSLv2 + #ssl.PROTOCOL_SSLv2 ssl.PROTOCOL_SSLv23 ssl.PROTOCOL_SSLv3 ssl.PROTOCOL_TLSv1 @@ -1008,7 +1011,8 @@ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False) @@ -1020,7 +1024,8 @@ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,8 @@ Library ------- +- Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. + - Issue #11164: Remove obsolete allnodes test from minidom test. - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -62,8 +62,10 @@ }; enum py_ssl_version { +#ifndef OPENSSL_NO_SSL2 PY_SSL_VERSION_SSL2, - PY_SSL_VERSION_SSL3, +#endif + PY_SSL_VERSION_SSL3=1, PY_SSL_VERSION_SSL23, PY_SSL_VERSION_TLS1 }; @@ -302,8 +304,10 @@ self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */ else if (proto_version == PY_SSL_VERSION_SSL3) self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */ +#ifndef OPENSSL_NO_SSL2 else if (proto_version == PY_SSL_VERSION_SSL2) self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */ +#endif else if (proto_version == PY_SSL_VERSION_SSL23) self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ PySSL_END_ALLOW_THREADS @@ -1708,8 +1712,10 @@ PY_SSL_CERT_REQUIRED); /* protocol versions */ +#ifndef OPENSSL_NO_SSL2 PyModule_AddIntConstant(m, "PROTOCOL_SSLv2", PY_SSL_VERSION_SSL2); +#endif PyModule_AddIntConstant(m, "PROTOCOL_SSLv3", PY_SSL_VERSION_SSL3); PyModule_AddIntConstant(m, "PROTOCOL_SSLv23", -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue May 10 04:59:43 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 10 May 2011 04:59:43 +0200 Subject: [Python-checkins] Daily reference leaks (0b8c7cf25d10): sum=0 Message-ID: results for 0b8c7cf25d10 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogb8zmtP', '-x'] From python-checkins at python.org Tue May 10 08:48:38 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 10 May 2011 08:48:38 +0200 Subject: [Python-checkins] cpython: Issue #12039: Now suppress spurious select.error raised on FreeBSD when the Message-ID: http://hg.python.org/cpython/rev/b365036b17c2 changeset: 70002:b365036b17c2 parent: 70000:0b8c7cf25d10 user: Vinay Sajip date: Tue May 10 07:48:28 2011 +0100 summary: Issue #12039: Now suppress spurious select.error raised on FreeBSD when the server (an asyncore.dispatcher) is closed. files: Lib/test/test_logging.py | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -723,7 +723,14 @@ :func:`select` or :func:`poll` call by :func:`asyncore.loop`. """ - asyncore.loop(poll_interval, map=self.sockmap) + try: + asyncore.loop(poll_interval, map=self.sockmap) + except select.error: + # On FreeBSD 8, closing the server repeatably + # raises this error. We swallow it if the + # server has been closed. + if self.connected or self.accepting: + raise def stop(self, timeout=None): """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 09:36:44 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 10 May 2011 09:36:44 +0200 Subject: [Python-checkins] cpython (3.2): Issue 12047: Expand the style guide. Message-ID: http://hg.python.org/cpython/rev/d5d91b14b238 changeset: 70003:d5d91b14b238 branch: 3.2 parent: 69998:20beec22764f user: Raymond Hettinger date: Tue May 10 00:35:03 2011 -0700 summary: Issue 12047: Expand the style guide. files: Doc/documenting/style.rst | 104 ++++++++++++++++++++++++++ 1 files changed, 104 insertions(+), 0 deletions(-) diff --git a/Doc/documenting/style.rst b/Doc/documenting/style.rst --- a/Doc/documenting/style.rst +++ b/Doc/documenting/style.rst @@ -108,6 +108,110 @@ The name of the operating system developed at AT&T Bell Labs in the early 1970s. +Affirmative Tone +---------------- + +The documentation focuses on affirmatively stating what the language does and +how to use it effectively. + +Except for certain security risks or segfault risks, the docs should avoid +wording along the lines of "feature x is dangerous" or "experts only". These +kinds of value judgments belong in external blogs and wikis, not in the core +documentation. + +Bad example (creating worry in the mind of a reader): + + Warning: failing to explicitly close a file could result in lost data or + excessive resource consumption. Never rely on reference counting to + automatically close a file. + +Good example (establishing confident knowledge in the effective use of the language): + + A best practice for using files is use a try/finally pair to explicitly + close a file after it is used. Alternatively, using a with-statement can + achieve the same effect. This assures that files are flushed and file + descriptor resources are released in a timely manner. + +Economy of Expression +--------------------- + +More documentation is not necessarily better documentation. Error on the side +of being succinct. + +It is an unfortunate fact that making documentation longer can be an impediment +to understanding and can result in even more ways to misread or misinterpret the +text. Long descriptions full of corner cases and caveats can create the +impression that a function is more complex or harder to use than it actually is. + +The documentation for :func:`super` is an example of where a good deal of +information was condensed into a few short paragraphs. Discussion of +:func:`super` could have filled a chapter in a book, but it is often easier to +grasp a terse description than a lengthy narrative. + + +Code Examples +------------- + +Short code examples can be a useful adjunct to understanding. Readers can often +grasp a simple example more quickly than they can digest a formal description in +prose. + +People learn faster with concrete, motivating examples that match the context of +a typical use case. For instance, the :func:`str.rpartition` method is better +demonstrated with an example splitting the domain from a URL than it would be +with an example of removing the last word from a line of Monty Python dialog. + +The ellipsis for the :attr:`sys.ps2` secondary interpreter prompt should only be +used sparingly, where it is necessary to clearly differentiate between input +lines and output lines. Besides contributing visual clutter, it makes it +difficult for readers to cut-and-paste examples so they can experiment with +variations. + +Code Equivalents +---------------- + +Giving pure Python code equivalents (or approximate equivalents) can be a useful +adjunct to a prose description. A documenter should carefully weigh whether the +code equivalent adds value. + +A good example is the code equivalent for :func:`all`. The short 4-line code +equivalent is easily digested; it re-emphasizes the early-out behavior; and it +clarifies the handling of the corner-case where the iterable is empty. In +addition, it serves as a model for people wanting to implement a commonly +requested alternative where :func:`all` would return the specific object +evaluating to False whenever the function terminates early. + +A more questionable example is the code for :func:`itertools.groupby`. Its code +equivalent borders on being too complex to be a quick aid to understanding. +Despite its complexity, the code equivalent was kept because it serves as a +model to alternative implementations and because the operation of the "grouper" +is more easily shown in code than in English prose. + +An example of when not to use a code equivalent is for the :func:`oct` function. +The exact steps in converting a number to octal doesn't add value for a user +trying to learn what the function does. + +Audience +-------- + +The tone of the tutorial (and all the docs) needs to be respectful of the +reader's intelligence. Don't presume that the readers are stupid. Lay out the +relevant information, show motivating use cases, provide glossary links, and do +our best to connect-the-dots, but don't talk down to them or waste their time. + +The tutorial is meant for newcomers, many of whom will be using the tutorial to +evaluate the language as a whole. The experience needs to be positive and not +leave the reader with worries that something bad will happen if they make a +misstep. The tutorial serves as guide for intelligent and curious readers, +saving details for the how-to guides and other sources. + +Be careful accepting requests for documentation changes from the rare but vocal +category of reader who is looking for vindication for one of their programming +errors ("I made a mistake, therefore the docs must be wrong ..."). Typically, +the documentation wasn't consulted until after the error was made. It is +unfortunate, but typically no documentation edit would have saved the user from +making false assumptions about the language ("I was surprised by ..."). + .. _Apple Publications Style Guide: http://developer.apple.com/mac/library/documentation/UserExperience/Conceptual/APStyleGuide/APSG_2009.pdf -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 09:36:45 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 10 May 2011 09:36:45 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): merge Message-ID: http://hg.python.org/cpython/rev/5a3140f30740 changeset: 70004:5a3140f30740 parent: 70000:0b8c7cf25d10 parent: 70003:d5d91b14b238 user: Raymond Hettinger date: Tue May 10 00:35:48 2011 -0700 summary: merge files: Doc/documenting/style.rst | 104 ++++++++++++++++++++++++++ 1 files changed, 104 insertions(+), 0 deletions(-) diff --git a/Doc/documenting/style.rst b/Doc/documenting/style.rst --- a/Doc/documenting/style.rst +++ b/Doc/documenting/style.rst @@ -109,6 +109,110 @@ The name of the operating system developed at AT&T Bell Labs in the early 1970s. +Affirmative Tone +---------------- + +The documentation focuses on affirmatively stating what the language does and +how to use it effectively. + +Except for certain security risks or segfault risks, the docs should avoid +wording along the lines of "feature x is dangerous" or "experts only". These +kinds of value judgments belong in external blogs and wikis, not in the core +documentation. + +Bad example (creating worry in the mind of a reader): + + Warning: failing to explicitly close a file could result in lost data or + excessive resource consumption. Never rely on reference counting to + automatically close a file. + +Good example (establishing confident knowledge in the effective use of the language): + + A best practice for using files is use a try/finally pair to explicitly + close a file after it is used. Alternatively, using a with-statement can + achieve the same effect. This assures that files are flushed and file + descriptor resources are released in a timely manner. + +Economy of Expression +--------------------- + +More documentation is not necessarily better documentation. Error on the side +of being succinct. + +It is an unfortunate fact that making documentation longer can be an impediment +to understanding and can result in even more ways to misread or misinterpret the +text. Long descriptions full of corner cases and caveats can create the +impression that a function is more complex or harder to use than it actually is. + +The documentation for :func:`super` is an example of where a good deal of +information was condensed into a few short paragraphs. Discussion of +:func:`super` could have filled a chapter in a book, but it is often easier to +grasp a terse description than a lengthy narrative. + + +Code Examples +------------- + +Short code examples can be a useful adjunct to understanding. Readers can often +grasp a simple example more quickly than they can digest a formal description in +prose. + +People learn faster with concrete, motivating examples that match the context of +a typical use case. For instance, the :func:`str.rpartition` method is better +demonstrated with an example splitting the domain from a URL than it would be +with an example of removing the last word from a line of Monty Python dialog. + +The ellipsis for the :attr:`sys.ps2` secondary interpreter prompt should only be +used sparingly, where it is necessary to clearly differentiate between input +lines and output lines. Besides contributing visual clutter, it makes it +difficult for readers to cut-and-paste examples so they can experiment with +variations. + +Code Equivalents +---------------- + +Giving pure Python code equivalents (or approximate equivalents) can be a useful +adjunct to a prose description. A documenter should carefully weigh whether the +code equivalent adds value. + +A good example is the code equivalent for :func:`all`. The short 4-line code +equivalent is easily digested; it re-emphasizes the early-out behavior; and it +clarifies the handling of the corner-case where the iterable is empty. In +addition, it serves as a model for people wanting to implement a commonly +requested alternative where :func:`all` would return the specific object +evaluating to False whenever the function terminates early. + +A more questionable example is the code for :func:`itertools.groupby`. Its code +equivalent borders on being too complex to be a quick aid to understanding. +Despite its complexity, the code equivalent was kept because it serves as a +model to alternative implementations and because the operation of the "grouper" +is more easily shown in code than in English prose. + +An example of when not to use a code equivalent is for the :func:`oct` function. +The exact steps in converting a number to octal doesn't add value for a user +trying to learn what the function does. + +Audience +-------- + +The tone of the tutorial (and all the docs) needs to be respectful of the +reader's intelligence. Don't presume that the readers are stupid. Lay out the +relevant information, show motivating use cases, provide glossary links, and do +our best to connect-the-dots, but don't talk down to them or waste their time. + +The tutorial is meant for newcomers, many of whom will be using the tutorial to +evaluate the language as a whole. The experience needs to be positive and not +leave the reader with worries that something bad will happen if they make a +misstep. The tutorial serves as guide for intelligent and curious readers, +saving details for the how-to guides and other sources. + +Be careful accepting requests for documentation changes from the rare but vocal +category of reader who is looking for vindication for one of their programming +errors ("I made a mistake, therefore the docs must be wrong ..."). Typically, +the documentation wasn't consulted until after the error was made. It is +unfortunate, but typically no documentation edit would have saved the user from +making false assumptions about the language ("I was surprised by ..."). + .. _Apple Publications Style Guide: http://developer.apple.com/mac/library/documentation/UserExperience/Conceptual/APStyleGuide/APSG_2009.pdf -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 09:36:56 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 10 May 2011 09:36:56 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge Message-ID: http://hg.python.org/cpython/rev/c4ced3719761 changeset: 70005:c4ced3719761 parent: 70004:5a3140f30740 parent: 70002:b365036b17c2 user: Raymond Hettinger date: Tue May 10 00:36:35 2011 -0700 summary: merge files: Lib/test/test_logging.py | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -723,7 +723,14 @@ :func:`select` or :func:`poll` call by :func:`asyncore.loop`. """ - asyncore.loop(poll_interval, map=self.sockmap) + try: + asyncore.loop(poll_interval, map=self.sockmap) + except select.error: + # On FreeBSD 8, closing the server repeatably + # raises this error. We swallow it if the + # server has been closed. + if self.connected or self.accepting: + raise def stop(self, timeout=None): """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 09:39:10 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 10 May 2011 09:39:10 +0200 Subject: [Python-checkins] cpython (2.7): Issue 12047: Expand the style guide. Message-ID: http://hg.python.org/cpython/rev/50a5e271edf9 changeset: 70006:50a5e271edf9 branch: 2.7 parent: 70001:3c87a13980be user: Raymond Hettinger date: Tue May 10 00:39:02 2011 -0700 summary: Issue 12047: Expand the style guide. files: Doc/documenting/style.rst | 104 ++++++++++++++++++++++++++ 1 files changed, 104 insertions(+), 0 deletions(-) diff --git a/Doc/documenting/style.rst b/Doc/documenting/style.rst --- a/Doc/documenting/style.rst +++ b/Doc/documenting/style.rst @@ -65,6 +65,110 @@ The name of the operating system developed at AT&T Bell Labs in the early 1970s. +Affirmative Tone +---------------- + +The documentation focuses on affirmatively stating what the language does and +how to use it effectively. + +Except for certain security risks or segfault risks, the docs should avoid +wording along the lines of "feature x is dangerous" or "experts only". These +kinds of value judgments belong in external blogs and wikis, not in the core +documentation. + +Bad example (creating worry in the mind of a reader): + + Warning: failing to explicitly close a file could result in lost data or + excessive resource consumption. Never rely on reference counting to + automatically close a file. + +Good example (establishing confident knowledge in the effective use of the language): + + A best practice for using files is use a try/finally pair to explicitly + close a file after it is used. Alternatively, using a with-statement can + achieve the same effect. This assures that files are flushed and file + descriptor resources are released in a timely manner. + +Economy of Expression +--------------------- + +More documentation is not necessarily better documentation. Error on the side +of being succinct. + +It is an unfortunate fact that making documentation longer can be an impediment +to understanding and can result in even more ways to misread or misinterpret the +text. Long descriptions full of corner cases and caveats can create the +impression that a function is more complex or harder to use than it actually is. + +The documentation for :func:`super` is an example of where a good deal of +information was condensed into a few short paragraphs. Discussion of +:func:`super` could have filled a chapter in a book, but it is often easier to +grasp a terse description than a lengthy narrative. + + +Code Examples +------------- + +Short code examples can be a useful adjunct to understanding. Readers can often +grasp a simple example more quickly than they can digest a formal description in +prose. + +People learn faster with concrete, motivating examples that match the context of +a typical use case. For instance, the :func:`str.rpartition` method is better +demonstrated with an example splitting the domain from a URL than it would be +with an example of removing the last word from a line of Monty Python dialog. + +The ellipsis for the :attr:`sys.ps2` secondary interpreter prompt should only be +used sparingly, where it is necessary to clearly differentiate between input +lines and output lines. Besides contributing visual clutter, it makes it +difficult for readers to cut-and-paste examples so they can experiment with +variations. + +Code Equivalents +---------------- + +Giving pure Python code equivalents (or approximate equivalents) can be a useful +adjunct to a prose description. A documenter should carefully weigh whether the +code equivalent adds value. + +A good example is the code equivalent for :func:`all`. The short 4-line code +equivalent is easily digested; it re-emphasizes the early-out behavior; and it +clarifies the handling of the corner-case where the iterable is empty. In +addition, it serves as a model for people wanting to implement a commonly +requested alternative where :func:`all` would return the specific object +evaluating to False whenever the function terminates early. + +A more questionable example is the code for :func:`itertools.groupby`. Its code +equivalent borders on being too complex to be a quick aid to understanding. +Despite its complexity, the code equivalent was kept because it serves as a +model to alternative implementations and because the operation of the "grouper" +is more easily shown in code than in English prose. + +An example of when not to use a code equivalent is for the :func:`oct` function. +The exact steps in converting a number to octal doesn't add value for a user +trying to learn what the function does. + +Audience +-------- + +The tone of the tutorial (and all the docs) needs to be respectful of the +reader's intelligence. Don't presume that the readers are stupid. Lay out the +relevant information, show motivating use cases, provide glossary links, and do +our best to connect-the-dots, but don't talk down to them or waste their time. + +The tutorial is meant for newcomers, many of whom will be using the tutorial to +evaluate the language as a whole. The experience needs to be positive and not +leave the reader with worries that something bad will happen if they make a +misstep. The tutorial serves as guide for intelligent and curious readers, +saving details for the how-to guides and other sources. + +Be careful accepting requests for documentation changes from the rare but vocal +category of reader who is looking for vindication for one of their programming +errors ("I made a mistake, therefore the docs must be wrong ..."). Typically, +the documentation wasn't consulted until after the error was made. It is +unfortunate, but typically no documentation edit would have saved the user from +making false assumptions about the language ("I was surprised by ..."). + .. _Apple Publications Style Guide: http://developer.apple.com/mac/library/documentation/UserExperience/Conceptual/APStyleGuide/APSG_2009.pdf -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 10:10:15 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 10 May 2011 10:10:15 +0200 Subject: [Python-checkins] cpython: Issue #12039: Add end_headers() call to avoid BadStatusLine. Message-ID: http://hg.python.org/cpython/rev/204e027dfa98 changeset: 70007:204e027dfa98 parent: 70005:c4ced3719761 user: Vinay Sajip date: Tue May 10 09:10:08 2011 +0100 summary: Issue #12039: Add end_headers() call to avoid BadStatusLine. files: Lib/test/test_logging.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1489,6 +1489,7 @@ except: self.post_data = None request.send_response(200) + request.end_headers() self.handled.set() def test_output(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 15:26:27 2011 From: python-checkins at python.org (lukasz.langa) Date: Tue, 10 May 2011 15:26:27 +0200 Subject: [Python-checkins] cpython (3.2): Actually print out the description of what changed. Message-ID: http://hg.python.org/cpython/rev/7254c03b7180 changeset: 70008:7254c03b7180 branch: 3.2 parent: 70003:d5d91b14b238 user: ?ukasz Langa date: Tue May 10 15:25:41 2011 +0200 summary: Actually print out the description of what changed. files: Doc/library/configparser.rst | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1065,7 +1065,6 @@ :meth:`get` method. .. versionchanged:: 3.2 - Items present in *vars* no longer appear in the result. The previous behaviour mixed actual parser options with variables provided for interpolation. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 15:26:30 2011 From: python-checkins at python.org (lukasz.langa) Date: Tue, 10 May 2011 15:26:30 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged trivial doc fix from 3.2. Message-ID: http://hg.python.org/cpython/rev/aa36806b5982 changeset: 70009:aa36806b5982 parent: 70007:204e027dfa98 parent: 70008:7254c03b7180 user: ?ukasz Langa date: Tue May 10 15:26:22 2011 +0200 summary: Merged trivial doc fix from 3.2. files: Doc/library/configparser.rst | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1065,7 +1065,6 @@ :meth:`get` method. .. versionchanged:: 3.2 - Items present in *vars* no longer appear in the result. The previous behaviour mixed actual parser options with variables provided for interpolation. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 17:15:04 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 17:15:04 +0200 Subject: [Python-checkins] cpython: Issue #12011: signal.signal() and signal.siginterrupt() raise an OSError, Message-ID: http://hg.python.org/cpython/rev/b86b39211ef1 changeset: 70010:b86b39211ef1 user: Victor Stinner date: Tue May 10 17:13:00 2011 +0200 summary: Issue #12011: signal.signal() and signal.siginterrupt() raise an OSError, instead of a RuntimeError: OSError has an errno attribute. files: Doc/whatsnew/3.3.rst | 3 +++ Misc/NEWS | 3 +++ Modules/signalmodule.c | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -148,6 +148,9 @@ a nul byte into the wakeup file descriptor. So it is possible to wait more than one signal and know which signals were raised. +* :func:`signal.signal` and :func:`signal.siginterrupt` raise an OSError, + instead of a RuntimeError: OSError has an errno attribute. + Optimizations ============= diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -143,6 +143,9 @@ Library ------- +- Issue #12011: signal.signal() and signal.siginterrupt() raise an OSError, + instead of a RuntimeError: OSError has an errno attribute. + - Issue #3709: a flush_headers method to BaseHTTPRequestHandler which manages the sending of headers to output stream and flushing the internal headers buffer. Patch contribution by Andrew Schaaf diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -324,7 +324,7 @@ else func = signal_handler; if (PyOS_setsig(sig_num, func) == SIG_ERR) { - PyErr_SetFromErrno(PyExc_RuntimeError); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } old_handler = Handlers[sig_num].func; @@ -393,7 +393,7 @@ return NULL; } if (siginterrupt(sig_num, flag)<0) { - PyErr_SetFromErrno(PyExc_RuntimeError); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 17:23:19 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 May 2011 17:23:19 +0200 Subject: [Python-checkins] peps: Update with URL of hg repo Message-ID: http://hg.python.org/peps/rev/0c3788b45afc changeset: 3874:0c3788b45afc user: Antoine Pitrou date: Tue May 10 17:20:17 2011 +0200 summary: Update with URL of hg repo files: pep-3151.txt | 19 ++++++++++--------- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/pep-3151.txt b/pep-3151.txt --- a/pep-3151.txt +++ b/pep-3151.txt @@ -504,15 +504,16 @@ Implementation ============== -A reference implementation has been started in ``branches/pep-3151`` in the -Python SVN repository. For now only `Step 1`_ is implemented, and without -the deprecation warnings. However, it shows that coalescing the exception -types doesn't produce any significant annoyance in the standard library. -The only observed trouble is with the respective constructors of ``IOError`` -and ``WindowsError``, which are slightly incompatible. The way it is solved -is by keeping the ``IOError`` semantics and adding a fourth optional argument -to allow passing the Windows error code (which is different from the POSIX -errno). All ``PyErr_SetFromWindowsErr*`` functions still do the right thing. +A reference implementation has been started in +http://hg.python.org/features/pep-3151/ in branch ``pep-3151``. +For now only `Step 1`_ is implemented, and without the deprecation warnings. +However, it shows that coalescing the exception types doesn't produce any +significant annoyance in the standard library. The only observed trouble +is with the respective constructors of ``IOError`` and ``WindowsError``, +which are slightly incompatible. The way it is solved is by keeping the +``IOError`` semantics and adding a fourth optional argument to allow passing +the Windows error code (which is different from the POSIX errno). All +``PyErr_SetFromWindowsErr*`` functions do the right thing. Possible alternative -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue May 10 17:23:20 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 May 2011 17:23:20 +0200 Subject: [Python-checkins] peps: Small update wrt.SSLError Message-ID: http://hg.python.org/peps/rev/6c4c8b21cb05 changeset: 3875:6c4c8b21cb05 user: Antoine Pitrou date: Tue May 10 17:23:14 2011 +0200 summary: Small update wrt.SSLError files: pep-3151.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-3151.txt b/pep-3151.txt --- a/pep-3151.txt +++ b/pep-3151.txt @@ -551,8 +551,8 @@ in order to propagate errors signalled by the ``OpenSSL`` library. Ideally, ``SSLError`` would benefit from a similar but separate treatment since it defines its own constants for error types (``ssl.SSL_ERROR_WANT_READ``, -etc.). However, ``SSLError`` should be replaced with ``TimeoutError`` in -the case it signals a socket timeout. +etc.). In Python 3.2, ``SSLError`` is already replaced with ``socket.timeout`` +when it signals a socket timeout (see `issue 10272 `_). Endly, the fate of ``socket.gaierror`` and ``socket.herror`` is not settled. While they would deserve less cryptic names, this can be handled separately -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue May 10 17:54:34 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 May 2011 17:54:34 +0200 Subject: [Python-checkins] peps: Mention the rare issue of having a Windows error code exposed as the errno Message-ID: http://hg.python.org/peps/rev/8a7c14eff52a changeset: 3876:8a7c14eff52a user: Antoine Pitrou date: Tue May 10 17:54:07 2011 +0200 summary: Mention the rare issue of having a Windows error code exposed as the errno attribute of a non-WindowsError exception. files: pep-3151.txt | 21 +++++++++++++++------ 1 files changed, 15 insertions(+), 6 deletions(-) diff --git a/pep-3151.txt b/pep-3151.txt --- a/pep-3151.txt +++ b/pep-3151.txt @@ -508,12 +508,21 @@ http://hg.python.org/features/pep-3151/ in branch ``pep-3151``. For now only `Step 1`_ is implemented, and without the deprecation warnings. However, it shows that coalescing the exception types doesn't produce any -significant annoyance in the standard library. The only observed trouble -is with the respective constructors of ``IOError`` and ``WindowsError``, -which are slightly incompatible. The way it is solved is by keeping the -``IOError`` semantics and adding a fourth optional argument to allow passing -the Windows error code (which is different from the POSIX errno). All -``PyErr_SetFromWindowsErr*`` functions do the right thing. +significant annoyance in the standard library. + +The only observed trouble is with the respective constructors of ``IOError`` +and ``WindowsError``, which are slightly incompatible. The way it is solved +is by keeping the ``IOError`` semantics and adding a fourth optional argument +to allow passing the Windows error code (which is different from the POSIX errno). +All ``PyErr_SetFromWindowsErr*`` functions do the right thing. + +An issue is when the ``PyErr_SetExcFromWindowsErr*`` functions were called +with an exception type which is neither ``WindowsError`` nor a subclass of it: +for example an ``IOError`` whose ``errno`` attribute ended up storing +a Windows error code rather than its POSIX translation - for example +ERROR_BROKEN_PIPE (109) rather than EPIPE (32). Since native Windows error +codes are not exposed by the standard library for matching by third-party code, +such instances should only be found in our own code, and easily fixed. Possible alternative -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue May 10 18:31:23 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 May 2011 18:31:23 +0200 Subject: [Python-checkins] peps: Try to rephrase Message-ID: http://hg.python.org/peps/rev/c07476c1e6c5 changeset: 3877:c07476c1e6c5 user: Antoine Pitrou date: Tue May 10 18:31:19 2011 +0200 summary: Try to rephrase files: pep-3151.txt | 37 +++++++++++++++++++++++++------------ 1 files changed, 25 insertions(+), 12 deletions(-) diff --git a/pep-3151.txt b/pep-3151.txt --- a/pep-3151.txt +++ b/pep-3151.txt @@ -510,19 +510,32 @@ However, it shows that coalescing the exception types doesn't produce any significant annoyance in the standard library. -The only observed trouble is with the respective constructors of ``IOError`` -and ``WindowsError``, which are slightly incompatible. The way it is solved -is by keeping the ``IOError`` semantics and adding a fourth optional argument -to allow passing the Windows error code (which is different from the POSIX errno). -All ``PyErr_SetFromWindowsErr*`` functions do the right thing. +One source of trouble is with the respective constructors of ``IOError`` +and ``WindowsError``, which were incompatible. The way it is solved is by +keeping the ``IOError`` signature and adding a fourth optional argument +to allow passing the Windows error code (which is different from the POSIX +errno). The fourth argument is stored as ``winerror`` and its POSIX +translation as ``errno``. The ``PyErr_SetFromWindowsErr*`` functions have +been adapted to use the right constructor call. -An issue is when the ``PyErr_SetExcFromWindowsErr*`` functions were called -with an exception type which is neither ``WindowsError`` nor a subclass of it: -for example an ``IOError`` whose ``errno`` attribute ended up storing -a Windows error code rather than its POSIX translation - for example -ERROR_BROKEN_PIPE (109) rather than EPIPE (32). Since native Windows error -codes are not exposed by the standard library for matching by third-party code, -such instances should only be found in our own code, and easily fixed. +A slight complication is when the ``PyErr_SetExcFromWindowsErr*`` functions +are called with ``IOError`` rather than ``WindowsError``: the ``errno`` +attribute of the exception object would store the Windows error code (such +as 109 for ERROR_BROKEN_PIPE) rather than its POSIX translation (such as 32 +for EPIPE), which it does now. For non-socket error codes, this only occurs +in the private ``_multiprocessing`` module for which there is no compatibility +concern. + +.. note:: + For socket errors, the "POSIX errno" as reflected by the ``errno`` module + is numerically equal to the `Windows Socket error code + `_ + returned by the ``WSAGetLastError`` system call:: + + >>> errno.EWOULDBLOCK + 10035 + >>> errno.WSAEWOULDBLOCK + 10035 Possible alternative -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue May 10 19:20:49 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 May 2011 19:20:49 +0200 Subject: [Python-checkins] cpython (2.7): Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in Message-ID: http://hg.python.org/cpython/rev/48743ad2d2ef changeset: 70011:48743ad2d2ef branch: 2.7 parent: 70006:50a5e271edf9 user: Antoine Pitrou date: Tue May 10 19:16:03 2011 +0200 summary: Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in order to accept exactly one connection. Patch by Daniel Evers. files: Doc/library/socket.rst | 4 ++-- Lib/test/test_socket.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ Modules/socketmodule.c | 11 +++++++---- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -644,8 +644,8 @@ .. method:: socket.listen(backlog) Listen for connections made to the socket. The *backlog* argument specifies the - maximum number of queued connections and should be at least 1; the maximum value - is system-dependent (usually 5). + maximum number of queued connections and should be at least 0; the maximum value + is system-dependent (usually 5), the minimum value is forced to 0. .. method:: socket.makefile([mode[, bufsize]]) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -700,6 +700,13 @@ def test_sendall_interrupted_with_timeout(self): self.check_sendall_interrupted(True) + def testListenBacklog0(self): + srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + srv.bind((HOST, 0)) + # backlog = 0 + srv.listen(0) + srv.close() + @unittest.skipUnless(thread, 'Threading required for this test.') class BasicTCPTest(SocketConnectedTest): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -243,6 +243,7 @@ Tim Everett Paul Everitt David Everly +Daniel Evers Greg Ewing Martijn Faassen Clovis Fabricio diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,9 @@ Library ------- +- Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in + order to accept exactly one connection. Patch by Daniel Evers. + - Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. - Issue #11164: Remove obsolete allnodes test from minidom test. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2244,8 +2244,10 @@ if (backlog == -1 && PyErr_Occurred()) return NULL; Py_BEGIN_ALLOW_THREADS - if (backlog < 1) - backlog = 1; + /* To avoid problems on systems that don't allow a negative backlog + * (which doesn't make sense anyway) we force a minimum value of 0. */ + if (backlog < 0) + backlog = 0; res = listen(s->sock_fd, backlog); Py_END_ALLOW_THREADS if (res < 0) @@ -2258,8 +2260,9 @@ "listen(backlog)\n\ \n\ Enable a server to accept connections. The backlog argument must be at\n\ -least 1; it specifies the number of unaccepted connection that the system\n\ -will allow before refusing new connections."); +least 0 (if it is lower, it is set to 0); it specifies the number of\n\ +unaccepted connections that the system will allow before refusing new\n\ +connections."); #ifndef NO_DUP -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 19:20:51 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 May 2011 19:20:51 +0200 Subject: [Python-checkins] cpython (3.2): Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in Message-ID: http://hg.python.org/cpython/rev/713006ecee0c changeset: 70012:713006ecee0c branch: 3.2 parent: 70008:7254c03b7180 user: Antoine Pitrou date: Tue May 10 19:16:29 2011 +0200 summary: Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in order to accept exactly one connection. Patch by Daniel Evers. files: Doc/library/socket.rst | 4 ++-- Lib/test/test_socket.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ Modules/socketmodule.c | 11 +++++++---- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -652,8 +652,8 @@ .. method:: socket.listen(backlog) Listen for connections made to the socket. The *backlog* argument specifies the - maximum number of queued connections and should be at least 1; the maximum value - is system-dependent (usually 5). + maximum number of queued connections and should be at least 0; the maximum value + is system-dependent (usually 5), the minimum value is forced to 0. .. method:: socket.makefile(mode='r', buffering=None, *, encoding=None, \ diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -788,6 +788,13 @@ fp.close() self.assertEqual(repr(fp), "<_io.BufferedReader name=-1>") + def testListenBacklog0(self): + srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + srv.bind((HOST, 0)) + # backlog = 0 + srv.listen(0) + srv.close() + @unittest.skipUnless(thread, 'Threading required for this test.') class BasicTCPTest(SocketConnectedTest): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -268,6 +268,7 @@ Tim Everett Paul Everitt David Everly +Daniel Evers Greg Ewing Martijn Faassen Clovis Fabricio diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -86,6 +86,9 @@ Library ------- +- Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in + order to accept exactly one connection. Patch by Daniel Evers. + - Issue #11164: Stop trying to use _xmlplus in the xml module. - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2220,8 +2220,10 @@ if (backlog == -1 && PyErr_Occurred()) return NULL; Py_BEGIN_ALLOW_THREADS - if (backlog < 1) - backlog = 1; + /* To avoid problems on systems that don't allow a negative backlog + * (which doesn't make sense anyway) we force a minimum value of 0. */ + if (backlog < 0) + backlog = 0; res = listen(s->sock_fd, backlog); Py_END_ALLOW_THREADS if (res < 0) @@ -2234,8 +2236,9 @@ "listen(backlog)\n\ \n\ Enable a server to accept connections. The backlog argument must be at\n\ -least 1; it specifies the number of unaccepted connection that the system\n\ -will allow before refusing new connections."); +least 0 (if it is lower, it is set to 0); it specifies the number of\n\ +unaccepted connections that the system will allow before refusing new\n\ +connections."); /* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 19:20:52 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 May 2011 19:20:52 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in Message-ID: http://hg.python.org/cpython/rev/5e1ed84883c5 changeset: 70013:5e1ed84883c5 parent: 70010:b86b39211ef1 parent: 70012:713006ecee0c user: Antoine Pitrou date: Tue May 10 19:19:13 2011 +0200 summary: Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in order to accept exactly one connection. Patch by Daniel Evers. files: Doc/library/socket.rst | 4 ++-- Lib/test/test_socket.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ Modules/socketmodule.c | 11 +++++++---- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -662,8 +662,8 @@ .. method:: socket.listen(backlog) Listen for connections made to the socket. The *backlog* argument specifies the - maximum number of queued connections and should be at least 1; the maximum value - is system-dependent (usually 5). + maximum number of queued connections and should be at least 0; the maximum value + is system-dependent (usually 5), the minimum value is forced to 0. .. method:: socket.makefile(mode='r', buffering=None, *, encoding=None, \ diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -797,6 +797,13 @@ for protocol in range(pickle.HIGHEST_PROTOCOL + 1): self.assertRaises(TypeError, pickle.dumps, sock, protocol) + def test_listen_backlog0(self): + srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + srv.bind((HOST, 0)) + # backlog = 0 + srv.listen(0) + srv.close() + @unittest.skipUnless(thread, 'Threading required for this test.') class BasicTCPTest(SocketConnectedTest): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -270,6 +270,7 @@ Tim Everett Paul Everitt David Everly +Daniel Evers Winston Ewert Greg Ewing Martijn Faassen diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -143,6 +143,9 @@ Library ------- +- Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in + order to accept exactly one connection. Patch by Daniel Evers. + - Issue #12011: signal.signal() and signal.siginterrupt() raise an OSError, instead of a RuntimeError: OSError has an errno attribute. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2220,8 +2220,10 @@ if (backlog == -1 && PyErr_Occurred()) return NULL; Py_BEGIN_ALLOW_THREADS - if (backlog < 1) - backlog = 1; + /* To avoid problems on systems that don't allow a negative backlog + * (which doesn't make sense anyway) we force a minimum value of 0. */ + if (backlog < 0) + backlog = 0; res = listen(s->sock_fd, backlog); Py_END_ALLOW_THREADS if (res < 0) @@ -2234,8 +2236,9 @@ "listen(backlog)\n\ \n\ Enable a server to accept connections. The backlog argument must be at\n\ -least 1; it specifies the number of unaccepted connection that the system\n\ -will allow before refusing new connections."); +least 0 (if it is lower, it is set to 0); it specifies the number of\n\ +unaccepted connections that the system will allow before refusing new\n\ +connections."); /* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 21:56:09 2011 From: python-checkins at python.org (mark.dickinson) Date: Tue, 10 May 2011 21:56:09 +0200 Subject: [Python-checkins] cpython: Issue #11888: remove duplicate check for log2 in configure.in. Message-ID: http://hg.python.org/cpython/rev/d3f9895e2e19 changeset: 70014:d3f9895e2e19 user: Mark Dickinson date: Tue May 10 20:56:00 2011 +0100 summary: Issue #11888: remove duplicate check for log2 in configure.in. files: configure.in | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -2512,7 +2512,7 @@ futimens futimes \ gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ - initgroups kill killpg lchmod lchown lockf log2 linkat lstat lutimes mbrtowc mkdirat mkfifo \ + initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \ posix_fallocate posix_fadvise pread \ pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 22:00:05 2011 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 10 May 2011 22:00:05 +0200 Subject: [Python-checkins] cpython: run autoreconf Message-ID: http://hg.python.org/cpython/rev/4a6edd4fc8ee changeset: 70015:4a6edd4fc8ee user: Benjamin Peterson date: Tue May 10 15:01:56 2011 -0500 summary: run autoreconf files: configure | 1013 +++++++++++++++++------------------- pyconfig.h.in | 14 +- 2 files changed, 492 insertions(+), 535 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,14 +1,14 @@ #! /bin/sh # From configure.in Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for python 3.3. +# Generated by GNU Autoconf 2.65 for python 3.3. # # 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 @@ -92,7 +92,6 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -218,18 +217,11 @@ # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. - # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL - case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; - esac - exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -328,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 @@ -368,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 @@ -542,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` @@ -840,9 +832,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. @@ -887,7 +878,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 @@ -913,7 +904,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 @@ -1117,7 +1108,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 @@ -1133,7 +1124,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 @@ -1163,8 +1154,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." ;; *=*) @@ -1172,7 +1163,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 ;; @@ -1182,7 +1173,7 @@ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac @@ -1190,13 +1181,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 @@ -1219,7 +1210,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' @@ -1233,8 +1224,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 @@ -1249,9 +1240,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. @@ -1290,11 +1281,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 @@ -1334,7 +1325,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 @@ -1519,9 +1510,9 @@ if $ac_init_version; then cat <<\_ACEOF python configure 3.3 -generated by GNU Autoconf 2.68 - -Copyright (C) 2010 Free Software Foundation, Inc. +generated by GNU Autoconf 2.65 + +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 @@ -1565,7 +1556,7 @@ ac_retval=1 fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile @@ -1611,7 +1602,7 @@ # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link @@ -1637,7 +1628,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 : @@ -1648,7 +1639,7 @@ ac_retval=1 fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp @@ -1661,10 +1652,10 @@ ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; 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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -1700,7 +1691,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; } @@ -1723,15 +1714,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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -1740,7 +1733,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel @@ -1781,7 +1774,7 @@ ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run @@ -1795,7 +1788,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 \${$3+:} false; 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 @@ -1813,7 +1806,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile @@ -1826,7 +1819,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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1867,7 +1860,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_type @@ -1880,7 +1873,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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1910,7 +1903,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 @@ -1920,7 +1914,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_find_uintX_t @@ -1933,7 +1927,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 \${$3+:} false; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1984,7 +1978,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 @@ -1994,7 +1989,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_find_intX_t @@ -2171,7 +2166,7 @@ rm -f conftest.val fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_compute_int @@ -2184,7 +2179,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 \${$3+:} false; 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 @@ -2239,7 +2234,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func @@ -2252,7 +2247,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 \${$4+:} false; 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 @@ -2296,22 +2291,19 @@ eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # 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 \${$3+:} false; 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 @@ -2320,12 +2312,8 @@ int main () { -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif +#ifndef $2 + (void) $2; #endif ; @@ -2342,7 +2330,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_decl cat >config.log <<_ACEOF @@ -2350,7 +2338,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by python $as_me 3.3, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ @@ -2460,9 +2448,11 @@ { echo - $as_echo "## ---------------- ## + cat <<\_ASBOX +## ---------------- ## ## Cache variables. ## -## ---------------- ##" +## ---------------- ## +_ASBOX echo # The following way of writing the cache mishandles newlines in values, ( @@ -2496,9 +2486,11 @@ ) echo - $as_echo "## ----------------- ## + cat <<\_ASBOX +## ----------------- ## ## Output variables. ## -## ----------------- ##" +## ----------------- ## +_ASBOX echo for ac_var in $ac_subst_vars do @@ -2511,9 +2503,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 @@ -2527,9 +2521,11 @@ fi if test -s confdefs.h; then - $as_echo "## ----------- ## + cat <<\_ASBOX +## ----------- ## ## confdefs.h. ## -## ----------- ##" +## ----------- ## +_ASBOX echo cat confdefs.h echo @@ -2584,12 +2580,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 @@ -2604,11 +2595,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 @@ -2684,7 +2671,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. ## @@ -2785,7 +2772,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 @@ -3177,7 +3164,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 @@ -3197,7 +3184,7 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3237,7 +3224,7 @@ set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3290,7 +3277,7 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3330,7 +3317,7 @@ set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3389,7 +3376,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : +if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3433,7 +3420,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3487,8 +3474,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 @@ -3602,8 +3589,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; } @@ -3645,8 +3633,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 @@ -3703,9 +3691,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 @@ -3716,7 +3704,7 @@ ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : +if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3756,8 +3744,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 @@ -3767,7 +3755,7 @@ ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : +if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3804,7 +3792,7 @@ ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : +if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag @@ -3882,7 +3870,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : +if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no @@ -4017,7 +4005,7 @@ set dummy g++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CXX+:} false; then : +if test "${ac_cv_path_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4058,7 +4046,7 @@ set dummy c++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CXX+:} false; then : +if test "${ac_cv_path_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4109,7 +4097,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : +if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then @@ -4210,7 +4198,7 @@ CPP= fi if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : + if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded @@ -4240,7 +4228,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. @@ -4256,11 +4244,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 @@ -4299,7 +4287,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. @@ -4315,18 +4303,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 @@ -4338,7 +4326,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : +if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -4387,7 +4375,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 @@ -4401,7 +4389,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : +if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -4453,7 +4441,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 @@ -4468,7 +4456,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : +if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4585,7 +4573,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 @@ -4597,7 +4586,7 @@ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = xyes; then : +if test "x$ac_cv_header_minix_config_h" = x""yes; then : MINIX=yes else MINIX= @@ -4619,7 +4608,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if ${ac_cv_safe_to_define___extensions__+:} false; then : +if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4812,7 +4801,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } -if ${ac_cv_c_inline+:} false; then : +if test "${ac_cv_c_inline+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no @@ -5008,7 +4997,7 @@ set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : +if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then @@ -5048,7 +5037,7 @@ set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then @@ -5102,7 +5091,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : +if test "${ac_cv_prog_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then @@ -5154,7 +5143,7 @@ set dummy hg; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_HAS_HG+:} false; then : +if test "${ac_cv_prog_HAS_HG+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$HAS_HG"; then @@ -5209,22 +5198,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, @@ -5253,7 +5236,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : +if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5439,7 +5422,7 @@ ac_save_cc="$CC" CC="$CC -fno-strict-aliasing" save_CFLAGS="$CFLAGS" - if ${ac_cv_no_strict_aliasing+:} false; then : + if test "${ac_cv_no_strict_aliasing+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5562,7 +5545,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 @@ -5689,7 +5672,7 @@ # options before we can check whether -Kpthread improves anything. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads are available without options" >&5 $as_echo_n "checking whether pthreads are available without options... " >&6; } -if ${ac_cv_pthread_is_default+:} false; then : +if test "${ac_cv_pthread_is_default+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -5742,7 +5725,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kpthread" >&5 $as_echo_n "checking whether $CC accepts -Kpthread... " >&6; } -if ${ac_cv_kpthread+:} false; then : +if test "${ac_cv_kpthread+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5791,7 +5774,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kthread" >&5 $as_echo_n "checking whether $CC accepts -Kthread... " >&6; } -if ${ac_cv_kthread+:} false; then : +if test "${ac_cv_kthread+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5840,7 +5823,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -pthread" >&5 $as_echo_n "checking whether $CC accepts -pthread... " >&6; } -if ${ac_cv_thread+:} false; then : +if test "${ac_cv_thread+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5925,7 +5908,7 @@ # checks for header files { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : +if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6050,7 +6033,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 @@ -6064,7 +6048,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 \${$as_ac_Header+:} false; 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 @@ -6091,7 +6075,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 @@ -6104,7 +6089,7 @@ if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : +if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6138,11 +6123,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : + if test "${ac_cv_search_opendir+set}" = set; then : break fi done -if ${ac_cv_search_opendir+:} false; then : +if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no @@ -6161,7 +6146,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : +if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6195,11 +6180,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : + if test "${ac_cv_search_opendir+set}" = set; then : break fi done -if ${ac_cv_search_opendir+:} false; then : +if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no @@ -6219,7 +6204,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 $as_echo_n "checking whether sys/types.h defines makedev... " >&6; } -if ${ac_cv_header_sys_types_h_makedev+:} false; then : +if test "${ac_cv_header_sys_types_h_makedev+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6247,7 +6232,7 @@ if test $ac_cv_header_sys_types_h_makedev = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : +if test "x$ac_cv_header_sys_mkdev_h" = x""yes; then : $as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h @@ -6257,7 +6242,7 @@ if test $ac_cv_header_sys_mkdev_h = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then : +if test "x$ac_cv_header_sys_sysmacros_h" = x""yes; then : $as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h @@ -6277,7 +6262,7 @@ #endif " -if test "x$ac_cv_header_term_h" = xyes; then : +if test "x$ac_cv_header_term_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_TERM_H 1 _ACEOF @@ -6299,7 +6284,7 @@ #endif " -if test "x$ac_cv_header_linux_netlink_h" = xyes; then : +if test "x$ac_cv_header_linux_netlink_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_NETLINK_H 1 _ACEOF @@ -6435,7 +6420,7 @@ # Type availability checks ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" -if test "x$ac_cv_type_mode_t" = xyes; then : +if test "x$ac_cv_type_mode_t" = x""yes; then : else @@ -6446,7 +6431,7 @@ fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" -if test "x$ac_cv_type_off_t" = xyes; then : +if test "x$ac_cv_type_off_t" = x""yes; then : else @@ -6457,7 +6442,7 @@ fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = xyes; then : +if test "x$ac_cv_type_pid_t" = x""yes; then : else @@ -6473,7 +6458,7 @@ _ACEOF ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : +if test "x$ac_cv_type_size_t" = x""yes; then : else @@ -6485,7 +6470,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if ${ac_cv_type_uid_t+:} false; then : +if test "${ac_cv_type_uid_t+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6564,7 +6549,7 @@ esac ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" -if test "x$ac_cv_type_ssize_t" = xyes; then : +if test "x$ac_cv_type_ssize_t" = x""yes; then : $as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h @@ -6579,7 +6564,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 $as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : +if test "${ac_cv_sizeof_int+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : @@ -6588,8 +6573,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 @@ -6612,7 +6598,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } -if ${ac_cv_sizeof_long+:} false; then : +if test "${ac_cv_sizeof_long+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : @@ -6621,8 +6607,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 @@ -6645,7 +6632,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 $as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : +if test "${ac_cv_sizeof_void_p+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : @@ -6654,8 +6641,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 @@ -6678,7 +6666,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 $as_echo_n "checking size of short... " >&6; } -if ${ac_cv_sizeof_short+:} false; then : +if test "${ac_cv_sizeof_short+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : @@ -6687,8 +6675,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 @@ -6711,7 +6700,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 $as_echo_n "checking size of float... " >&6; } -if ${ac_cv_sizeof_float+:} false; then : +if test "${ac_cv_sizeof_float+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default"; then : @@ -6720,8 +6709,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 @@ -6744,7 +6734,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 $as_echo_n "checking size of double... " >&6; } -if ${ac_cv_sizeof_double+:} false; then : +if test "${ac_cv_sizeof_double+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then : @@ -6753,8 +6743,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 @@ -6777,7 +6768,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 $as_echo_n "checking size of fpos_t... " >&6; } -if ${ac_cv_sizeof_fpos_t+:} false; then : +if test "${ac_cv_sizeof_fpos_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default"; then : @@ -6786,8 +6777,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 @@ -6810,7 +6802,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 $as_echo_n "checking size of size_t... " >&6; } -if ${ac_cv_sizeof_size_t+:} false; then : +if test "${ac_cv_sizeof_size_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : @@ -6819,8 +6811,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 @@ -6843,7 +6836,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 $as_echo_n "checking size of pid_t... " >&6; } -if ${ac_cv_sizeof_pid_t+:} false; then : +if test "${ac_cv_sizeof_pid_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default"; then : @@ -6852,8 +6845,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 @@ -6903,7 +6897,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 $as_echo_n "checking size of long long... " >&6; } -if ${ac_cv_sizeof_long_long+:} false; then : +if test "${ac_cv_sizeof_long_long+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : @@ -6912,8 +6906,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 @@ -6964,7 +6959,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 $as_echo_n "checking size of long double... " >&6; } -if ${ac_cv_sizeof_long_double+:} false; then : +if test "${ac_cv_sizeof_long_double+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then : @@ -6973,8 +6968,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 @@ -7026,7 +7022,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of _Bool" >&5 $as_echo_n "checking size of _Bool... " >&6; } -if ${ac_cv_sizeof__Bool+:} false; then : +if test "${ac_cv_sizeof__Bool+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default"; then : @@ -7035,8 +7031,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 @@ -7062,7 +7059,7 @@ #include #endif " -if test "x$ac_cv_type_uintptr_t" = xyes; then : +if test "x$ac_cv_type_uintptr_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINTPTR_T 1 @@ -7074,7 +7071,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 $as_echo_n "checking size of uintptr_t... " >&6; } -if ${ac_cv_sizeof_uintptr_t+:} false; then : +if test "${ac_cv_sizeof_uintptr_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default"; then : @@ -7083,8 +7080,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 @@ -7110,7 +7108,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 $as_echo_n "checking size of off_t... " >&6; } -if ${ac_cv_sizeof_off_t+:} false; then : +if test "${ac_cv_sizeof_off_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " @@ -7124,8 +7122,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 @@ -7169,7 +7168,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 $as_echo_n "checking size of time_t... " >&6; } -if ${ac_cv_sizeof_time_t+:} false; then : +if test "${ac_cv_sizeof_time_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " @@ -7186,8 +7185,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 @@ -7244,7 +7244,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 $as_echo_n "checking size of pthread_t... " >&6; } -if ${ac_cv_sizeof_pthread_t+:} false; then : +if test "${ac_cv_sizeof_pthread_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " @@ -7258,8 +7258,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 @@ -7346,7 +7347,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 @@ -7358,7 +7359,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 @@ -7384,7 +7385,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 @@ -7690,7 +7691,7 @@ # checks for libraries { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile in -lsendfile" >&5 $as_echo_n "checking for sendfile in -lsendfile... " >&6; } -if ${ac_cv_lib_sendfile_sendfile+:} false; then : +if test "${ac_cv_lib_sendfile_sendfile+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7724,7 +7725,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sendfile_sendfile" >&5 $as_echo "$ac_cv_lib_sendfile_sendfile" >&6; } -if test "x$ac_cv_lib_sendfile_sendfile" = xyes; then : +if test "x$ac_cv_lib_sendfile_sendfile" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSENDFILE 1 _ACEOF @@ -7735,7 +7736,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7769,7 +7770,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF @@ -7780,7 +7781,7 @@ # Dynamic linking for SunOS/Solaris and SYSV { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } -if ${ac_cv_lib_dld_shl_load+:} false; then : +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7814,7 +7815,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes; then : +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDLD 1 _ACEOF @@ -7828,7 +7829,7 @@ if test "$with_threads" = "yes" -o -z "$with_threads"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5 $as_echo_n "checking for library containing sem_init... " >&6; } -if ${ac_cv_search_sem_init+:} false; then : +if test "${ac_cv_search_sem_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -7862,11 +7863,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if ${ac_cv_search_sem_init+:} false; then : + if test "${ac_cv_search_sem_init+set}" = set; then : break fi done -if ${ac_cv_search_sem_init+:} false; then : +if test "${ac_cv_search_sem_init+set}" = set; then : else ac_cv_search_sem_init=no @@ -7889,7 +7890,7 @@ # check if we need libintl for locale functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for textdomain in -lintl" >&5 $as_echo_n "checking for textdomain in -lintl... " >&6; } -if ${ac_cv_lib_intl_textdomain+:} false; then : +if test "${ac_cv_lib_intl_textdomain+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7923,7 +7924,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_textdomain" >&5 $as_echo "$ac_cv_lib_intl_textdomain" >&6; } -if test "x$ac_cv_lib_intl_textdomain" = xyes; then : +if test "x$ac_cv_lib_intl_textdomain" = x""yes; then : $as_echo "#define WITH_LIBINTL 1" >>confdefs.h @@ -7970,7 +7971,7 @@ # Most SVR4 platforms (e.g. Solaris) need -lsocket and -lnsl. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for t_open in -lnsl" >&5 $as_echo_n "checking for t_open in -lnsl... " >&6; } -if ${ac_cv_lib_nsl_t_open+:} false; then : +if test "${ac_cv_lib_nsl_t_open+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8004,13 +8005,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 $as_echo "$ac_cv_lib_nsl_t_open" >&6; } -if test "x$ac_cv_lib_nsl_t_open" = xyes; then : +if test "x$ac_cv_lib_nsl_t_open" = x""yes; then : LIBS="-lnsl $LIBS" fi # SVR4 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 $as_echo_n "checking for socket in -lsocket... " >&6; } -if ${ac_cv_lib_socket_socket+:} false; then : +if test "${ac_cv_lib_socket_socket+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8044,7 +8045,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 $as_echo "$ac_cv_lib_socket_socket" >&6; } -if test "x$ac_cv_lib_socket_socket" = xyes; then : +if test "x$ac_cv_lib_socket_socket" = x""yes; then : LIBS="-lsocket $LIBS" fi # SVR4 sockets @@ -8070,7 +8071,7 @@ set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PKG_CONFIG+:} false; then : +if test "${ac_cv_path_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in @@ -8113,7 +8114,7 @@ set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : +if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in @@ -8224,12 +8225,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 @@ -8378,7 +8379,7 @@ $as_echo "#define _REENTRANT 1" >>confdefs.h ac_fn_c_check_header_mongrel "$LINENO" "cthreads.h" "ac_cv_header_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_cthreads_h" = xyes; then : +if test "x$ac_cv_header_cthreads_h" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8391,7 +8392,7 @@ else ac_fn_c_check_header_mongrel "$LINENO" "mach/cthreads.h" "ac_cv_header_mach_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_mach_cthreads_h" = xyes; then : +if test "x$ac_cv_header_mach_cthreads_h" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8435,7 +8436,7 @@ LIBS=$_libs ac_fn_c_check_func "$LINENO" "pthread_detach" "ac_cv_func_pthread_detach" -if test "x$ac_cv_func_pthread_detach" = xyes; then : +if test "x$ac_cv_func_pthread_detach" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8444,7 +8445,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 $as_echo_n "checking for pthread_create in -lpthreads... " >&6; } -if ${ac_cv_lib_pthreads_pthread_create+:} false; then : +if test "${ac_cv_lib_pthreads_pthread_create+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8478,7 +8479,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 $as_echo "$ac_cv_lib_pthreads_pthread_create" >&6; } -if test "x$ac_cv_lib_pthreads_pthread_create" = xyes; then : +if test "x$ac_cv_lib_pthreads_pthread_create" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8488,7 +8489,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 $as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if ${ac_cv_lib_c_r_pthread_create+:} false; then : +if test "${ac_cv_lib_c_r_pthread_create+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8522,7 +8523,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 $as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : +if test "x$ac_cv_lib_c_r_pthread_create" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8532,7 +8533,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_create_system in -lpthread" >&5 $as_echo_n "checking for __pthread_create_system in -lpthread... " >&6; } -if ${ac_cv_lib_pthread___pthread_create_system+:} false; then : +if test "${ac_cv_lib_pthread___pthread_create_system+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8566,7 +8567,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_create_system" >&5 $as_echo "$ac_cv_lib_pthread___pthread_create_system" >&6; } -if test "x$ac_cv_lib_pthread___pthread_create_system" = xyes; then : +if test "x$ac_cv_lib_pthread___pthread_create_system" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8576,7 +8577,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lcma" >&5 $as_echo_n "checking for pthread_create in -lcma... " >&6; } -if ${ac_cv_lib_cma_pthread_create+:} false; then : +if test "${ac_cv_lib_cma_pthread_create+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8610,7 +8611,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cma_pthread_create" >&5 $as_echo "$ac_cv_lib_cma_pthread_create" >&6; } -if test "x$ac_cv_lib_cma_pthread_create" = xyes; then : +if test "x$ac_cv_lib_cma_pthread_create" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8642,7 +8643,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usconfig in -lmpc" >&5 $as_echo_n "checking for usconfig in -lmpc... " >&6; } -if ${ac_cv_lib_mpc_usconfig+:} false; then : +if test "${ac_cv_lib_mpc_usconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8676,7 +8677,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mpc_usconfig" >&5 $as_echo "$ac_cv_lib_mpc_usconfig" >&6; } -if test "x$ac_cv_lib_mpc_usconfig" = xyes; then : +if test "x$ac_cv_lib_mpc_usconfig" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lmpc" @@ -8688,7 +8689,7 @@ if test "$posix_threads" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for thr_create in -lthread" >&5 $as_echo_n "checking for thr_create in -lthread... " >&6; } -if ${ac_cv_lib_thread_thr_create+:} false; then : +if test "${ac_cv_lib_thread_thr_create+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8722,7 +8723,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_thread_thr_create" >&5 $as_echo "$ac_cv_lib_thread_thr_create" >&6; } -if test "x$ac_cv_lib_thread_thr_create" = xyes; then : +if test "x$ac_cv_lib_thread_thr_create" = x""yes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lthread" @@ -8762,7 +8763,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PTHREAD_SCOPE_SYSTEM is supported" >&5 $as_echo_n "checking if PTHREAD_SCOPE_SYSTEM is supported... " >&6; } - if ${ac_cv_pthread_system_supported+:} false; then : + if test "${ac_cv_pthread_system_supported+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -8805,7 +8806,7 @@ for ac_func in pthread_sigmask do : ac_fn_c_check_func "$LINENO" "pthread_sigmask" "ac_cv_func_pthread_sigmask" -if test "x$ac_cv_func_pthread_sigmask" = xyes; then : +if test "x$ac_cv_func_pthread_sigmask" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_SIGMASK 1 _ACEOF @@ -9197,12 +9198,12 @@ $as_echo "$with_valgrind" >&6; } if test "$with_valgrind" != no; then ac_fn_c_check_header_mongrel "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_valgrind_h" = xyes; then : +if test "x$ac_cv_header_valgrind_valgrind_h" = x""yes; then : $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 @@ -9219,7 +9220,7 @@ for ac_func in dlopen do : ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes; then : +if test "x$ac_cv_func_dlopen" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLOPEN 1 _ACEOF @@ -9300,7 +9301,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 @@ -9550,7 +9552,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock declaration" >&5 $as_echo_n "checking for flock declaration... " >&6; } -if ${ac_cv_flock_decl+:} false; then : +if test "${ac_cv_flock_decl+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -9580,7 +9582,7 @@ for ac_func in flock do : ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" -if test "x$ac_cv_func_flock" = xyes; then : +if test "x$ac_cv_func_flock" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FLOCK 1 _ACEOF @@ -9588,7 +9590,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 $as_echo_n "checking for flock in -lbsd... " >&6; } -if ${ac_cv_lib_bsd_flock+:} false; then : +if test "${ac_cv_lib_bsd_flock+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9622,7 +9624,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_flock" >&5 $as_echo "$ac_cv_lib_bsd_flock" >&6; } -if test "x$ac_cv_lib_bsd_flock" = xyes; then : +if test "x$ac_cv_lib_bsd_flock" = x""yes; then : $as_echo "#define HAVE_FLOCK 1" >>confdefs.h @@ -9699,7 +9701,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_TRUE+:} false; then : +if test "${ac_cv_prog_TRUE+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$TRUE"; then @@ -9739,7 +9741,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lc" >&5 $as_echo_n "checking for inet_aton in -lc... " >&6; } -if ${ac_cv_lib_c_inet_aton+:} false; then : +if test "${ac_cv_lib_c_inet_aton+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9773,12 +9775,12 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_aton" >&5 $as_echo "$ac_cv_lib_c_inet_aton" >&6; } -if test "x$ac_cv_lib_c_inet_aton" = xyes; then : +if test "x$ac_cv_lib_c_inet_aton" = x""yes; then : $ac_cv_prog_TRUE else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 $as_echo_n "checking for inet_aton in -lresolv... " >&6; } -if ${ac_cv_lib_resolv_inet_aton+:} false; then : +if test "${ac_cv_lib_resolv_inet_aton+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9812,7 +9814,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5 $as_echo "$ac_cv_lib_resolv_inet_aton" >&6; } -if test "x$ac_cv_lib_resolv_inet_aton" = xyes; then : +if test "x$ac_cv_lib_resolv_inet_aton" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF @@ -9829,7 +9831,7 @@ # exit Python { $as_echo "$as_me:${as_lineno-$LINENO}: checking for chflags" >&5 $as_echo_n "checking for chflags... " >&6; } -if ${ac_cv_have_chflags+:} false; then : +if test "${ac_cv_have_chflags+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -9863,7 +9865,7 @@ $as_echo "$ac_cv_have_chflags" >&6; } if test "$ac_cv_have_chflags" = cross ; then ac_fn_c_check_func "$LINENO" "chflags" "ac_cv_func_chflags" -if test "x$ac_cv_func_chflags" = xyes; then : +if test "x$ac_cv_func_chflags" = x""yes; then : ac_cv_have_chflags="yes" else ac_cv_have_chflags="no" @@ -9878,7 +9880,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lchflags" >&5 $as_echo_n "checking for lchflags... " >&6; } -if ${ac_cv_have_lchflags+:} false; then : +if test "${ac_cv_have_lchflags+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -9912,7 +9914,7 @@ $as_echo "$ac_cv_have_lchflags" >&6; } if test "$ac_cv_have_lchflags" = cross ; then ac_fn_c_check_func "$LINENO" "lchflags" "ac_cv_func_lchflags" -if test "x$ac_cv_func_lchflags" = xyes; then : +if test "x$ac_cv_func_lchflags" = x""yes; then : ac_cv_have_lchflags="yes" else ac_cv_have_lchflags="no" @@ -9936,7 +9938,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 $as_echo_n "checking for inflateCopy in -lz... " >&6; } -if ${ac_cv_lib_z_inflateCopy+:} false; then : +if test "${ac_cv_lib_z_inflateCopy+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9970,7 +9972,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 $as_echo "$ac_cv_lib_z_inflateCopy" >&6; } -if test "x$ac_cv_lib_z_inflateCopy" = xyes; then : +if test "x$ac_cv_lib_z_inflateCopy" = x""yes; then : $as_echo "#define HAVE_ZLIB_COPY 1" >>confdefs.h @@ -10113,7 +10115,7 @@ for ac_func in openpty do : ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty" -if test "x$ac_cv_func_openpty" = xyes; then : +if test "x$ac_cv_func_openpty" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENPTY 1 _ACEOF @@ -10121,7 +10123,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 $as_echo_n "checking for openpty in -lutil... " >&6; } -if ${ac_cv_lib_util_openpty+:} false; then : +if test "${ac_cv_lib_util_openpty+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10155,13 +10157,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 $as_echo "$ac_cv_lib_util_openpty" >&6; } -if test "x$ac_cv_lib_util_openpty" = xyes; then : +if test "x$ac_cv_lib_util_openpty" = x""yes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 $as_echo_n "checking for openpty in -lbsd... " >&6; } -if ${ac_cv_lib_bsd_openpty+:} false; then : +if test "${ac_cv_lib_bsd_openpty+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10195,7 +10197,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_openpty" >&5 $as_echo "$ac_cv_lib_bsd_openpty" >&6; } -if test "x$ac_cv_lib_bsd_openpty" = xyes; then : +if test "x$ac_cv_lib_bsd_openpty" = x""yes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10210,7 +10212,7 @@ for ac_func in forkpty do : ac_fn_c_check_func "$LINENO" "forkpty" "ac_cv_func_forkpty" -if test "x$ac_cv_func_forkpty" = xyes; then : +if test "x$ac_cv_func_forkpty" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FORKPTY 1 _ACEOF @@ -10218,7 +10220,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 $as_echo_n "checking for forkpty in -lutil... " >&6; } -if ${ac_cv_lib_util_forkpty+:} false; then : +if test "${ac_cv_lib_util_forkpty+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10252,13 +10254,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_forkpty" >&5 $as_echo "$ac_cv_lib_util_forkpty" >&6; } -if test "x$ac_cv_lib_util_forkpty" = xyes; then : +if test "x$ac_cv_lib_util_forkpty" = x""yes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 $as_echo_n "checking for forkpty in -lbsd... " >&6; } -if ${ac_cv_lib_bsd_forkpty+:} false; then : +if test "${ac_cv_lib_bsd_forkpty+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10292,7 +10294,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_forkpty" >&5 $as_echo "$ac_cv_lib_bsd_forkpty" >&6; } -if test "x$ac_cv_lib_bsd_forkpty" = xyes; then : +if test "x$ac_cv_lib_bsd_forkpty" = x""yes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10309,7 +10311,7 @@ for ac_func in memmove do : ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" -if test "x$ac_cv_func_memmove" = xyes; then : +if test "x$ac_cv_func_memmove" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MEMMOVE 1 _ACEOF @@ -10323,7 +10325,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 @@ -10332,50 +10335,31 @@ done -ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" -if test "x$ac_cv_func_dup2" = xyes; then : - $as_echo "#define HAVE_DUP2 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 - *" dup2.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS dup2.$ac_objext" + *" $ac_func.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;; esac fi - -ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" -if test "x$ac_cv_func_getcwd" = xyes; 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" = xyes; then : - $as_echo "#define HAVE_STRDUP 1" >>confdefs.h - -else - case " $LIBOBJS " in - *" strdup.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS strdup.$ac_objext" - ;; -esac - -fi +done for ac_func in getpgrp do : ac_fn_c_check_func "$LINENO" "getpgrp" "ac_cv_func_getpgrp" -if test "x$ac_cv_func_getpgrp" = xyes; then : +if test "x$ac_cv_func_getpgrp" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETPGRP 1 _ACEOF @@ -10403,7 +10387,7 @@ for ac_func in setpgrp do : ac_fn_c_check_func "$LINENO" "setpgrp" "ac_cv_func_setpgrp" -if test "x$ac_cv_func_setpgrp" = xyes; then : +if test "x$ac_cv_func_setpgrp" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETPGRP 1 _ACEOF @@ -10431,7 +10415,7 @@ for ac_func in gettimeofday do : ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" -if test "x$ac_cv_func_gettimeofday" = xyes; then : +if test "x$ac_cv_func_gettimeofday" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETTIMEOFDAY 1 _ACEOF @@ -10533,7 +10517,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking getaddrinfo bug" >&5 $as_echo_n "checking getaddrinfo bug... " >&6; } - if ${ac_cv_buggy_getaddrinfo+:} false; then : + if test "${ac_cv_buggy_getaddrinfo+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10662,7 +10646,7 @@ for ac_func in getnameinfo do : ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo" -if test "x$ac_cv_func_getnameinfo" = xyes; then : +if test "x$ac_cv_func_getnameinfo" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETNAMEINFO 1 _ACEOF @@ -10674,7 +10658,7 @@ # checks for structures { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if ${ac_cv_header_time+:} false; then : +if test "${ac_cv_header_time+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10709,7 +10693,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if ${ac_cv_struct_tm+:} false; then : +if test "${ac_cv_struct_tm+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10746,7 +10730,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -10762,7 +10746,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = xyes; then : +if test "x$ac_cv_have_decl_tzname" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -10774,7 +10758,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if ${ac_cv_var_tzname+:} false; then : +if test "${ac_cv_var_tzname+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10810,7 +10794,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_RDEV 1 @@ -10820,7 +10804,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_blksize" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 @@ -10830,7 +10814,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_flags" "ac_cv_member_struct_stat_st_flags" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_flags" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_flags" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_FLAGS 1 @@ -10840,7 +10824,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_gen" "ac_cv_member_struct_stat_st_gen" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_gen" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_gen" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_GEN 1 @@ -10850,7 +10834,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtime" "ac_cv_member_struct_stat_st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtime" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_birthtime" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 @@ -10860,7 +10844,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_blocks" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLOCKS 1 @@ -10882,7 +10866,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 $as_echo_n "checking for time.h that defines altzone... " >&6; } -if ${ac_cv_header_time_altzone+:} false; then : +if test "${ac_cv_header_time_altzone+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -10946,7 +10930,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for addrinfo" >&5 $as_echo_n "checking for addrinfo... " >&6; } -if ${ac_cv_struct_addrinfo+:} false; then : +if test "${ac_cv_struct_addrinfo+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10978,7 +10962,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sockaddr_storage" >&5 $as_echo_n "checking for sockaddr_storage... " >&6; } -if ${ac_cv_struct_sockaddr_storage+:} false; then : +if test "${ac_cv_struct_sockaddr_storage+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11014,7 +10998,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether char is unsigned" >&5 $as_echo_n "checking whether char is unsigned... " >&6; } -if ${ac_cv_c_char_unsigned+:} false; then : +if test "${ac_cv_c_char_unsigned+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11046,7 +11030,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if ${ac_cv_c_const+:} false; then : +if test "${ac_cv_c_const+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11334,7 +11318,7 @@ ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" -if test "x$ac_cv_func_gethostbyname_r" = xyes; then : +if test "x$ac_cv_func_gethostbyname_r" = x""yes; then : $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h @@ -11465,7 +11449,7 @@ for ac_func in gethostbyname do : ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = xyes; then : +if test "x$ac_cv_func_gethostbyname" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTBYNAME 1 _ACEOF @@ -11487,12 +11471,12 @@ # Linux requires this for correct f.p. operations ac_fn_c_check_func "$LINENO" "__fpu_control" "ac_cv_func___fpu_control" -if test "x$ac_cv_func___fpu_control" = xyes; then : +if test "x$ac_cv_func___fpu_control" = x""yes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 $as_echo_n "checking for __fpu_control in -lieee... " >&6; } -if ${ac_cv_lib_ieee___fpu_control+:} false; then : +if test "${ac_cv_lib_ieee___fpu_control+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -11526,7 +11510,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee___fpu_control" >&5 $as_echo "$ac_cv_lib_ieee___fpu_control" >&6; } -if test "x$ac_cv_lib_ieee___fpu_control" = xyes; then : +if test "x$ac_cv_lib_ieee___fpu_control" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBIEEE 1 _ACEOF @@ -11582,7 +11566,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 @@ -11606,7 +11590,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 @@ -11620,7 +11604,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are little-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are little-endian IEEE 754 binary64... " >&6; } -if ${ac_cv_little_endian_double+:} false; then : +if test "${ac_cv_little_endian_double+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -11662,7 +11646,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are big-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are big-endian IEEE 754 binary64... " >&6; } -if ${ac_cv_big_endian_double+:} false; then : +if test "${ac_cv_big_endian_double+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -11708,7 +11692,7 @@ # conversions work. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are ARM mixed-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are ARM mixed-endian IEEE 754 binary64... " >&6; } -if ${ac_cv_mixed_endian_double+:} false; then : +if test "${ac_cv_mixed_endian_double+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -11856,7 +11840,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 @@ -11868,7 +11853,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 @@ -11878,7 +11864,7 @@ ac_fn_c_check_decl "$LINENO" "isinf" "ac_cv_have_decl_isinf" "#include " -if test "x$ac_cv_have_decl_isinf" = xyes; then : +if test "x$ac_cv_have_decl_isinf" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11889,7 +11875,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isnan" "ac_cv_have_decl_isnan" "#include " -if test "x$ac_cv_have_decl_isnan" = xyes; then : +if test "x$ac_cv_have_decl_isnan" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11900,7 +11886,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isfinite" "ac_cv_have_decl_isfinite" "#include " -if test "x$ac_cv_have_decl_isfinite" = xyes; then : +if test "x$ac_cv_have_decl_isfinite" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11915,7 +11901,7 @@ # -0. on some architectures. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tanh preserves the sign of zero" >&5 $as_echo_n "checking whether tanh preserves the sign of zero... " >&6; } -if ${ac_cv_tanh_preserves_zero_sign+:} false; then : +if test "${ac_cv_tanh_preserves_zero_sign+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -11963,7 +11949,7 @@ # -0. See issue #9920. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether log1p drops the sign of negative zero" >&5 $as_echo_n "checking whether log1p drops the sign of negative zero... " >&6; } - if ${ac_cv_log1p_drops_zero_sign+:} false; then : + if test "${ac_cv_log1p_drops_zero_sign+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -12015,7 +12001,7 @@ # sem_open results in a 'Signal 12' error. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX semaphores are enabled" >&5 $as_echo_n "checking whether POSIX semaphores are enabled... " >&6; } -if ${ac_cv_posix_semaphores_enabled+:} false; then : +if test "${ac_cv_posix_semaphores_enabled+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12066,7 +12052,7 @@ # Multiprocessing check for broken sem_getvalue { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken sem_getvalue" >&5 $as_echo_n "checking for broken sem_getvalue... " >&6; } -if ${ac_cv_broken_sem_getvalue+:} false; then : +if test "${ac_cv_broken_sem_getvalue+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12131,7 +12117,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; } @@ -12149,7 +12135,7 @@ # check for wchar.h ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" -if test "x$ac_cv_header_wchar_h" = xyes; then : +if test "x$ac_cv_header_wchar_h" = x""yes; then : $as_echo "#define HAVE_WCHAR_H 1" >>confdefs.h @@ -12172,7 +12158,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 $as_echo_n "checking size of wchar_t... " >&6; } -if ${ac_cv_sizeof_wchar_t+:} false; then : +if test "${ac_cv_sizeof_wchar_t+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include @@ -12182,8 +12168,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 @@ -12238,7 +12225,7 @@ # check whether wchar_t is signed or not { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wchar_t is signed" >&5 $as_echo_n "checking whether wchar_t is signed... " >&6; } - if ${ac_cv_wchar_t_signed+:} false; then : + if test "${ac_cv_wchar_t_signed+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -12334,7 +12321,7 @@ # check for endianness { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if ${ac_cv_c_bigendian+:} false; then : +if test "${ac_cv_c_bigendian+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown @@ -12552,7 +12539,7 @@ ;; #( *) - as_fn_error $? "unknown endianness + as_fn_error "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac @@ -12625,7 +12612,7 @@ # or fills with zeros (like the Cray J90, according to Tim Peters). { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether right shift extends the sign bit" >&5 $as_echo_n "checking whether right shift extends the sign bit... " >&6; } -if ${ac_cv_rshift_extends_sign+:} false; then : +if test "${ac_cv_rshift_extends_sign+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -12664,7 +12651,7 @@ # check for getc_unlocked and related locking functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getc_unlocked() and friends" >&5 $as_echo_n "checking for getc_unlocked() and friends... " >&6; } -if ${ac_cv_have_getc_unlocked+:} false; then : +if test "${ac_cv_have_getc_unlocked+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -12762,7 +12749,7 @@ # check for readline 2.1 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_callback_handler_install in -lreadline" >&5 $as_echo_n "checking for rl_callback_handler_install in -lreadline... " >&6; } -if ${ac_cv_lib_readline_rl_callback_handler_install+:} false; then : +if test "${ac_cv_lib_readline_rl_callback_handler_install+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12796,7 +12783,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_callback_handler_install" >&5 $as_echo "$ac_cv_lib_readline_rl_callback_handler_install" >&6; } -if test "x$ac_cv_lib_readline_rl_callback_handler_install" = xyes; then : +if test "x$ac_cv_lib_readline_rl_callback_handler_install" = x""yes; then : $as_echo "#define HAVE_RL_CALLBACK 1" >>confdefs.h @@ -12814,7 +12801,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 @@ -12848,7 +12835,7 @@ # check for readline 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_pre_input_hook in -lreadline" >&5 $as_echo_n "checking for rl_pre_input_hook in -lreadline... " >&6; } -if ${ac_cv_lib_readline_rl_pre_input_hook+:} false; then : +if test "${ac_cv_lib_readline_rl_pre_input_hook+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12882,7 +12869,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_pre_input_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_pre_input_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_pre_input_hook" = xyes; then : +if test "x$ac_cv_lib_readline_rl_pre_input_hook" = x""yes; then : $as_echo "#define HAVE_RL_PRE_INPUT_HOOK 1" >>confdefs.h @@ -12892,7 +12879,7 @@ # also in 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_display_matches_hook in -lreadline" >&5 $as_echo_n "checking for rl_completion_display_matches_hook in -lreadline... " >&6; } -if ${ac_cv_lib_readline_rl_completion_display_matches_hook+:} false; then : +if test "${ac_cv_lib_readline_rl_completion_display_matches_hook+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12926,7 +12913,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_display_matches_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_display_matches_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = xyes; then : +if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = x""yes; then : $as_echo "#define HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK 1" >>confdefs.h @@ -12936,7 +12923,7 @@ # check for readline 4.2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_matches in -lreadline" >&5 $as_echo_n "checking for rl_completion_matches in -lreadline... " >&6; } -if ${ac_cv_lib_readline_rl_completion_matches+:} false; then : +if test "${ac_cv_lib_readline_rl_completion_matches+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12970,7 +12957,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_matches" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_matches" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_matches" = xyes; then : +if test "x$ac_cv_lib_readline_rl_completion_matches" = x""yes; then : $as_echo "#define HAVE_RL_COMPLETION_MATCHES 1" >>confdefs.h @@ -12988,7 +12975,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 @@ -13011,7 +12998,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken nice()" >&5 $as_echo_n "checking for broken nice()... " >&6; } -if ${ac_cv_broken_nice+:} false; then : +if test "${ac_cv_broken_nice+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -13052,7 +13039,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken poll()" >&5 $as_echo_n "checking for broken poll()... " >&6; } -if ${ac_cv_broken_poll+:} false; then : +if test "${ac_cv_broken_poll+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13107,7 +13094,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -13123,7 +13110,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = xyes; then : +if test "x$ac_cv_have_decl_tzname" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 @@ -13135,7 +13122,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if ${ac_cv_var_tzname+:} false; then : +if test "${ac_cv_var_tzname+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13174,7 +13161,7 @@ # check tzset(3) exists and works like we expect it to { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working tzset()" >&5 $as_echo_n "checking for working tzset()... " >&6; } -if ${ac_cv_working_tzset+:} false; then : +if test "${ac_cv_working_tzset+set}" = set; then : $as_echo_n "(cached) " >&6 else @@ -13271,7 +13258,7 @@ # Look for subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec in struct stat" >&5 $as_echo_n "checking for tv_nsec in struct stat... " >&6; } -if ${ac_cv_stat_tv_nsec+:} false; then : +if test "${ac_cv_stat_tv_nsec+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13308,7 +13295,7 @@ # Look for BSD style subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec2 in struct stat" >&5 $as_echo_n "checking for tv_nsec2 in struct stat... " >&6; } -if ${ac_cv_stat_tv_nsec2+:} false; then : +if test "${ac_cv_stat_tv_nsec2+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13345,7 +13332,7 @@ # On HP/UX 11.0, mvwdelch is a block with a return statement { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mvwdelch is an expression" >&5 $as_echo_n "checking whether mvwdelch is an expression... " >&6; } -if ${ac_cv_mvwdelch_is_expression+:} false; then : +if test "${ac_cv_mvwdelch_is_expression+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13382,7 +13369,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether WINDOW has _flags" >&5 $as_echo_n "checking whether WINDOW has _flags... " >&6; } -if ${ac_cv_window_has_flags+:} false; then : +if test "${ac_cv_window_has_flags+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13530,7 +13517,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %lld and %llu printf() format support" >&5 $as_echo_n "checking for %lld and %llu printf() format support... " >&6; } - if ${ac_cv_have_long_long_format+:} false; then : + if test "${ac_cv_have_long_long_format+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13600,7 +13587,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %zd printf() format support" >&5 $as_echo_n "checking for %zd printf() format support... " >&6; } -if ${ac_cv_have_size_t_format+:} false; then : +if test "${ac_cv_have_size_t_format+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13673,7 +13660,7 @@ #endif " -if test "x$ac_cv_type_socklen_t" = xyes; then : +if test "x$ac_cv_type_socklen_t" = x""yes; then : else @@ -13684,7 +13671,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken mbstowcs" >&5 $as_echo_n "checking for broken mbstowcs... " >&6; } -if ${ac_cv_broken_mbstowcs+:} false; then : +if test "${ac_cv_broken_mbstowcs+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13724,7 +13711,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports computed gotos" >&5 $as_echo_n "checking whether $CC supports computed gotos... " >&6; } -if ${ac_cv_computed_gotos+:} false; then : +if test "${ac_cv_computed_gotos+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13804,7 +13791,7 @@ ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" -if test "x$ac_cv_func_pipe2" = xyes; then : +if test "x$ac_cv_func_pipe2" = x""yes; then : $as_echo "#define HAVE_PIPE2 1" >>confdefs.h @@ -13899,21 +13886,10 @@ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then + test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi + cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} @@ -13929,7 +13905,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$//' @@ -13946,7 +13921,7 @@ -: "${CONFIG_STATUS=./config.status}" +: ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" @@ -14047,7 +14022,6 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -14093,19 +14067,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 @@ -14301,7 +14275,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 @@ -14355,7 +14329,7 @@ # values after options handling. ac_log=" This file was extended by python $as_me 3.3, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -14417,10 +14391,10 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ python config.status 3.3 -configured by $0, generated by GNU Autoconf 2.68, +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." @@ -14436,16 +14410,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 @@ -14467,7 +14436,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;; @@ -14480,7 +14448,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 ;; @@ -14489,7 +14457,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" @@ -14548,7 +14516,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 @@ -14570,10 +14538,9 @@ # after its creation but before its name has been assigned to `$tmp'. $debug || { - tmp= ac_tmp= + tmp= trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } @@ -14581,13 +14548,12 @@ { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" + test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp +} || 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. @@ -14604,12 +14570,12 @@ 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 -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF @@ -14618,18 +14584,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 @@ -14637,7 +14603,7 @@ rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h @@ -14685,7 +14651,7 @@ rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && +cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" @@ -14717,29 +14683,21 @@ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || 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 +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# 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 @@ -14751,7 +14709,7 @@ # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || +cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF @@ -14763,11 +14721,11 @@ # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + 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 @@ -14852,7 +14810,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" @@ -14865,7 +14823,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 @@ -14884,7 +14842,7 @@ for ac_f do case $ac_f in - -) ac_f="$ac_tmp/stdin";; + -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. @@ -14893,7 +14851,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'" @@ -14919,8 +14877,8 @@ esac case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -15050,24 +15008,23 @@ s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 +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 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && + { 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;} - - rm -f "$ac_tmp/stdin" +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + -) 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) # @@ -15076,21 +15033,21 @@ if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || 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 "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error "could not create -" "$LINENO" 5 fi ;; @@ -15110,7 +15067,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. @@ -15131,7 +15088,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 diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -494,7 +494,7 @@ /* Define this if you have the makedev macro. */ #undef HAVE_MAKEDEV -/* Define this if mallopt can set malloc mmap threshold. */ +/* Define if mallopt can set malloc mmap threshold. */ #undef HAVE_MALLOPT_MMAP_THRESHOLD /* Define to 1 if you have the `mbrtowc' function. */ @@ -590,12 +590,12 @@ /* Define to 1 if you have the `pthread_init' function. */ #undef HAVE_PTHREAD_INIT +/* Define to 1 if you have the `pthread_kill' function. */ +#undef HAVE_PTHREAD_KILL + /* Define to 1 if you have the `pthread_sigmask' function. */ #undef HAVE_PTHREAD_SIGMASK -/* Define to 1 if you have the `pthread_kill' function. */ -#undef HAVE_PTHREAD_KILL - /* Define to 1 if you have the header file. */ #undef HAVE_PTY_H @@ -725,12 +725,12 @@ /* Define to 1 if you have the `siginterrupt' function. */ #undef HAVE_SIGINTERRUPT +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGNAL_H + /* Define to 1 if you have the `sigpending' function. */ #undef HAVE_SIGPENDING -/* Define to 1 if you have the header file. */ -#undef HAVE_SIGNAL_H - /* Define to 1 if you have the `sigrelse' function. */ #undef HAVE_SIGRELSE -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 23:38:11 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 May 2011 23:38:11 +0200 Subject: [Python-checkins] cpython (3.2): Issue #12054: use support.find_unused_port() instead of reinventing the wheel Message-ID: http://hg.python.org/cpython/rev/695a7acae392 changeset: 70016:695a7acae392 branch: 3.2 parent: 70012:713006ecee0c user: Antoine Pitrou date: Tue May 10 23:37:11 2011 +0200 summary: Issue #12054: use support.find_unused_port() instead of reinventing the wheel files: Lib/test/test_socket.py | 18 ++---------------- 1 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -564,23 +564,9 @@ # XXX The following don't test module-level functionality... - def _get_unused_port(self, bind_address='0.0.0.0'): - """Use a temporary socket to elicit an unused ephemeral port. - - Args: - bind_address: Hostname or IP address to search for a port on. - - Returns: A most likely to be unused port. - """ - tempsock = socket.socket() - tempsock.bind((bind_address, 0)) - host, port = tempsock.getsockname() - tempsock.close() - return port - def testSockName(self): # Testing getsockname() - port = self._get_unused_port() + port = support.find_unused_port() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.addCleanup(sock.close) sock.bind(("0.0.0.0", port)) @@ -629,7 +615,7 @@ def test_getsockaddrarg(self): host = '0.0.0.0' - port = self._get_unused_port(bind_address=host) + port = support.find_unused_port() big_port = port + 65536 neg_port = port - 65536 sock = socket.socket() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 23:38:12 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 May 2011 23:38:12 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #12054: use support.find_unused_port() instead of reinventing the wheel Message-ID: http://hg.python.org/cpython/rev/1b9d6226a3dd changeset: 70017:1b9d6226a3dd parent: 70015:4a6edd4fc8ee parent: 70016:695a7acae392 user: Antoine Pitrou date: Tue May 10 23:37:42 2011 +0200 summary: Issue #12054: use support.find_unused_port() instead of reinventing the wheel files: Lib/test/test_socket.py | 18 ++---------------- 1 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -567,23 +567,9 @@ # XXX The following don't test module-level functionality... - def _get_unused_port(self, bind_address='0.0.0.0'): - """Use a temporary socket to elicit an unused ephemeral port. - - Args: - bind_address: Hostname or IP address to search for a port on. - - Returns: A most likely to be unused port. - """ - tempsock = socket.socket() - tempsock.bind((bind_address, 0)) - host, port = tempsock.getsockname() - tempsock.close() - return port - def testSockName(self): # Testing getsockname() - port = self._get_unused_port() + port = support.find_unused_port() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.addCleanup(sock.close) sock.bind(("0.0.0.0", port)) @@ -632,7 +618,7 @@ def test_getsockaddrarg(self): host = '0.0.0.0' - port = self._get_unused_port(bind_address=host) + port = support.find_unused_port() big_port = port + 65536 neg_port = port - 65536 sock = socket.socket() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 10 23:42:44 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 May 2011 23:42:44 +0200 Subject: [Python-checkins] cpython: Issue #11888: skip some log2 tests on Mac OS X Tiger Message-ID: http://hg.python.org/cpython/rev/34871c3072c9 changeset: 70018:34871c3072c9 user: Victor Stinner date: Tue May 10 23:40:17 2011 +0200 summary: Issue #11888: skip some log2 tests on Mac OS X Tiger System log2() is not accurate for exact power of 2. files: Lib/test/test_math.py | 15 +++++++++++---- 1 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -5,6 +5,7 @@ import unittest import math import os +import platform import sys import struct import sysconfig @@ -652,10 +653,6 @@ @requires_IEEE_754 def testLog2(self): self.assertRaises(TypeError, math.log2) - # Check that we get exact equality for log2 of powers of 2. - actual = [math.log2(math.ldexp(1.0, n)) for n in range(-1074, 1024)] - expected = [float(n) for n in range(-1074, 1024)] - self.assertEqual(actual, expected) # Check some integer values self.assertEqual(math.log2(1), 0.0) @@ -671,6 +668,16 @@ self.assertRaises(ValueError, math.log2, NINF) self.assertTrue(math.isnan(math.log2(NAN))) + @requires_IEEE_754 + @unittest.skipIf(sys.platform == 'darwin' + and platform.mac_ver()[0].startswith('10.4.'), + 'Mac OS X Tiger log2() is not accurate enough') + def testLog2Exact(self): + # Check that we get exact equality for log2 of powers of 2. + actual = [math.log2(math.ldexp(1.0, n)) for n in range(-1074, 1024)] + expected = [float(n) for n in range(-1074, 1024)] + self.assertEqual(actual, expected) + def testLog10(self): self.assertRaises(TypeError, math.log10) self.ftest('log10(0.1)', math.log10(0.1), -1) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:15:38 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 May 2011 00:15:38 +0200 Subject: [Python-checkins] cpython: Close #10419, issue #6011: build_scripts command of distutils handles correctly Message-ID: http://hg.python.org/cpython/rev/6ad356525381 changeset: 70019:6ad356525381 user: Victor Stinner date: Wed May 11 00:14:28 2011 +0200 summary: Close #10419, issue #6011: build_scripts command of distutils handles correctly non-ASCII path (path to the Python executable). Open and write the script in binary mode, but ensure that the shebang is decodable from UTF-8 and from the encoding of the script. files: Lib/distutils/command/build_scripts.py | 45 ++++++++++--- Misc/NEWS | 5 + 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/Lib/distutils/command/build_scripts.py b/Lib/distutils/command/build_scripts.py --- a/Lib/distutils/command/build_scripts.py +++ b/Lib/distutils/command/build_scripts.py @@ -11,9 +11,10 @@ from distutils.dep_util import newer from distutils.util import convert_path, Mixin2to3 from distutils import log +import tokenize # check if Python is called on the first line with this expression -first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$') +first_line_re = re.compile(b'^#!.*python[0-9.]*([ \t].*)?$') class build_scripts(Command): @@ -74,12 +75,14 @@ # that way, we'll get accurate feedback if we can read the # script. try: - f = open(script, "r") + f = open(script, "rb") except IOError: if not self.dry_run: raise f = None else: + encoding, lines = tokenize.detect_encoding(f.readline) + f.seek(0) first_line = f.readline() if not first_line: self.warn("%s is an empty file (skipping)" % script) @@ -88,25 +91,45 @@ match = first_line_re.match(first_line) if match: adjust = True - post_interp = match.group(1) or '' + post_interp = match.group(1) or b'' if adjust: log.info("copying and adjusting %s -> %s", script, self.build_dir) updated_files.append(outfile) if not self.dry_run: - outf = open(outfile, "w") if not sysconfig.python_build: - outf.write("#!%s%s\n" % - (self.executable, - post_interp)) + executable = self.executable else: - outf.write("#!%s%s\n" % - (os.path.join( + executable = os.path.join( sysconfig.get_config_var("BINDIR"), "python%s%s" % (sysconfig.get_config_var("VERSION"), - sysconfig.get_config_var("EXE"))), - post_interp)) + sysconfig.get_config_var("EXE"))) + executable = os.fsencode(executable) + shebang = b"#!" + executable + post_interp + b"\n" + # Python parser starts to read a script using UTF-8 until + # it gets a #coding:xxx cookie. The shebang has to be the + # first line of a file, the #coding:xxx cookie cannot be + # written before. So the shebang has to be decodable from + # UTF-8. + try: + shebang.decode('utf-8') + except UnicodeDecodeError: + raise ValueError( + "The shebang ({!r}) is not decodable " + "from utf-8".format(shebang)) + # If the script is encoded to a custom encoding (use a + # #coding:xxx cookie), the shebang has to be decodable from + # the script encoding too. + try: + shebang.decode(encoding) + except UnicodeDecodeError: + raise ValueError( + "The shebang ({!r}) is not decodable " + "from the script encoding ({})" + .format(shebang, encoding)) + outf = open(outfile, "wb") + outf.write(shebang) outf.writelines(f.readlines()) outf.close() if f: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -143,6 +143,11 @@ Library ------- +- Issue #10419, #6011: build_scripts command of distutils handles correctly + non-ASCII path (path to the Python executable). Open and write the script in + binary mode, but ensure that the shebang is decodable from UTF-8 and from the + encoding of the script. + - Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in order to accept exactly one connection. Patch by Daniel Evers. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:24:02 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 11 May 2011 00:24:02 +0200 Subject: [Python-checkins] cpython (2.7): #12051: Fix segfault in json.dumps() while encoding highly-nested objects using Message-ID: http://hg.python.org/cpython/rev/a21f5af476cb changeset: 70020:a21f5af476cb branch: 2.7 parent: 70011:48743ad2d2ef user: Ezio Melotti date: Wed May 11 00:55:35 2011 +0300 summary: #12051: Fix segfault in json.dumps() while encoding highly-nested objects using the C accelerations. files: Lib/json/tests/test_recursion.py | 22 +++++++++++++++++++- Misc/NEWS | 3 ++ Modules/_json.c | 17 +++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Lib/json/tests/test_recursion.py b/Lib/json/tests/test_recursion.py --- a/Lib/json/tests/test_recursion.py +++ b/Lib/json/tests/test_recursion.py @@ -16,6 +16,11 @@ return 'JSONTestObject' return json.JSONEncoder.default(o) +class EndlessJSONEncoder(json.JSONEncoder): + def default(self, o): + """If check_circular is False, this will keep adding another list.""" + return [o] + class TestRecursion(TestCase): def test_listrecursion(self): @@ -67,7 +72,7 @@ self.fail("didn't raise ValueError on default recursion") - def test_highly_nested_objects(self): + def test_highly_nested_objects_decoding(self): # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 # str @@ -84,3 +89,18 @@ json.loads(u'{"a":' * 100000 + u'[1]' + u'}' * 100000) with self.assertRaises(RuntimeError): json.loads(u'[' * 100000 + u'1' + u']' * 100000) + + def test_highly_nested_objects_encoding(self): + # See #12051 + l, d = [], {} + for x in xrange(100000): + l, d = [l], {'k':d} + with self.assertRaises(RuntimeError): + json.dumps(l) + with self.assertRaises(RuntimeError): + json.dumps(d) + + def test_endless_recursion(self): + # See #12051 + with self.assertRaises(RuntimeError): + EndlessJSONEncoder(check_circular=False).encode(5j) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -373,6 +373,9 @@ - Issue #10169: Fix argument parsing in socket.sendto() to avoid error masking. +- Issue #12051: Fix segfault in json.dumps() while encoding highly-nested + objects using the C accelerations. + - Issue #12017: Fix segfault in json.loads() while decoding highly-nested objects using the C accelerations. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1999,10 +1999,18 @@ return _steal_list_append(rval, encoded); } else if (PyList_Check(obj) || PyTuple_Check(obj)) { - return encoder_listencode_list(s, rval, obj, indent_level); + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; + rv = encoder_listencode_list(s, rval, obj, indent_level); + Py_LeaveRecursiveCall(); + return rv; } else if (PyDict_Check(obj)) { - return encoder_listencode_dict(s, rval, obj, indent_level); + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; + rv = encoder_listencode_dict(s, rval, obj, indent_level); + Py_LeaveRecursiveCall(); + return rv; } else { PyObject *ident = NULL; @@ -2028,7 +2036,12 @@ Py_XDECREF(ident); return -1; } + + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; rv = encoder_listencode_obj(s, rval, newobj, indent_level); + Py_LeaveRecursiveCall(); + Py_DECREF(newobj); if (rv) { Py_XDECREF(ident); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:24:15 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 11 May 2011 00:24:15 +0200 Subject: [Python-checkins] cpython (3.1): #12051: Fix segfault in json.dumps() while encoding highly-nested objects using Message-ID: http://hg.python.org/cpython/rev/9557e4eeb291 changeset: 70021:9557e4eeb291 branch: 3.1 parent: 69997:b7abf0590e1c user: Ezio Melotti date: Wed May 11 01:02:56 2011 +0300 summary: #12051: Fix segfault in json.dumps() while encoding highly-nested objects using the C accelerations. files: Lib/json/tests/test_recursion.py | 21 +++++++++++++++++++- Misc/NEWS | 3 ++ Modules/_json.c | 17 ++++++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Lib/json/tests/test_recursion.py b/Lib/json/tests/test_recursion.py --- a/Lib/json/tests/test_recursion.py +++ b/Lib/json/tests/test_recursion.py @@ -16,6 +16,11 @@ return 'JSONTestObject' return json.JSONEncoder.default(o) +class EndlessJSONEncoder(json.JSONEncoder): + def default(self, o): + """If check_circular is False, this will keep adding another list.""" + return [o] + class TestRecursion(TestCase): def test_listrecursion(self): @@ -67,7 +72,7 @@ self.fail("didn't raise ValueError on default recursion") - def test_highly_nested_objects(self): + def test_highly_nested_objects_decoding(self): # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 with self.assertRaises(RuntimeError): @@ -77,3 +82,17 @@ with self.assertRaises(RuntimeError): json.loads('[' * 100000 + '1' + ']' * 100000) + def test_highly_nested_objects_encoding(self): + # See #12051 + l, d = [], {} + for x in range(100000): + l, d = [l], {'k':d} + with self.assertRaises(RuntimeError): + json.dumps(l) + with self.assertRaises(RuntimeError): + json.dumps(d) + + def test_endless_recursion(self): + # See #12051 + with self.assertRaises(RuntimeError): + EndlessJSONEncoder(check_circular=False).encode(5j) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -326,6 +326,9 @@ Extension Modules ----------------- +- Issue #12051: Fix segfault in json.dumps() while encoding highly-nested + objects using the C accelerations. + - Issue #12017: Fix segfault in json.loads() while decoding highly-nested objects using the C accelerations. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1301,10 +1301,18 @@ return _steal_list_append(rval, encoded); } else if (PyList_Check(obj) || PyTuple_Check(obj)) { - return encoder_listencode_list(s, rval, obj, indent_level); + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; + rv = encoder_listencode_list(s, rval, obj, indent_level); + Py_LeaveRecursiveCall(); + return rv; } else if (PyDict_Check(obj)) { - return encoder_listencode_dict(s, rval, obj, indent_level); + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; + rv = encoder_listencode_dict(s, rval, obj, indent_level); + Py_LeaveRecursiveCall(); + return rv; } else { PyObject *ident = NULL; @@ -1330,7 +1338,12 @@ Py_XDECREF(ident); return -1; } + + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; rv = encoder_listencode_obj(s, rval, newobj, indent_level); + Py_LeaveRecursiveCall(); + Py_DECREF(newobj); if (rv) { Py_XDECREF(ident); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:24:23 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 11 May 2011 00:24:23 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #12051: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/3847b279d665 changeset: 70022:3847b279d665 branch: 3.2 parent: 70016:695a7acae392 parent: 70021:9557e4eeb291 user: Ezio Melotti date: Wed May 11 01:10:27 2011 +0300 summary: #12051: merge with 3.1. files: Lib/test/json_tests/test_recursion.py | 21 ++++++++++++++- Misc/NEWS | 3 ++ Modules/_json.c | 17 ++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Lib/test/json_tests/test_recursion.py b/Lib/test/json_tests/test_recursion.py --- a/Lib/test/json_tests/test_recursion.py +++ b/Lib/test/json_tests/test_recursion.py @@ -16,6 +16,11 @@ return 'JSONTestObject' return json.JSONEncoder.default(o) +class EndlessJSONEncoder(json.JSONEncoder): + def default(self, o): + """If check_circular is False, this will keep adding another list.""" + return [o] + class TestRecursion(TestCase): def test_listrecursion(self): @@ -67,7 +72,7 @@ self.fail("didn't raise ValueError on default recursion") - def test_highly_nested_objects(self): + def test_highly_nested_objects_decoding(self): # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 with self.assertRaises(RuntimeError): @@ -77,3 +82,17 @@ with self.assertRaises(RuntimeError): json.loads('[' * 100000 + '1' + ']' * 100000) + def test_highly_nested_objects_encoding(self): + # See #12051 + l, d = [], {} + for x in range(100000): + l, d = [l], {'k':d} + with self.assertRaises(RuntimeError): + json.dumps(l) + with self.assertRaises(RuntimeError): + json.dumps(d) + + def test_endless_recursion(self): + # See #12051 + with self.assertRaises(RuntimeError): + EndlessJSONEncoder(check_circular=False).encode(5j) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -342,6 +342,9 @@ Extension Modules ----------------- +- Issue #12051: Fix segfault in json.dumps() while encoding highly-nested + objects using the C accelerations. + - Issue #12017: Fix segfault in json.loads() while decoding highly-nested objects using the C accelerations. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1338,10 +1338,18 @@ return _steal_list_append(rval, encoded); } else if (PyList_Check(obj) || PyTuple_Check(obj)) { - return encoder_listencode_list(s, rval, obj, indent_level); + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; + rv = encoder_listencode_list(s, rval, obj, indent_level); + Py_LeaveRecursiveCall(); + return rv; } else if (PyDict_Check(obj)) { - return encoder_listencode_dict(s, rval, obj, indent_level); + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; + rv = encoder_listencode_dict(s, rval, obj, indent_level); + Py_LeaveRecursiveCall(); + return rv; } else { PyObject *ident = NULL; @@ -1367,7 +1375,12 @@ Py_XDECREF(ident); return -1; } + + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; rv = encoder_listencode_obj(s, rval, newobj, indent_level); + Py_LeaveRecursiveCall(); + Py_DECREF(newobj); if (rv) { Py_XDECREF(ident); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:24:29 2011 From: python-checkins at python.org (ezio.melotti) Date: Wed, 11 May 2011 00:24:29 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #12051: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/821d7885c7ec changeset: 70023:821d7885c7ec parent: 70019:6ad356525381 parent: 70022:3847b279d665 user: Ezio Melotti date: Wed May 11 01:23:41 2011 +0300 summary: #12051: merge with 3.2. files: Lib/test/json_tests/test_recursion.py | 22 ++++++++++++++- Misc/NEWS | 3 ++ Modules/_json.c | 17 ++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Lib/test/json_tests/test_recursion.py b/Lib/test/json_tests/test_recursion.py --- a/Lib/test/json_tests/test_recursion.py +++ b/Lib/test/json_tests/test_recursion.py @@ -16,6 +16,11 @@ return 'JSONTestObject' return json.JSONEncoder.default(o) +class EndlessJSONEncoder(json.JSONEncoder): + def default(self, o): + """If check_circular is False, this will keep adding another list.""" + return [o] + class TestRecursion(TestCase): def test_listrecursion(self): @@ -67,7 +72,7 @@ self.fail("didn't raise ValueError on default recursion") - def test_highly_nested_objects(self): + def test_highly_nested_objects_decoding(self): # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 with self.assertRaises(RuntimeError): @@ -76,3 +81,18 @@ json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) with self.assertRaises(RuntimeError): json.loads('[' * 100000 + '1' + ']' * 100000) + + def test_highly_nested_objects_encoding(self): + # See #12051 + l, d = [], {} + for x in range(100000): + l, d = [l], {'k':d} + with self.assertRaises(RuntimeError): + json.dumps(l) + with self.assertRaises(RuntimeError): + json.dumps(d) + + def test_endless_recursion(self): + # See #12051 + with self.assertRaises(RuntimeError): + EndlessJSONEncoder(check_circular=False).encode(5j) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -624,6 +624,9 @@ Extension Modules ----------------- +- Issue #12051: Fix segfault in json.dumps() while encoding highly-nested + objects using the C accelerations. + - Issue #12017: Fix segfault in json.loads() while decoding highly-nested objects using the C accelerations. diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1354,10 +1354,18 @@ return _steal_list_append(rval, encoded); } else if (PyList_Check(obj) || PyTuple_Check(obj)) { - return encoder_listencode_list(s, rval, obj, indent_level); + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; + rv = encoder_listencode_list(s, rval, obj, indent_level); + Py_LeaveRecursiveCall(); + return rv; } else if (PyDict_Check(obj)) { - return encoder_listencode_dict(s, rval, obj, indent_level); + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; + rv = encoder_listencode_dict(s, rval, obj, indent_level); + Py_LeaveRecursiveCall(); + return rv; } else { PyObject *ident = NULL; @@ -1383,7 +1391,12 @@ Py_XDECREF(ident); return -1; } + + if (Py_EnterRecursiveCall(" while encoding a JSON object")) + return -1; rv = encoder_listencode_obj(s, rval, newobj, indent_level); + Py_LeaveRecursiveCall(); + Py_DECREF(newobj); if (rv) { Py_XDECREF(ident); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:32:14 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 May 2011 00:32:14 +0200 Subject: [Python-checkins] cpython (3.2): Close #10419, issue #6011: build_scripts command of distutils handles correctly Message-ID: http://hg.python.org/cpython/rev/47236a0cfb15 changeset: 70024:47236a0cfb15 branch: 3.2 parent: 70022:3847b279d665 user: Victor Stinner date: Wed May 11 00:14:28 2011 +0200 summary: Close #10419, issue #6011: build_scripts command of distutils handles correctly non-ASCII path (path to the Python executable). Open and write the script in binary mode, but ensure that the shebang is decodable from UTF-8 and from the encoding of the script. files: Lib/distutils/command/build_scripts.py | 45 ++++++++++--- Misc/NEWS | 5 + 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/Lib/distutils/command/build_scripts.py b/Lib/distutils/command/build_scripts.py --- a/Lib/distutils/command/build_scripts.py +++ b/Lib/distutils/command/build_scripts.py @@ -11,9 +11,10 @@ from distutils.dep_util import newer from distutils.util import convert_path, Mixin2to3 from distutils import log +import tokenize # check if Python is called on the first line with this expression -first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$') +first_line_re = re.compile(b'^#!.*python[0-9.]*([ \t].*)?$') class build_scripts(Command): @@ -74,12 +75,14 @@ # that way, we'll get accurate feedback if we can read the # script. try: - f = open(script, "r") + f = open(script, "rb") except IOError: if not self.dry_run: raise f = None else: + encoding, lines = tokenize.detect_encoding(f.readline) + f.seek(0) first_line = f.readline() if not first_line: self.warn("%s is an empty file (skipping)" % script) @@ -88,25 +91,45 @@ match = first_line_re.match(first_line) if match: adjust = True - post_interp = match.group(1) or '' + post_interp = match.group(1) or b'' if adjust: log.info("copying and adjusting %s -> %s", script, self.build_dir) updated_files.append(outfile) if not self.dry_run: - outf = open(outfile, "w") if not sysconfig.python_build: - outf.write("#!%s%s\n" % - (self.executable, - post_interp)) + executable = self.executable else: - outf.write("#!%s%s\n" % - (os.path.join( + executable = os.path.join( sysconfig.get_config_var("BINDIR"), "python%s%s" % (sysconfig.get_config_var("VERSION"), - sysconfig.get_config_var("EXE"))), - post_interp)) + sysconfig.get_config_var("EXE"))) + executable = os.fsencode(executable) + shebang = b"#!" + executable + post_interp + b"\n" + # Python parser starts to read a script using UTF-8 until + # it gets a #coding:xxx cookie. The shebang has to be the + # first line of a file, the #coding:xxx cookie cannot be + # written before. So the shebang has to be decodable from + # UTF-8. + try: + shebang.decode('utf-8') + except UnicodeDecodeError: + raise ValueError( + "The shebang ({!r}) is not decodable " + "from utf-8".format(shebang)) + # If the script is encoded to a custom encoding (use a + # #coding:xxx cookie), the shebang has to be decodable from + # the script encoding too. + try: + shebang.decode(encoding) + except UnicodeDecodeError: + raise ValueError( + "The shebang ({!r}) is not decodable " + "from the script encoding ({})" + .format(shebang, encoding)) + outf = open(outfile, "wb") + outf.write(shebang) outf.writelines(f.readlines()) outf.close() if f: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -86,6 +86,11 @@ Library ------- +- Issue #10419, #6011: build_scripts command of distutils handles correctly + non-ASCII path (path to the Python executable). Open and write the script in + binary mode, but ensure that the shebang is decodable from UTF-8 and from the + encoding of the script. + - Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in order to accept exactly one connection. Patch by Daniel Evers. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:32:15 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 May 2011 00:32:15 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2 (empty, patch already applied to 3.3) Message-ID: http://hg.python.org/cpython/rev/87d3c17a39b6 changeset: 70025:87d3c17a39b6 parent: 70023:821d7885c7ec parent: 70024:47236a0cfb15 user: Victor Stinner date: Wed May 11 00:31:16 2011 +0200 summary: Merge 3.2 (empty, patch already applied to 3.3) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:38:43 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 May 2011 00:38:43 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11169: compileall module uses repr() to format filenames and paths to Message-ID: http://hg.python.org/cpython/rev/85cfbbc7da60 changeset: 70026:85cfbbc7da60 branch: 3.2 parent: 70024:47236a0cfb15 user: Victor Stinner date: Wed May 11 00:36:28 2011 +0200 summary: Issue #11169: compileall module uses repr() to format filenames and paths to escape surrogate characters and show spaces. files: Lib/compileall.py | 10 +++++----- Lib/test/test_compileall.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/compileall.py b/Lib/compileall.py --- a/Lib/compileall.py +++ b/Lib/compileall.py @@ -35,11 +35,11 @@ optimize: optimization level or -1 for level of the interpreter """ if not quiet: - print('Listing', dir, '...') + print('Listing {!r}...'.format(dir)) try: names = os.listdir(dir) except os.error: - print("Can't list", dir) + print("Can't list {!r}".format(dir)) names = [] names.sort() success = 1 @@ -109,13 +109,13 @@ except IOError: pass if not quiet: - print('Compiling', fullname, '...') + print('Compiling {!r}...'.format(fullname)) try: ok = py_compile.compile(fullname, cfile, dfile, True, optimize=optimize) except py_compile.PyCompileError as err: if quiet: - print('*** Error compiling', fullname, '...') + print('*** Error compiling {!r}...'.format(fullname)) else: print('*** ', end='') # escape non-printable characters in msg @@ -126,7 +126,7 @@ success = 0 except (SyntaxError, UnicodeError, IOError) as e: if quiet: - print('*** Error compiling', fullname, '...') + print('*** Error compiling {!r}...'.format(fullname)) else: print('*** ', end='') print(e.__class__.__name__ + ':', e) diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -345,7 +345,7 @@ def test_invalid_arg_produces_message(self): out = self.assertRunOK('badfilename') - self.assertRegex(out, b"Can't list badfilename") + self.assertRegex(out, b"Can't list 'badfilename'") def test_main(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -86,6 +86,9 @@ Library ------- +- Issue #11169: compileall module uses repr() to format filenames and paths to + escape surrogate characters and show spaces. + - Issue #10419, #6011: build_scripts command of distutils handles correctly non-ASCII path (path to the Python executable). Open and write the script in binary mode, but ensure that the shebang is decodable from UTF-8 and from the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:38:44 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 May 2011 00:38:44 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2 (empty, patch already applied to 3.3) Message-ID: http://hg.python.org/cpython/rev/58ef15feb937 changeset: 70027:58ef15feb937 parent: 70025:87d3c17a39b6 parent: 70026:85cfbbc7da60 user: Victor Stinner date: Wed May 11 00:37:36 2011 +0200 summary: Merge 3.2 (empty, patch already applied to 3.3) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:59:44 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 May 2011 00:59:44 +0200 Subject: [Python-checkins] cpython (3.1): Issue #10419: Fix build_scripts command of distutils to handle correctly Message-ID: http://hg.python.org/cpython/rev/fd7d4639dae2 changeset: 70028:fd7d4639dae2 branch: 3.1 parent: 70021:9557e4eeb291 user: Victor Stinner date: Wed May 11 00:57:29 2011 +0200 summary: Issue #10419: Fix build_scripts command of distutils to handle correctly non-ASCII scripts. Open and write the script in binary mode, but ensure that the shebang is decodable from UTF-8 and from the encoding of the script. files: Lib/distutils/command/build_scripts.py | 47 ++++++++++--- Misc/NEWS | 4 + 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Lib/distutils/command/build_scripts.py b/Lib/distutils/command/build_scripts.py --- a/Lib/distutils/command/build_scripts.py +++ b/Lib/distutils/command/build_scripts.py @@ -11,9 +11,11 @@ from distutils.dep_util import newer from distutils.util import convert_path, Mixin2to3 from distutils import log +import sys +import tokenize # check if Python is called on the first line with this expression -first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$') +first_line_re = re.compile(b'^#!.*python[0-9.]*([ \t].*)?$') class build_scripts(Command): @@ -74,12 +76,14 @@ # that way, we'll get accurate feedback if we can read the # script. try: - f = open(script, "r") + f = open(script, "rb") except IOError: if not self.dry_run: raise f = None else: + encoding, lines = tokenize.detect_encoding(f.readline) + f.seek(0) first_line = f.readline() if not first_line: self.warn("%s is an empty file (skipping)" % script) @@ -88,25 +92,46 @@ match = first_line_re.match(first_line) if match: adjust = True - post_interp = match.group(1) or '' + post_interp = match.group(1) or b'' if adjust: log.info("copying and adjusting %s -> %s", script, self.build_dir) updated_files.append(outfile) if not self.dry_run: - outf = open(outfile, "w") if not sysconfig.python_build: - outf.write("#!%s%s\n" % - (self.executable, - post_interp)) + executable = self.executable else: - outf.write("#!%s%s\n" % - (os.path.join( + executable = os.path.join( sysconfig.get_config_var("BINDIR"), "python%s%s" % (sysconfig.get_config_var("VERSION"), - sysconfig.get_config_var("EXE"))), - post_interp)) + sysconfig.get_config_var("EXE"))) + executable = executable.encode(sys.getfilesystemencoding(), + 'surrogateescape') + shebang = b"#!" + executable + post_interp + b"\n" + # Python parser starts to read a script using UTF-8 until + # it gets a #coding:xxx cookie. The shebang has to be the + # first line of a file, the #coding:xxx cookie cannot be + # written before. So the shebang has to be decodable from + # UTF-8. + try: + shebang.decode('utf-8') + except UnicodeDecodeError: + raise ValueError( + "The shebang ({!r}) is not decodable " + "from utf-8".format(shebang)) + # If the script is encoded to a custom encoding (use a + # #coding:xxx cookie), the shebang has to be decodable from + # the script encoding too. + try: + shebang.decode(encoding) + except UnicodeDecodeError: + raise ValueError( + "The shebang ({!r}) is not decodable " + "from the script encoding ({})" + .format(shebang, encoding)) + outf = open(outfile, "wb") + outf.write(shebang) outf.writelines(f.readlines()) outf.close() if f: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,10 @@ Library ------- +- Issue #10419: Fix build_scripts command of distutils to handle correctly + non-ASCII scripts. Open and write the script in binary mode, but ensure that + the shebang is decodable from UTF-8 and from the encoding of the script. + - Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. - Issue #11164: Stop trying to use _xmlplus in the xml module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:59:45 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 May 2011 00:59:45 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge 3.1 (empty merge, a similar patch was already applied) Message-ID: http://hg.python.org/cpython/rev/af18b150065e changeset: 70029:af18b150065e branch: 3.2 parent: 70026:85cfbbc7da60 parent: 70028:fd7d4639dae2 user: Victor Stinner date: Wed May 11 00:58:26 2011 +0200 summary: Merge 3.1 (empty merge, a similar patch was already applied) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 00:59:58 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 May 2011 00:59:58 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2 (empty merge, patch already applied to 3.3) Message-ID: http://hg.python.org/cpython/rev/96235f1cfd7e changeset: 70030:96235f1cfd7e parent: 70027:58ef15feb937 parent: 70029:af18b150065e user: Victor Stinner date: Wed May 11 00:59:08 2011 +0200 summary: Merge 3.2 (empty merge, patch already applied to 3.3) files: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed May 11 04:59:32 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 11 May 2011 04:59:32 +0200 Subject: [Python-checkins] Daily reference leaks (96235f1cfd7e): sum=0 Message-ID: results for 96235f1cfd7e on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogEc9Wa8', '-x'] From python-checkins at python.org Wed May 11 05:46:01 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 11 May 2011 05:46:01 +0200 Subject: [Python-checkins] cpython: Issue #12039 - Update the http.server.rst with the requirement to call Message-ID: http://hg.python.org/cpython/rev/d59ec3aa442e changeset: 70031:d59ec3aa442e user: Senthil Kumaran date: Wed May 11 11:45:48 2011 +0800 summary: Issue #12039 - Update the http.server.rst with the requirement to call `end_headers` after calling `send_header`. files: Doc/library/http.server.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -188,9 +188,10 @@ .. method:: send_header(keyword, value) Adds the HTTP header to an internal buffer which will be written to the - output stream when either :meth:`end_headers` or :meth:`flush_headers` - is invoked. *keyword* should specify the header keyword, with *value* - specifying its value. + output stream when either :meth:`end_headers` or :meth:`flush_headers` is + invoked. *keyword* should specify the header keyword, with *value* + specifying its value. Note that, after the send_header calls are done, + :meth:`end_headers` MUST BE called in order to complete the operation. .. versionchanged:: 3.2 Storing the headers in an internal buffer -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 10:04:41 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 11 May 2011 10:04:41 +0200 Subject: [Python-checkins] cpython: issue12039 - update the documentation of send_response method in Message-ID: http://hg.python.org/cpython/rev/4651bf40af8d changeset: 70032:4651bf40af8d user: Senthil Kumaran date: Wed May 11 16:04:28 2011 +0800 summary: issue12039 - update the documentation of send_response method in http.server.rst. files: Doc/library/http.server.rst | 15 +++++++++++---- 1 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -180,10 +180,17 @@ .. method:: send_response(code, message=None) Adds a response header to the headers buffer and logs the accepted - request. The HTTP response line is sent, followed by *Server* and - *Date* headers. The values for these two headers are picked up from - the :meth:`version_string` and :meth:`date_time_string` methods, - respectively. + request. The HTTP response line is written to the internal buffer, + followed by *Server* and *Date* headers. The values for these two headers + are picked up from the :meth:`version_string` and + :meth:`date_time_string` methods, respectively. If the server does not + intend to send any other headers using the :meth:`send_header` method, + then send_response should be followed by a :meth:`end_headers` call. + + ..versionchanged:: 3.3 + Writing of headers to internal buffer and need to call + :meth:`end_headers` explicitly. + .. method:: send_header(keyword, value) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 15:18:12 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 11 May 2011 15:18:12 +0200 Subject: [Python-checkins] cpython: Fix closes Issue #11799: urllib.request Authentication Handlers will raise a Message-ID: http://hg.python.org/cpython/rev/6072db001b51 changeset: 70033:6072db001b51 user: Senthil Kumaran date: Wed May 11 21:17:57 2011 +0800 summary: Fix closes Issue #11799: urllib.request Authentication Handlers will raise a ValueError when presented with an unsupported Authentication Scheme. files: Doc/library/urllib.request.rst | 26 +++++++++++++++------ Lib/test/test_urllib2.py | 24 ++++++++++++++++++++ Lib/urllib/request.py | 25 ++++++++++++++------ Misc/NEWS | 4 +++ 4 files changed, 63 insertions(+), 16 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -240,10 +240,11 @@ .. class:: HTTPBasicAuthHandler(password_mgr=None) - Handle authentication with the remote host. *password_mgr*, if given, should be - something that is compatible with :class:`HTTPPasswordMgr`; refer to section - :ref:`http-password-mgr` for information on the interface that must be - supported. + Handle authentication with the remote host. *password_mgr*, if given, should + be something that is compatible with :class:`HTTPPasswordMgr`; refer to + section :ref:`http-password-mgr` for information on the interface that must + be supported. HTTPBasicAuthHandler will raise a :exc:`ValueError` when + presented with a wrong Authentication scheme. .. class:: ProxyBasicAuthHandler(password_mgr=None) @@ -265,10 +266,19 @@ .. class:: HTTPDigestAuthHandler(password_mgr=None) - Handle authentication with the remote host. *password_mgr*, if given, should be - something that is compatible with :class:`HTTPPasswordMgr`; refer to section - :ref:`http-password-mgr` for information on the interface that must be - supported. + Handle authentication with the remote host. *password_mgr*, if given, should + be something that is compatible with :class:`HTTPPasswordMgr`; refer to + section :ref:`http-password-mgr` for information on the interface that must + be supported. When both Digest Authentication Handler and Basic + Authentication Handler are both added, Digest Authentication is always tried + first. If the Digest Authentication returns a 40x response again, it is sent + to Basic Authentication handler to Handle. This Handler method will raise a + :exc:`ValueError` when presented with an authentication scheme other than + Digest or Basic. + + ..versionchanged:: 3.3 + Raise ValueError on unsupported Authentication Scheme. + .. class:: ProxyDigestAuthHandler(password_mgr=None) diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -5,6 +5,7 @@ import io import socket import array +import sys import urllib.request # The proxy bypass method imported below has logic specific to the OSX @@ -1162,6 +1163,8 @@ self.assertEqual(req.get_host(), "proxy.example.com:3128") self.assertEqual(req.get_header("Proxy-authorization"),"FooBar") + # TODO: This should be only for OSX + @unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX") def test_osx_proxy_bypass(self): bypass = { 'exclude_simple': False, @@ -1265,6 +1268,26 @@ # _test_basic_auth called .open() twice) self.assertEqual(opener.recorded, ["digest", "basic"]*2) + def test_unsupported_auth_digest_handler(self): + opener = OpenerDirector() + # While using DigestAuthHandler + digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None) + http_handler = MockHTTPHandler( + 401, 'WWW-Authenticate: Kerberos\r\n\r\n') + opener.add_handler(digest_auth_handler) + opener.add_handler(http_handler) + self.assertRaises(ValueError,opener.open,"http://www.example.com") + + def test_unsupported_auth_basic_handler(self): + # While using BasicAuthHandler + opener = OpenerDirector() + basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None) + http_handler = MockHTTPHandler( + 401, 'WWW-Authenticate: NTLM\r\n\r\n') + opener.add_handler(basic_auth_handler) + opener.add_handler(http_handler) + self.assertRaises(ValueError,opener.open,"http://www.example.com") + def _test_basic_auth(self, opener, auth_handler, auth_header, realm, http_handler, password_manager, request_url, protected_url): @@ -1302,6 +1325,7 @@ self.assertEqual(len(http_handler.requests), 1) self.assertFalse(http_handler.requests[0].has_header(auth_header)) + class MiscTests(unittest.TestCase): def test_build_opener(self): diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -825,14 +825,20 @@ self.retried += 1 if authreq: - mo = AbstractBasicAuthHandler.rx.search(authreq) - if mo: - scheme, quote, realm = mo.groups() - if scheme.lower() == 'basic': - response = self.retry_http_basic_auth(host, req, realm) - if response and response.code != 401: - self.retried = 0 - return response + scheme = authreq.split()[0] + if not scheme.lower() == 'basic': + raise ValueError("AbstractBasicAuthHandler does not" + " support the following scheme: '%s'" % + scheme) + else: + mo = AbstractBasicAuthHandler.rx.search(authreq) + if mo: + scheme, quote, realm = mo.groups() + if scheme.lower() == 'basic': + response = self.retry_http_basic_auth(host, req, realm) + if response and response.code != 401: + self.retried = 0 + return response def retry_http_basic_auth(self, host, req, realm): user, pw = self.passwd.find_user_password(realm, host) @@ -918,6 +924,9 @@ scheme = authreq.split()[0] if scheme.lower() == 'digest': return self.retry_http_digest_auth(req, authreq) + elif not scheme.lower() == 'basic': + raise ValueError("AbstractDigestAuthHandler does not support" + " the following scheme: '%s'" % scheme) def retry_http_digest_auth(self, req, auth): token, challenge = auth.split(' ', 1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -143,6 +143,10 @@ Library ------- +- Issue #11799: urllib.request Authentication Handlers will raise a ValueError + when presented with an unsupported Authentication Scheme. Patch contributed + by Yuval Greenfield. + - Issue #10419, #6011: build_scripts command of distutils handles correctly non-ASCII path (path to the Python executable). Open and write the script in binary mode, but ensure that the shebang is decodable from UTF-8 and from the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 16:27:38 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 11 May 2011 16:27:38 +0200 Subject: [Python-checkins] cpython: Fix closed Issue #11968 - the start_response header values in wsgiref shoudl be Message-ID: http://hg.python.org/cpython/rev/e7c62e0981c7 changeset: 70034:e7c62e0981c7 user: Senthil Kumaran date: Wed May 11 22:27:26 2011 +0800 summary: Fix closed Issue #11968 - the start_response header values in wsgiref shoudl be str not bytes. The PEP-0333 says that and test_wsgiref follows the same. Updated docs accordingly. files: Doc/library/wsgiref.rst | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -122,8 +122,8 @@ def simple_app(environ, start_response): setup_testing_defaults(environ) - status = b'200 OK' - headers = [(b'Content-type', b'text/plain; charset=utf-8')] + status = '200 OK' + headers = [('Content-type', 'text/plain; charset=utf-8')] start_response(status, headers) @@ -414,8 +414,8 @@ # Our callable object which is intentionally not compliant to the # standard, so the validator is going to break def simple_app(environ, start_response): - status = b'200 OK' # HTTP Status - headers = [(b'Content-type', b'text/plain')] # HTTP Headers + status = '200 OK' # HTTP Status + headers = [('Content-type', 'text/plain')] # HTTP Headers start_response(status, headers) # This is going to break because we need to return a list, and @@ -754,8 +754,8 @@ # is a dictionary containing CGI-style envrironment variables and the # second variable is the callable object (see PEP 333). def hello_world_app(environ, start_response): - status = b'200 OK' # HTTP Status - headers = [(b'Content-type', b'text/plain; charset=utf-8')] # HTTP Headers + status = '200 OK' # HTTP Status + headers = [('Content-type', 'text/plain; charset=utf-8')] # HTTP Headers start_response(status, headers) # The returned object is going to be printed -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 16:38:03 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 11 May 2011 16:38:03 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11968 - the start_response header values in wsgiref shoudl be str not Message-ID: http://hg.python.org/cpython/rev/5add0c01933f changeset: 70035:5add0c01933f branch: 3.2 parent: 70029:af18b150065e user: Senthil Kumaran date: Wed May 11 22:34:59 2011 +0800 summary: Issue #11968 - the start_response header values in wsgiref shoudl be str not bytes. The PEP-0333 says that and test_wsgiref follows the same. Updated docs accordingly. files: Doc/library/wsgiref.rst | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -122,8 +122,8 @@ def simple_app(environ, start_response): setup_testing_defaults(environ) - status = b'200 OK' - headers = [(b'Content-type', b'text/plain; charset=utf-8')] + status = '200 OK' + headers = [('Content-type', 'text/plain; charset=utf-8')] start_response(status, headers) @@ -414,8 +414,8 @@ # Our callable object which is intentionally not compliant to the # standard, so the validator is going to break def simple_app(environ, start_response): - status = b'200 OK' # HTTP Status - headers = [(b'Content-type', b'text/plain')] # HTTP Headers + status = '200 OK' # HTTP Status + headers = [('Content-type', 'text/plain')] # HTTP Headers start_response(status, headers) # This is going to break because we need to return a list, and @@ -754,8 +754,8 @@ # is a dictionary containing CGI-style envrironment variables and the # second variable is the callable object (see PEP 333). def hello_world_app(environ, start_response): - status = b'200 OK' # HTTP Status - headers = [(b'Content-type', b'text/plain; charset=utf-8')] # HTTP Headers + status = '200 OK' # HTTP Status + headers = [('Content-type', 'text/plain; charset=utf-8')] # HTTP Headers start_response(status, headers) # The returned object is going to be printed -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 16:38:04 2011 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 11 May 2011 16:38:04 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): [Merge Branch] Issue #11968 - the start_response header values in wsgiref Message-ID: http://hg.python.org/cpython/rev/482f60d6a687 changeset: 70036:482f60d6a687 parent: 70034:e7c62e0981c7 parent: 70035:5add0c01933f user: Senthil Kumaran date: Wed May 11 22:37:50 2011 +0800 summary: [Merge Branch] Issue #11968 - the start_response header values in wsgiref shoudl be str not bytes. The PEP-0333 says that and test_wsgiref follows the same. Updated docs accordingly. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 19:48:13 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 11 May 2011 19:48:13 +0200 Subject: [Python-checkins] cpython (3.2): Document default fmtspec. Fix inaccurate note. Document exceptions. Message-ID: http://hg.python.org/cpython/rev/65f8a084220f changeset: 70037:65f8a084220f branch: 3.2 parent: 70035:5add0c01933f user: Raymond Hettinger date: Wed May 11 10:47:27 2011 -0700 summary: Document default fmtspec. Fix inaccurate note. Document exceptions. files: Doc/library/functions.rst | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -498,11 +498,14 @@ of the *value* argument, however there is a standard formatting syntax that is used by most built-in types: :ref:`formatspec`. - .. note:: + The default *format_spec* is an empty string which usually gives the same + effect as calling ``str(value)``. - ``format(value, format_spec)`` merely calls - ``value.__format__(format_spec)``. - + A call to ``format(value, format_spec)`` is translated to + ``type(value).__format__(format_spec)`` which bypasses the instance + dictionary when searching for the value's :meth:`__format__` method. A + :exc:`TypeError` exception is raised if the method is not found or if either + the *format_spec* or the return value are not strings. .. function:: frozenset([iterable]) :noindex: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 19:48:14 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 11 May 2011 19:48:14 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Document default fmtspec. Fix inaccurate note. Document exceptions. Message-ID: http://hg.python.org/cpython/rev/a85cf047f56a changeset: 70038:a85cf047f56a parent: 70036:482f60d6a687 parent: 70037:65f8a084220f user: Raymond Hettinger date: Wed May 11 10:48:02 2011 -0700 summary: Document default fmtspec. Fix inaccurate note. Document exceptions. files: Doc/library/functions.rst | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -498,11 +498,14 @@ of the *value* argument, however there is a standard formatting syntax that is used by most built-in types: :ref:`formatspec`. - .. note:: + The default *format_spec* is an empty string which usually gives the same + effect as calling ``str(value)``. - ``format(value, format_spec)`` merely calls - ``value.__format__(format_spec)``. - + A call to ``format(value, format_spec)`` is translated to + ``type(value).__format__(format_spec)`` which bypasses the instance + dictionary when searching for the value's :meth:`__format__` method. A + :exc:`TypeError` exception is raised if the method is not found or if either + the *format_spec* or the return value are not strings. .. function:: frozenset([iterable]) :noindex: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 20:19:42 2011 From: python-checkins at python.org (kurt.kaiser) Date: Wed, 11 May 2011 20:19:42 +0200 Subject: [Python-checkins] cpython (3.1): Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. Message-ID: http://hg.python.org/cpython/rev/82cfbe2ddfbb changeset: 70039:82cfbe2ddfbb branch: 3.1 parent: 70028:fd7d4639dae2 user: Kurt B. Kaiser date: Wed May 11 12:24:17 2011 -0400 summary: Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused IDLE to exit. Converted to valid Unicode null in PythonCmd(). files: Lib/idlelib/NEWS.txt | 9 ++++++--- Misc/NEWS | 4 ++++ Modules/_tkinter.c | 14 +++++++++++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,18 +1,21 @@ What's New in IDLE 3.1.4? ========================= -*Release date: XX-XXX-XX* +*Release date: 15-May-11* + +- Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. + Tk < 8.5 was sending invalid Unicode null; replaced with valid null. - toggle failing on Tk 8.5, causing IDLE exits and strange selection behavior. Issue 4676. Improve selection extension behaviour. + - toggle non-functional when NumLock set on Windows. Issue 3851. - What's New in IDLE 3.1b1? ========================= -*Release date: XX-XXX-09* +*Release date: 06-May-09* - Use of 'filter' in keybindingDialog.py was causing custom key assignment to fail. Patch 5707 amaury.forgeotdarc. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,10 @@ Library ------- +- Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. + With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused + IDLE to exit. Converted to valid Unicode null in PythonCmd(). + - Issue #10419: Fix build_scripts command of distutils to handle correctly non-ASCII scripts. Open and write the script in binary mode, but ensure that the shebang is decodable from UTF-8 and from the encoding of the script. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -2023,7 +2023,19 @@ for (i = 0; i < (argc - 1); i++) { PyObject *s = PyUnicode_FromString(argv[i + 1]); - if (!s || PyTuple_SetItem(arg, i, s)) { + if (!s) { + /* Is Tk leaking 0xC080 in %A - a "modified" utf-8 null? */ + if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError) && + !strcmp(argv[i + 1], "\xC0\x80")) { + PyErr_Clear(); + /* Convert to "strict" utf-8 null */ + s = PyUnicode_FromString("\0"); + } else { + Py_DECREF(arg); + return PythonCmd_Error(interp); + } + } + if (PyTuple_SetItem(arg, i, s)) { Py_DECREF(arg); return PythonCmd_Error(interp); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 20:19:55 2011 From: python-checkins at python.org (kurt.kaiser) Date: Wed, 11 May 2011 20:19:55 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/65a6a2f8721f changeset: 70040:65a6a2f8721f branch: 3.2 parent: 70035:5add0c01933f parent: 70039:82cfbe2ddfbb user: Kurt B. Kaiser date: Wed May 11 13:48:54 2011 -0400 summary: Merge from 3.1 files: Lib/idlelib/NEWS.txt | 9 ++++++--- Misc/NEWS | 3 +++ Modules/_tkinter.c | 14 +++++++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,18 +1,21 @@ What's New in IDLE 3.1.4? ========================= -*Release date: XX-XXX-XX* +*Release date: 15-May-11* + +- Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. + Tk < 8.5 was sending invalid Unicode null; replaced with valid null. - toggle failing on Tk 8.5, causing IDLE exits and strange selection behavior. Issue 4676. Improve selection extension behaviour. + - toggle non-functional when NumLock set on Windows. Issue 3851. - What's New in IDLE 3.1b1? ========================= -*Release date: 27-Jun-09* +*Release date: 06-May-09* - Use of 'filter' in keybindingDialog.py was causing custom key assignment to fail. Patch 5707 amaury.forgeotdarc. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -85,6 +85,9 @@ Library ------- +- Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. + With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused + IDLE to exit. Converted to valid Unicode null in PythonCmd(). - Issue #11169: compileall module uses repr() to format filenames and paths to escape surrogate characters and show spaces. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -2023,7 +2023,19 @@ for (i = 0; i < (argc - 1); i++) { PyObject *s = PyUnicode_FromString(argv[i + 1]); - if (!s || PyTuple_SetItem(arg, i, s)) { + if (!s) { + /* Is Tk leaking 0xC080 in %A - a "modified" utf-8 null? */ + if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError) && + !strcmp(argv[i + 1], "\xC0\x80")) { + PyErr_Clear(); + /* Convert to "strict" utf-8 null */ + s = PyUnicode_FromString("\0"); + } else { + Py_DECREF(arg); + return PythonCmd_Error(interp); + } + } + if (PyTuple_SetItem(arg, i, s)) { Py_DECREF(arg); return PythonCmd_Error(interp); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 20:20:10 2011 From: python-checkins at python.org (kurt.kaiser) Date: Wed, 11 May 2011 20:20:10 +0200 Subject: [Python-checkins] cpython (3.2): Correct version in IDLE NEWS.txt Message-ID: http://hg.python.org/cpython/rev/b3ed068ded18 changeset: 70041:b3ed068ded18 branch: 3.2 user: Kurt B. Kaiser date: Wed May 11 13:54:44 2011 -0400 summary: Correct version in IDLE NEWS.txt files: Lib/idlelib/NEWS.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,4 +1,4 @@ -What's New in IDLE 3.1.4? +What's New in IDLE 3.2.1? ========================= *Release date: 15-May-11* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 20:20:11 2011 From: python-checkins at python.org (kurt.kaiser) Date: Wed, 11 May 2011 20:20:11 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): Merge heads Message-ID: http://hg.python.org/cpython/rev/0d9837985725 changeset: 70042:0d9837985725 branch: 3.2 parent: 70041:b3ed068ded18 parent: 70037:65f8a084220f user: Kurt B. Kaiser date: Wed May 11 14:02:13 2011 -0400 summary: Merge heads files: Doc/library/functions.rst | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -498,11 +498,14 @@ of the *value* argument, however there is a standard formatting syntax that is used by most built-in types: :ref:`formatspec`. - .. note:: + The default *format_spec* is an empty string which usually gives the same + effect as calling ``str(value)``. - ``format(value, format_spec)`` merely calls - ``value.__format__(format_spec)``. - + A call to ``format(value, format_spec)`` is translated to + ``type(value).__format__(format_spec)`` which bypasses the instance + dictionary when searching for the value's :meth:`__format__` method. A + :exc:`TypeError` exception is raised if the method is not found or if either + the *format_spec* or the return value are not strings. .. function:: frozenset([iterable]) :noindex: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 20:20:13 2011 From: python-checkins at python.org (kurt.kaiser) Date: Wed, 11 May 2011 20:20:13 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/5c4f68128680 changeset: 70043:5c4f68128680 parent: 70038:a85cf047f56a parent: 70042:0d9837985725 user: Kurt B. Kaiser date: Wed May 11 14:18:13 2011 -0400 summary: Merge from 3.2 files: Lib/idlelib/NEWS.txt | 11 +++++++---- Misc/NEWS | 3 +++ Modules/_tkinter.c | 14 +++++++++++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,18 +1,21 @@ -What's New in IDLE 3.1.4? +What's New in IDLE 3.2.1? ========================= -*Release date: XX-XXX-XX* +*Release date: 15-May-11* + +- Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. + Tk < 8.5 was sending invalid Unicode null; replaced with valid null. - toggle failing on Tk 8.5, causing IDLE exits and strange selection behavior. Issue 4676. Improve selection extension behaviour. + - toggle non-functional when NumLock set on Windows. Issue 3851. - What's New in IDLE 3.1b1? ========================= -*Release date: 27-Jun-09* +*Release date: 06-May-09* - Use of 'filter' in keybindingDialog.py was causing custom key assignment to fail. Patch 5707 amaury.forgeotdarc. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -142,6 +142,9 @@ Library ------- +- Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. + With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused + IDLE to exit. Converted to valid Unicode null in PythonCmd(). - Issue #11799: urllib.request Authentication Handlers will raise a ValueError when presented with an unsupported Authentication Scheme. Patch contributed diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -2022,7 +2022,19 @@ for (i = 0; i < (argc - 1); i++) { PyObject *s = PyUnicode_FromString(argv[i + 1]); - if (!s || PyTuple_SetItem(arg, i, s)) { + if (!s) { + /* Is Tk leaking 0xC080 in %A - a "modified" utf-8 null? */ + if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError) && + !strcmp(argv[i + 1], "\xC0\x80")) { + PyErr_Clear(); + /* Convert to "strict" utf-8 null */ + s = PyUnicode_FromString("\0"); + } else { + Py_DECREF(arg); + return PythonCmd_Error(interp); + } + } + if (PyTuple_SetItem(arg, i, s)) { Py_DECREF(arg); return PythonCmd_Error(interp); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 11 20:58:01 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 May 2011 20:58:01 +0200 Subject: [Python-checkins] cpython: Issue #12058: Minor edits to comments in faulthandler Message-ID: http://hg.python.org/cpython/rev/5f407b5479f5 changeset: 70044:5f407b5479f5 user: Victor Stinner date: Wed May 11 20:56:08 2011 +0200 summary: Issue #12058: Minor edits to comments in faulthandler Patch written by ?ric Araujo. files: Modules/faulthandler.c | 36 +++++++++++++++--------------- 1 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -53,8 +53,8 @@ int exit; char *header; size_t header_len; - /* The main thread always hold this lock. It is only released when - faulthandler_thread() is interrupted until this thread exits, or at + /* The main thread always holds this lock. It is only released when + faulthandler_thread() is interrupted before this thread exits, or at Python exit. */ PyThread_type_lock cancel_event; /* released by child thread when joined */ @@ -218,18 +218,18 @@ } -/* Handler of SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals. +/* Handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals. Display the current Python traceback, restore the previous handler and call the previous handler. - On Windows, don't call explictly the previous handler, because Windows + On Windows, don't explicitly call the previous handler, because the Windows signal handler would not be called (for an unknown reason). The execution of the program continues at faulthandler_fatal_error() exit, but the same instruction will raise the same fault (signal), and so the previous handler will be called. - This function is signal safe and should only call signal safe functions. */ + This function is signal-safe and should only call signal-safe functions. */ static void faulthandler_fatal_error(int signum) @@ -267,7 +267,7 @@ #ifdef WITH_THREAD /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and - so are delivered to the thread that caused the fault. Get the Python + are thus delivered to the thread that caused the fault. Get the Python thread state of the current thread. PyThreadState_Get() doesn't give the state of the thread that caused the @@ -289,7 +289,7 @@ errno = save_errno; #ifdef MS_WINDOWS if (signum == SIGSEGV) { - /* don't call explictly the previous handler for SIGSEGV in this signal + /* don't explicitly call the previous handler for SIGSEGV in this signal handler, because the Windows signal handler would not be called */ return; } @@ -457,7 +457,7 @@ static void cancel_dump_tracebacks_later(void) { - /* notify cancellation */ + /* Notify cancellation */ PyThread_release_lock(thread.cancel_event); /* Wait for thread to join */ @@ -580,7 +580,7 @@ cancel_dump_tracebacks_later(); Py_RETURN_NONE; } -#endif /* FAULTHANDLER_LATER */ +#endif /* FAULTHANDLER_LATER */ #ifdef FAULTHANDLER_USER /* Handler of user signals (e.g. SIGUSR1). @@ -781,7 +781,7 @@ #if defined(MS_WINDOWS) /* For SIGSEGV, faulthandler_fatal_error() restores the previous signal handler and then gives back the execution flow to the program (without - calling explicitly the previous error handler). In a normal case, the + explicitly calling the previous error handler). In a normal case, the SIGSEGV was raised by the kernel because of a fault, and so if the program retries to execute the same instruction, the fault will be raised again. @@ -805,11 +805,11 @@ PowerPC. Use volatile to disable compile-time optimizations. */ volatile int x = 1, y = 0, z; z = x / y; - /* if the division by zero didn't raise a SIGFPE (e.g. on PowerPC), - raise it manually */ + /* If the division by zero didn't raise a SIGFPE (e.g. on PowerPC), + raise it manually. */ raise(SIGFPE); - /* use z to make quiet a compiler warning, but this line - is never reached */ + /* This line is never reached, but we pretend to make something with z + to silence a compiler warning. */ return PyLong_FromLong(z); } @@ -977,14 +977,14 @@ {"_stack_overflow", (PyCFunction)faulthandler_stack_overflow, METH_NOARGS, PyDoc_STR("_stack_overflow(): recursive call to raise a stack overflow")}, #endif - {NULL, NULL} /* terminator */ + {NULL, NULL} /* sentinel */ }; static struct PyModuleDef module_def = { PyModuleDef_HEAD_INIT, "faulthandler", module_doc, - 0, /* non negative size to be able to unload the module */ + 0, /* non-negative size to be able to unload the module */ module_methods, NULL, faulthandler_traverse, @@ -998,8 +998,8 @@ return PyModule_Create(&module_def); } -/* Call faulthandler.enable() if PYTHONFAULTHANDLER environment variable is - defined, or if sys._xoptions has a 'faulthandler' key. */ +/* Call faulthandler.enable() if the PYTHONFAULTHANDLER environment variable + is defined, or if sys._xoptions has a 'faulthandler' key. */ static int faulthandler_env_options(void) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 00:11:13 2011 From: python-checkins at python.org (ezio.melotti) Date: Thu, 12 May 2011 00:11:13 +0200 Subject: [Python-checkins] cpython: Fix markup and working in the doc. Message-ID: http://hg.python.org/cpython/rev/3e7c2afd0c16 changeset: 70045:3e7c2afd0c16 user: Ezio Melotti date: Thu May 12 01:10:57 2011 +0300 summary: Fix markup and working in the doc. files: Doc/library/http.server.rst | 16 +++++++++------- Doc/library/urllib.request.rst | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -185,11 +185,12 @@ are picked up from the :meth:`version_string` and :meth:`date_time_string` methods, respectively. If the server does not intend to send any other headers using the :meth:`send_header` method, - then send_response should be followed by a :meth:`end_headers` call. + then :meth:`send_response` should be followed by a :meth:`end_headers` + call. - ..versionchanged:: 3.3 - Writing of headers to internal buffer and need to call - :meth:`end_headers` explicitly. + .. versionchanged:: 3.3 + Headers are stored to an internal buffer and :meth:`end_headers` + needs to be called explicitly. .. method:: send_header(keyword, value) @@ -200,7 +201,7 @@ specifying its value. Note that, after the send_header calls are done, :meth:`end_headers` MUST BE called in order to complete the operation. - .. versionchanged:: 3.2 Storing the headers in an internal buffer + .. versionchanged:: 3.2 Headers are stored in an internal buffer. .. method:: send_response_only(code, message=None) @@ -216,9 +217,10 @@ Adds a blank line (indicating the end of the HTTP headers in the response) - to the headers buffer and calls :meth:`flush_headers()` + to the headers buffer and calls :meth:`flush_headers()`. - .. versionchanged:: 3.2 Writing the buffered headers to the output stream. + .. versionchanged:: 3.2 + The buffered headers are written to the output stream. .. method:: flush_headers() diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -276,8 +276,8 @@ :exc:`ValueError` when presented with an authentication scheme other than Digest or Basic. - ..versionchanged:: 3.3 - Raise ValueError on unsupported Authentication Scheme. + .. versionchanged:: 3.3 + Raise :exc:`ValueError` on unsupported Authentication Scheme. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 01:59:49 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 May 2011 01:59:49 +0200 Subject: [Python-checkins] cpython: Issue #9971: Write an optimized implementation of BufferedReader.readinto(). Message-ID: http://hg.python.org/cpython/rev/a1d77c6f4ec1 changeset: 70046:a1d77c6f4ec1 user: Antoine Pitrou date: Thu May 12 01:57:53 2011 +0200 summary: Issue #9971: Write an optimized implementation of BufferedReader.readinto(). Patch by John O'Connor. files: Lib/test/test_io.py | 6 + Misc/ACKS | 1 + Misc/NEWS | 4 + Modules/_io/bufferedio.c | 86 ++++++++++++++++++++++----- 4 files changed, 81 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -794,6 +794,12 @@ self.assertEqual(b, b"gf") self.assertEqual(bufio.readinto(b), 0) self.assertEqual(b, b"gf") + rawio = self.MockRawIO((b"abc", None)) + bufio = self.tp(rawio) + self.assertEqual(bufio.readinto(b), 2) + self.assertEqual(b, b"ab") + self.assertEqual(bufio.readinto(b), 1) + self.assertEqual(b, b"cb") def test_readlines(self): def bufio(): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -645,6 +645,7 @@ Michal Nowikowski Steffen Daode Nurpmeso Nigel O'Brian +John O'Connor Kevin O'Connor Tim O'Malley Pascal Oberndoerfer diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -142,6 +142,10 @@ Library ------- + +- Issue #9971: Write an optimized implementation of BufferedReader.readinto(). + Patch by John O'Connor. + - Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused IDLE to exit. Converted to valid Unicode null in PythonCmd(). diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1,9 +1,9 @@ /* An implementation of Buffered I/O as defined by PEP 3116 - "New I/O" - + Classes defined here: BufferedIOBase, BufferedReader, BufferedWriter, BufferedRandom. - + Written by Amaury Forgeot d'Arc and Antoine Pitrou */ @@ -198,7 +198,7 @@ int readable; int writable; int deallocating; - + /* True if this is a vanilla Buffered object (rather than a user derived class) *and* the raw stream is a vanilla FileIO object. */ int fast_closed_checks; @@ -237,7 +237,7 @@ /* Implementation notes: - + * BufferedReader, BufferedWriter and BufferedRandom try to share most methods (this is helped by the members `readable` and `writable`, which are initialized in the respective constructors) @@ -255,7 +255,7 @@ NOTE: we should try to maintain block alignment of reads and writes to the raw stream (according to the buffer size), but for now it is only done in read() and friends. - + */ /* These macros protect the buffered object against concurrent operations. */ @@ -596,7 +596,8 @@ _bufferedreader_read_fast(buffered *self, Py_ssize_t); static PyObject * _bufferedreader_read_generic(buffered *self, Py_ssize_t); - +static Py_ssize_t +_bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len); /* * Helpers @@ -635,7 +636,7 @@ if (!PyErr_Occurred()) PyErr_Format(PyExc_IOError, "Raw stream returned invalid position %" PY_PRIdOFF, - (PY_OFF_T_COMPAT)n); + (PY_OFF_T_COMPAT)n); return -1; } self->abs_pos = n; @@ -668,7 +669,7 @@ if (!PyErr_Occurred()) PyErr_Format(PyExc_IOError, "Raw stream returned invalid position %" PY_PRIdOFF, - (PY_OFF_T_COMPAT)n); + (PY_OFF_T_COMPAT)n); return -1; } self->abs_pos = n; @@ -863,7 +864,7 @@ if (!ENTER_BUFFERED(self)) return NULL; - + if (self->writable) { res = _bufferedwriter_flush_unlocked(self, 1); if (res == NULL) @@ -912,23 +913,75 @@ static PyObject * buffered_readinto(buffered *self, PyObject *args) { + Py_buffer buf; + Py_ssize_t n, written = 0, remaining; PyObject *res = NULL; CHECK_INITIALIZED(self) - - /* TODO: use raw.readinto() instead! */ + + if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) + return NULL; + + n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); + if (n > 0) { + if (n >= buf.len) { + memcpy(buf.buf, self->buffer + self->pos, buf.len); + self->pos += buf.len; + res = PyLong_FromSsize_t(buf.len); + goto end_unlocked; + } + memcpy(buf.buf, self->buffer + self->pos, n); + self->pos += n; + written = n; + } + + if (!ENTER_BUFFERED(self)) + goto end_unlocked; + if (self->writable) { - if (!ENTER_BUFFERED(self)) - return NULL; res = _bufferedwriter_flush_unlocked(self, 0); - LEAVE_BUFFERED(self) if (res == NULL) goto end; - Py_DECREF(res); + Py_CLEAR(res); } - res = bufferediobase_readinto((PyObject *)self, args); + + _bufferedreader_reset_buf(self); + self->pos = 0; + + for (remaining = buf.len - written; + remaining > 0; + written += n, remaining -= n) { + /* If remaining bytes is larger than internal buffer size, copy + * directly into caller's buffer. */ + if (remaining > self->buffer_size) { + n = _bufferedreader_raw_read(self, buf.buf + written, remaining); + } + else { + n = _bufferedreader_fill_buffer(self); + if (n > 0) { + if (n > remaining) + n = remaining; + memcpy(buf.buf + written, self->buffer + self->pos, n); + self->pos += n; + continue; /* short circuit */ + } + } + if (n == 0 || (n == -2 && written > 0)) + break; + if (n < 0) { + if (n == -2) { + Py_INCREF(Py_None); + res = Py_None; + } + goto end; + } + } + res = PyLong_FromSsize_t(written); end: + LEAVE_BUFFERED(self); +end_unlocked: + PyBuffer_Release(&buf); return res; } @@ -1573,6 +1626,7 @@ {"read", (PyCFunction)buffered_read, METH_VARARGS}, {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, {"read1", (PyCFunction)buffered_read1, METH_VARARGS}, + {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS}, {"readline", (PyCFunction)buffered_readline, METH_VARARGS}, {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 02:07:04 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 May 2011 02:07:04 +0200 Subject: [Python-checkins] cpython: Fix compile error under Windows Message-ID: http://hg.python.org/cpython/rev/eb1b93fd68f5 changeset: 70047:eb1b93fd68f5 user: Antoine Pitrou date: Thu May 12 02:07:00 2011 +0200 summary: Fix compile error under Windows files: Modules/_io/bufferedio.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -954,14 +954,16 @@ /* If remaining bytes is larger than internal buffer size, copy * directly into caller's buffer. */ if (remaining > self->buffer_size) { - n = _bufferedreader_raw_read(self, buf.buf + written, remaining); + n = _bufferedreader_raw_read(self, (char *) buf.buf + written, + remaining); } else { n = _bufferedreader_fill_buffer(self); if (n > 0) { if (n > remaining) n = remaining; - memcpy(buf.buf + written, self->buffer + self->pos, n); + memcpy((char *) buf.buf + written, + self->buffer + self->pos, n); self->pos += n; continue; /* short circuit */ } -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu May 12 04:59:22 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 12 May 2011 04:59:22 +0200 Subject: [Python-checkins] Daily reference leaks (eb1b93fd68f5): sum=0 Message-ID: results for eb1b93fd68f5 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloguYCfxL', '-x'] From python-checkins at python.org Thu May 12 06:42:22 2011 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 12 May 2011 06:42:22 +0200 Subject: [Python-checkins] cpython: - Issue #12044: Fixed subprocess.Popen when used as a context manager to Message-ID: http://hg.python.org/cpython/rev/7a3f3ad83676 changeset: 70048:7a3f3ad83676 user: Gregory P. Smith date: Wed May 11 21:42:08 2011 -0700 summary: - Issue #12044: Fixed subprocess.Popen when used as a context manager to wait for the process to end when exiting the context to avoid unintentionally leaving zombie processes around. files: Doc/library/subprocess.rst | 4 ++-- Lib/subprocess.py | 2 ++ Lib/test/test_subprocess.py | 3 ++- Misc/NEWS | 4 ++++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -219,8 +219,8 @@ *creationflags*, if given, can be :data:`CREATE_NEW_CONSOLE` or :data:`CREATE_NEW_PROCESS_GROUP`. (Windows only) - Popen objects are supported as context managers via the :keyword:`with` statement, - closing any open file descriptors on exit. + Popen objects are supported as context managers via the :keyword:`with` statement: + on exit, standard file descriptors are closed, and the process is waited for. :: with Popen(["ifconfig"], stdout=PIPE) as proc: diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -796,6 +796,8 @@ self.stderr.close() if self.stdin: self.stdin.close() + # Wait for the process to terminate, to avoid zombies. + self.wait() def __del__(self, _maxsize=sys.maxsize, _active=_active): if not self._child_created: diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1590,7 +1590,8 @@ def test_returncode(self): with subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(100)"]) as proc: - proc.wait() + pass + # __exit__ calls wait(), so the returncode should be set self.assertEqual(proc.returncode, 100) def test_communicate_stdin(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #12044: Fixed subprocess.Popen when used as a context manager to + wait for the process to end when exiting the context to avoid unintentionally + leaving zombie processes around. + - Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, clear the end-of-file indicator after CTRL+d. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 07:20:57 2011 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 12 May 2011 07:20:57 +0200 Subject: [Python-checkins] cpython (3.2): merge - 7a3f3ad83676 Fixes Issue #12044. Message-ID: http://hg.python.org/cpython/rev/b00a64a5cb93 changeset: 70049:b00a64a5cb93 branch: 3.2 parent: 70042:0d9837985725 user: Gregory P. Smith date: Wed May 11 22:18:23 2011 -0700 summary: merge - 7a3f3ad83676 Fixes Issue #12044. files: Doc/library/subprocess.rst | 4 ++-- Lib/subprocess.py | 2 ++ Lib/test/test_subprocess.py | 3 ++- Misc/NEWS | 4 ++++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -217,8 +217,8 @@ *creationflags*, if given, can be :data:`CREATE_NEW_CONSOLE` or :data:`CREATE_NEW_PROCESS_GROUP`. (Windows only) - Popen objects are supported as context managers via the :keyword:`with` statement, - closing any open file descriptors on exit. + Popen objects are supported as context managers via the :keyword:`with` statement: + on exit, standard file descriptors are closed, and the process is waited for. :: with Popen(["ifconfig"], stdout=PIPE) as proc: diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -764,6 +764,8 @@ self.stderr.close() if self.stdin: self.stdin.close() + # Wait for the process to terminate, to avoid zombies. + self.wait() def __del__(self, _maxsize=sys.maxsize, _active=_active): if not self._child_created: diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1491,7 +1491,8 @@ def test_returncode(self): with subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(100)"]) as proc: - proc.wait() + pass + # __exit__ calls wait(), so the returncode should be set self.assertEqual(proc.returncode, 100) def test_communicate_stdin(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #12044: Fixed subprocess.Popen when used as a context manager to + wait for the process to end when exiting the context to avoid unintentionally + leaving zombie processes around. + - Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, clear the end-of-file indicator after CTRL+d. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 07:20:58 2011 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 12 May 2011 07:20:58 +0200 Subject: [Python-checkins] cpython (3.2): normalize whitespace. Message-ID: http://hg.python.org/cpython/rev/654d473f2951 changeset: 70050:654d473f2951 branch: 3.2 user: Gregory P. Smith date: Wed May 11 22:20:11 2011 -0700 summary: normalize whitespace. files: Lib/subprocess.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -419,7 +419,7 @@ STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE, SW_HIDE, STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) - + __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", "STD_ERROR_HANDLE", "SW_HIDE", -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 07:47:10 2011 From: python-checkins at python.org (georg.brandl) Date: Thu, 12 May 2011 07:47:10 +0200 Subject: [Python-checkins] cpython (2.7): #12061: remove duplicate glossary entry. Message-ID: http://hg.python.org/cpython/rev/534a9e274d88 changeset: 70051:534a9e274d88 branch: 2.7 parent: 70020:a21f5af476cb user: Georg Brandl date: Thu May 12 07:47:06 2011 +0200 summary: #12061: remove duplicate glossary entry. files: Doc/glossary.rst | 20 -------------------- 1 files changed, 0 insertions(+), 20 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -392,26 +392,6 @@ value is assigned. ``**`` is used to accept or pass a dictionary of keyword arguments. See :term:`argument`. - key function - A key function or collation function is a callable that returns a value - used for sorting or ordering. For example, :func:`locale.strxfrm` is - used to produce a sort key that is aware of locale specific sort - conventions. - - A number of tools in Python accept key functions to control how elements - are ordered or grouped. They include :func:`min`, :func:`max`, - :func:`sorted`, :meth:`list.sort`, :func:`heapq.nsmallest`, - :func:`heapq.nlargest`, and :func:`itertools.groupby`. - - There are several ways to create a key function. For example. the - :meth:`str.lower` method can serve as a key function for case insensitive - sorts. Alternatively, an ad-hoc key function can be built from a - :keyword:`lambda` expression such as ``lambda r: (r[0], r[2])``. Also, - the :mod:`operator` module provides three key function constuctors: - :func:`~operator.attrgetter`, :func:`~operator.itemgetter`, and - :func:`~operator.methodcaller`. See the :ref:`sortinghowto` for - examples of how to create and use key functions. - lambda An anonymous inline function consisting of a single :term:`expression` which is evaluated when the function is called. The syntax to create -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 16:48:26 2011 From: python-checkins at python.org (lukasz.langa) Date: Thu, 12 May 2011 16:48:26 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Cleaned up a backward merge after fixes issue #12044. Message-ID: http://hg.python.org/cpython/rev/361f87c8f36a changeset: 70052:361f87c8f36a parent: 70048:7a3f3ad83676 parent: 70050:654d473f2951 user: ?ukasz Langa date: Thu May 12 16:46:30 2011 +0200 summary: Cleaned up a backward merge after fixes issue #12044. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 17:18:44 2011 From: python-checkins at python.org (vinay.sajip) Date: Thu, 12 May 2011 17:18:44 +0200 Subject: [Python-checkins] cpython: TimedTRotatingFileHandler test now improved to minimise chances of failure on Message-ID: http://hg.python.org/cpython/rev/3ebe2d261920 changeset: 70053:3ebe2d261920 user: Vinay Sajip date: Thu May 12 16:18:29 2011 +0100 summary: TimedTRotatingFileHandler test now improved to minimise chances of failure on very slow machines. files: Lib/test/test_logging.py | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3502,6 +3502,7 @@ fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S', backupCount=1) r = logging.makeLogRecord({'msg': 'testing'}) + start = datetime.datetime.now() fh.emit(r) self.assertLogFile(self.fn) time.sleep(1.0) @@ -3510,20 +3511,21 @@ # At this point, we should have a recent rotated file which we # can test for the existence of. However, in practice, on some # machines which run really slowly, we don't know how far back - # in time to go to look for the log file. So, we go back a fair - # bit, and stop as soon as we see a rotated file. In theory this - # could of course still fail, but the chances are lower. + # in time to go to look for the log file. So, we go back as far as + # when the test started, and stop as soon as we see a rotated file. found = False now = datetime.datetime.now() - GO_BACK = 2 * 60 # seconds - for secs in range(1, GO_BACK): - prev = now - datetime.timedelta(seconds=secs) + secs = 1 + prev = now - datetime.timedelta(seconds=secs) + while prev > start: fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S") found = os.path.exists(fn) if found: self.rmfiles.append(fn) break - msg = 'No rotated files found, went back %d seconds' % GO_BACK + secs += 1 + prev -= datetime.timedelta(seconds=1) + msg = 'No rotated files found, went back %d seconds' % secs self.assertTrue(found, msg=msg) def test_invalid(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 18:09:08 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 May 2011 18:09:08 +0200 Subject: [Python-checkins] peps: Mention the lack of "errno" on select.error Message-ID: http://hg.python.org/peps/rev/1bc2e9bcea04 changeset: 3878:1bc2e9bcea04 user: Antoine Pitrou date: Thu May 12 18:09:06 2011 +0200 summary: Mention the lack of "errno" on select.error files: pep-3151.txt | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+), 0 deletions(-) diff --git a/pep-3151.txt b/pep-3151.txt --- a/pep-3151.txt +++ b/pep-3151.txt @@ -883,6 +883,25 @@ * epoll objects raise IOError; * kqueue objects raise both OSError and IOError. +As a side-note, not deriving from ``EnvironmentError`` means ``select.error`` +does not get the useful ``errno`` attribute. User code must check ``args[0]`` +instead:: + + >>> signal.alarm(1); select.select([], [], []) + 0 + Traceback (most recent call last): + File "", line 1, in + select.error: (4, 'Interrupted system call') + >>> e = sys.last_value + >>> e + error(4, 'Interrupted system call') + >>> e.errno == errno.EINTR + Traceback (most recent call last): + File "", line 1, in + AttributeError: 'error' object has no attribute 'errno' + >>> e.args[0] == errno.EINTR + True + signal '''''' -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu May 12 19:31:46 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 May 2011 19:31:46 +0200 Subject: [Python-checkins] peps: Mention the interesting idea of modifiying IOError.__new__ Message-ID: http://hg.python.org/peps/rev/0502a584fd63 changeset: 3879:0502a584fd63 user: Antoine Pitrou date: Thu May 12 19:31:43 2011 +0200 summary: Mention the interesting idea of modifiying IOError.__new__ (instead of the PyErr_SetFromErrno functions) files: pep-3151.txt | 21 +++++++++------------ 1 files changed, 9 insertions(+), 12 deletions(-) diff --git a/pep-3151.txt b/pep-3151.txt --- a/pep-3151.txt +++ b/pep-3151.txt @@ -440,22 +440,19 @@ Since it is proposed that the subclasses are raised based purely on the value of ``errno``, little or no changes should be required in extension -modules (either standard or third-party). As long as they use the -``PyErr_SetFromErrno()`` family of functions (or the -``PyErr_SetFromWindowsErr()`` family of functions under Windows), they -should automatically benefit from the new, finer-grained exception classes. +modules (either standard or third-party). -Library modules written in Python, though, will have to be adapted where -they currently use the following idiom (seen in ``Lib/tempfile.py``):: +The first possibility is to adapt the ``PyErr_SetFromErrno()`` family +of functions (``PyErr_SetFromWindowsErr()`` under Windows) to raise the +appropriate ``IOError`` subclass. This wouldn't cover, however, Python +code raising IOError directly, using the following idiom (seen in +``Lib/tempfile.py``):: raise IOError(_errno.EEXIST, "No usable temporary file name found") -Fortunately, such Python code is quite rare since raising OSError or IOError -with an errno value normally happens when interfacing with system calls, -which is usually done in C extensions. - -If there is popular demand, the subroutine choosing an exception type based -on the errno value could be exposed for use in pure Python. +A second possibility, suggested by Marc-Andre Lemburg, is to adapt +``IOError.__new__`` to instantiate the appropriate subclass. This would +have the benefit of also covering Python code such as the above. Possible objections -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu May 12 21:37:02 2011 From: python-checkins at python.org (kurt.kaiser) Date: Thu, 12 May 2011 21:37:02 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11896: Save on Close failed despite selecting "Yes" in dialog. Message-ID: http://hg.python.org/cpython/rev/da7a120c0478 changeset: 70054:da7a120c0478 branch: 3.1 parent: 70039:82cfbe2ddfbb user: Kurt B. Kaiser date: Thu May 12 15:25:24 2011 -0400 summary: Issue #11896: Save on Close failed despite selecting "Yes" in dialog. _tkinter.c is returning sometimes. Don't use tkinter.messagebox.Message - use the helper functions which convert to str. files: Lib/idlelib/IOBinding.py | 44 ++++++++++++------------ Lib/idlelib/NEWS.txt | 4 +- Lib/idlelib/ScriptBinding.py | 16 +++---- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py --- a/Lib/idlelib/IOBinding.py +++ b/Lib/idlelib/IOBinding.py @@ -309,17 +309,20 @@ return "yes" message = "Do you want to save %s before closing?" % ( self.filename or "this untitled document") - m = tkMessageBox.Message( - title="Save On Close", - message=message, - icon=tkMessageBox.QUESTION, - type=tkMessageBox.YESNOCANCEL, - master=self.text) - reply = m.show() - if reply == "yes": + confirm = tkMessageBox.askyesnocancel( + title="Save On Close", + message=message, + default=tkMessageBox.YES, + master=self.text) + if confirm: + reply = "yes" self.save(None) if not self.get_saved(): reply = "cancel" + elif confirm is None: + reply = "cancel" + else: + reply = "no" self.text.focus_set() return reply @@ -328,7 +331,7 @@ self.save_as(event) else: if self.writefile(self.filename): - self.set_saved(1) + self.set_saved(True) try: self.editwin.store_file_breaks() except AttributeError: # may be a PyShell @@ -420,15 +423,12 @@ self.text.insert("end-1c", "\n") def print_window(self, event): - m = tkMessageBox.Message( - title="Print", - message="Print to Default Printer", - icon=tkMessageBox.QUESTION, - type=tkMessageBox.OKCANCEL, - default=tkMessageBox.OK, - master=self.text) - reply = m.show() - if reply != tkMessageBox.OK: + confirm = tkMessageBox.askokcancel( + title="Print", + message="Print to Default Printer", + default=tkMessageBox.OK, + master=self.text) + if not confirm: self.text.focus_set() return "break" tempfilename = None @@ -443,8 +443,8 @@ if not self.writefile(tempfilename): os.unlink(tempfilename) return "break" - platform=os.name - printPlatform=1 + platform = os.name + printPlatform = True if platform == 'posix': #posix platform command = idleConf.GetOption('main','General', 'print-command-posix') @@ -452,7 +452,7 @@ elif platform == 'nt': #win32 platform command = idleConf.GetOption('main','General','print-command-win') else: #no printing for this platform - printPlatform=0 + printPlatform = False if printPlatform: #we can try to print for this platform command = command % filename pipe = os.popen(command, "r") @@ -466,7 +466,7 @@ output = "Printing command: %s\n" % repr(command) + output tkMessageBox.showerror("Print status", output, master=self.text) else: #no printing for this platform - message="Printing is not enabled for this platform: %s" % platform + message = "Printing is not enabled for this platform: %s" % platform tkMessageBox.showinfo("Print status", message, master=self.text) if tempfilename: os.unlink(tempfilename) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,7 +1,9 @@ What's New in IDLE 3.1.4? ========================= -*Release date: 15-May-11* +*Release date: XX-XXX-11* + +- Issue #11896: Save on Close failed despite selecting "Yes" in dialog. - Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. Tk < 8.5 was sending invalid Unicode null; replaced with valid null. diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -174,9 +174,9 @@ if autosave and filename: self.editwin.io.save(None) else: - reply = self.ask_save_dialog() + confirm = self.ask_save_dialog() self.editwin.text.focus_set() - if reply == "ok": + if confirm: self.editwin.io.save(None) filename = self.editwin.io.filename else: @@ -185,13 +185,11 @@ def ask_save_dialog(self): msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?" - mb = tkMessageBox.Message(title="Save Before Run or Check", - message=msg, - icon=tkMessageBox.QUESTION, - type=tkMessageBox.OKCANCEL, - default=tkMessageBox.OK, - master=self.editwin.text) - return mb.show() + confirm = tkMessageBox.askokcancel(title="Save Before Run or Check", + message=msg, + default=tkMessageBox.OK, + master=self.editwin.text) + return confirm def errorbox(self, title, message): # XXX This should really be a function of EditorWindow... -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 21:37:03 2011 From: python-checkins at python.org (kurt.kaiser) Date: Thu, 12 May 2011 21:37:03 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/35ed0efd7dd3 changeset: 70055:35ed0efd7dd3 branch: 3.2 parent: 70050:654d473f2951 parent: 70054:da7a120c0478 user: Kurt B. Kaiser date: Thu May 12 15:30:18 2011 -0400 summary: Merge from 3.1 files: Lib/idlelib/IOBinding.py | 44 ++++++++++++------------ Lib/idlelib/NEWS.txt | 2 + Lib/idlelib/ScriptBinding.py | 16 +++---- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py --- a/Lib/idlelib/IOBinding.py +++ b/Lib/idlelib/IOBinding.py @@ -309,17 +309,20 @@ return "yes" message = "Do you want to save %s before closing?" % ( self.filename or "this untitled document") - m = tkMessageBox.Message( - title="Save On Close", - message=message, - icon=tkMessageBox.QUESTION, - type=tkMessageBox.YESNOCANCEL, - master=self.text) - reply = m.show() - if reply == "yes": + confirm = tkMessageBox.askyesnocancel( + title="Save On Close", + message=message, + default=tkMessageBox.YES, + master=self.text) + if confirm: + reply = "yes" self.save(None) if not self.get_saved(): reply = "cancel" + elif confirm is None: + reply = "cancel" + else: + reply = "no" self.text.focus_set() return reply @@ -328,7 +331,7 @@ self.save_as(event) else: if self.writefile(self.filename): - self.set_saved(1) + self.set_saved(True) try: self.editwin.store_file_breaks() except AttributeError: # may be a PyShell @@ -420,15 +423,12 @@ self.text.insert("end-1c", "\n") def print_window(self, event): - m = tkMessageBox.Message( - title="Print", - message="Print to Default Printer", - icon=tkMessageBox.QUESTION, - type=tkMessageBox.OKCANCEL, - default=tkMessageBox.OK, - master=self.text) - reply = m.show() - if reply != tkMessageBox.OK: + confirm = tkMessageBox.askokcancel( + title="Print", + message="Print to Default Printer", + default=tkMessageBox.OK, + master=self.text) + if not confirm: self.text.focus_set() return "break" tempfilename = None @@ -443,8 +443,8 @@ if not self.writefile(tempfilename): os.unlink(tempfilename) return "break" - platform=os.name - printPlatform=1 + platform = os.name + printPlatform = True if platform == 'posix': #posix platform command = idleConf.GetOption('main','General', 'print-command-posix') @@ -452,7 +452,7 @@ elif platform == 'nt': #win32 platform command = idleConf.GetOption('main','General','print-command-win') else: #no printing for this platform - printPlatform=0 + printPlatform = False if printPlatform: #we can try to print for this platform command = command % filename pipe = os.popen(command, "r") @@ -466,7 +466,7 @@ output = "Printing command: %s\n" % repr(command) + output tkMessageBox.showerror("Print status", output, master=self.text) else: #no printing for this platform - message="Printing is not enabled for this platform: %s" % platform + message = "Printing is not enabled for this platform: %s" % platform tkMessageBox.showinfo("Print status", message, master=self.text) if tempfilename: os.unlink(tempfilename) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,8 @@ *Release date: 15-May-11* +- Issue #11896: Save on Close failed despite selecting "Yes" in dialog. + - Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. Tk < 8.5 was sending invalid Unicode null; replaced with valid null. diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -174,9 +174,9 @@ if autosave and filename: self.editwin.io.save(None) else: - reply = self.ask_save_dialog() + confirm = self.ask_save_dialog() self.editwin.text.focus_set() - if reply == "ok": + if confirm: self.editwin.io.save(None) filename = self.editwin.io.filename else: @@ -185,13 +185,11 @@ def ask_save_dialog(self): msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?" - mb = tkMessageBox.Message(title="Save Before Run or Check", - message=msg, - icon=tkMessageBox.QUESTION, - type=tkMessageBox.OKCANCEL, - default=tkMessageBox.OK, - master=self.editwin.text) - return mb.show() + confirm = tkMessageBox.askokcancel(title="Save Before Run or Check", + message=msg, + default=tkMessageBox.OK, + master=self.editwin.text) + return confirm def errorbox(self, title, message): # XXX This should really be a function of EditorWindow... -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 21:37:03 2011 From: python-checkins at python.org (kurt.kaiser) Date: Thu, 12 May 2011 21:37:03 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/87196154dec8 changeset: 70056:87196154dec8 parent: 70053:3ebe2d261920 parent: 70055:35ed0efd7dd3 user: Kurt B. Kaiser date: Thu May 12 15:36:42 2011 -0400 summary: Merge from 3.2 Issue #11896: Save on Close failed despite selecting "Yes" in dialog. files: Lib/idlelib/IOBinding.py | 44 ++++++++++++------------ Lib/idlelib/NEWS.txt | 2 + Lib/idlelib/ScriptBinding.py | 16 +++---- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py --- a/Lib/idlelib/IOBinding.py +++ b/Lib/idlelib/IOBinding.py @@ -309,17 +309,20 @@ return "yes" message = "Do you want to save %s before closing?" % ( self.filename or "this untitled document") - m = tkMessageBox.Message( - title="Save On Close", - message=message, - icon=tkMessageBox.QUESTION, - type=tkMessageBox.YESNOCANCEL, - master=self.text) - reply = m.show() - if reply == "yes": + confirm = tkMessageBox.askyesnocancel( + title="Save On Close", + message=message, + default=tkMessageBox.YES, + master=self.text) + if confirm: + reply = "yes" self.save(None) if not self.get_saved(): reply = "cancel" + elif confirm is None: + reply = "cancel" + else: + reply = "no" self.text.focus_set() return reply @@ -328,7 +331,7 @@ self.save_as(event) else: if self.writefile(self.filename): - self.set_saved(1) + self.set_saved(True) try: self.editwin.store_file_breaks() except AttributeError: # may be a PyShell @@ -420,15 +423,12 @@ self.text.insert("end-1c", "\n") def print_window(self, event): - m = tkMessageBox.Message( - title="Print", - message="Print to Default Printer", - icon=tkMessageBox.QUESTION, - type=tkMessageBox.OKCANCEL, - default=tkMessageBox.OK, - master=self.text) - reply = m.show() - if reply != tkMessageBox.OK: + confirm = tkMessageBox.askokcancel( + title="Print", + message="Print to Default Printer", + default=tkMessageBox.OK, + master=self.text) + if not confirm: self.text.focus_set() return "break" tempfilename = None @@ -443,8 +443,8 @@ if not self.writefile(tempfilename): os.unlink(tempfilename) return "break" - platform=os.name - printPlatform=1 + platform = os.name + printPlatform = True if platform == 'posix': #posix platform command = idleConf.GetOption('main','General', 'print-command-posix') @@ -452,7 +452,7 @@ elif platform == 'nt': #win32 platform command = idleConf.GetOption('main','General','print-command-win') else: #no printing for this platform - printPlatform=0 + printPlatform = False if printPlatform: #we can try to print for this platform command = command % filename pipe = os.popen(command, "r") @@ -466,7 +466,7 @@ output = "Printing command: %s\n" % repr(command) + output tkMessageBox.showerror("Print status", output, master=self.text) else: #no printing for this platform - message="Printing is not enabled for this platform: %s" % platform + message = "Printing is not enabled for this platform: %s" % platform tkMessageBox.showinfo("Print status", message, master=self.text) if tempfilename: os.unlink(tempfilename) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,8 @@ *Release date: 15-May-11* +- Issue #11896: Save on Close failed despite selecting "Yes" in dialog. + - Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. Tk < 8.5 was sending invalid Unicode null; replaced with valid null. diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -174,9 +174,9 @@ if autosave and filename: self.editwin.io.save(None) else: - reply = self.ask_save_dialog() + confirm = self.ask_save_dialog() self.editwin.text.focus_set() - if reply == "ok": + if confirm: self.editwin.io.save(None) filename = self.editwin.io.filename else: @@ -185,13 +185,11 @@ def ask_save_dialog(self): msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?" - mb = tkMessageBox.Message(title="Save Before Run or Check", - message=msg, - icon=tkMessageBox.QUESTION, - type=tkMessageBox.OKCANCEL, - default=tkMessageBox.OK, - master=self.editwin.text) - return mb.show() + confirm = tkMessageBox.askokcancel(title="Save Before Run or Check", + message=msg, + default=tkMessageBox.OK, + master=self.editwin.text) + return confirm def errorbox(self, title, message): # XXX This should really be a function of EditorWindow... -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 12 22:07:24 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 May 2011 22:07:24 +0200 Subject: [Python-checkins] peps: Fix the spelling of some errno mnemonics Message-ID: http://hg.python.org/peps/rev/15e36765eae3 changeset: 3880:15e36765eae3 user: Antoine Pitrou date: Thu May 12 22:07:21 2011 +0200 summary: Fix the spelling of some errno mnemonics (indirectly proving how easy to remember they are) files: pep-3151.txt | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pep-3151.txt b/pep-3151.txt --- a/pep-3151.txt +++ b/pep-3151.txt @@ -369,7 +369,7 @@ else (ENOTDIR) * ``PermissionError``: trying to run an operation without the adequate access - rights - for example filesystem permissions (EACCESS, EPERM) + rights - for example filesystem permissions (EACCES, EPERM) * ``BlockingIOError``: an operation would block on an object (e.g. socket) set for non-blocking operation (EAGAIN, EALREADY, EWOULDBLOCK, EINPROGRESS); @@ -385,7 +385,7 @@ * ``ConnectionResetError``: connection reset by peer (ECONNRESET) -* ``TimeoutError``: connection timed out (ECONNTIMEOUT); this can be re-cast +* ``TimeoutError``: connection timed out (ETIMEDOUT); this can be re-cast as a generic timeout exception, replacing ``socket.timeout`` and also useful for other types of timeout (for example in Lock.acquire()) @@ -413,8 +413,8 @@ +-- FileNotFoundError ENOENT +-- IsADirectoryError EISDIR +-- NotADirectoryError ENOTDIR - +-- PermissionError EACCESS, EPERM - +-- TimeoutError ECONNTIMEOUT + +-- PermissionError EACCES, EPERM + +-- TimeoutError ETIMEDOUT Naming ------ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 13 00:28:29 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 May 2011 00:28:29 +0200 Subject: [Python-checkins] cpython (3.1): Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence Message-ID: http://hg.python.org/cpython/rev/89f77afac947 changeset: 70057:89f77afac947 branch: 3.1 parent: 70054:da7a120c0478 user: Antoine Pitrou date: Fri May 13 00:13:33 2011 +0200 summary: Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence on a file opened in read+write mode (namely: reading, seeking a bit forward, writing, then seeking before the previous write but still within buffered data, and writing again). files: Lib/test/test_io.py | 26 ++++++++++++++++++++++++++ Misc/NEWS | 5 +++++ Modules/_io/bufferedio.c | 2 +- 3 files changed, 32 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1461,6 +1461,32 @@ self.assertEqual(s, b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size)) + def test_write_rewind_write(self): + # Various combinations of reading / writing / seeking backwards / writing again + def mutate(bufio, pos1, pos2): + assert pos2 >= pos1 + # Fill the buffer + bufio.seek(pos1) + bufio.read(pos2 - pos1) + bufio.write(b'\x02') + # This writes earlier than the previous write, but still inside + # the buffer. + bufio.seek(pos1) + bufio.write(b'\x01') + + b = b"\x80\x81\x82\x83\x84" + for i in range(0, len(b)): + for j in range(i, len(b)): + raw = self.BytesIO(b) + bufio = self.tp(raw, 100) + mutate(bufio, i, j) + bufio.flush() + expected = bytearray(b) + expected[j] = 2 + expected[i] = 1 + self.assertEqual(raw.getvalue(), expected, + "failed result for i=%d, j=%d" % (i, j)) + def test_truncate_after_read_or_write(self): raw = self.BytesIO(b"A" * 10) bufio = self.tp(raw, 100) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,11 @@ Library ------- +- Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence + on a file opened in read+write mode (namely: reading, seeking a bit forward, + writing, then seeking before the previous write but still within buffered + data, and writing again). + - Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused IDLE to exit. Converted to valid Unicode null in PythonCmd(). diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1749,7 +1749,7 @@ avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t); if (buf.len <= avail) { memcpy(self->buffer + self->pos, buf.buf, buf.len); - if (!VALID_WRITE_BUFFER(self)) { + if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) { self->write_pos = self->pos; } ADJUST_POSITION(self, self->pos + buf.len); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 00:28:30 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 May 2011 00:28:30 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence Message-ID: http://hg.python.org/cpython/rev/47ca1244a929 changeset: 70058:47ca1244a929 branch: 3.2 parent: 70055:35ed0efd7dd3 parent: 70057:89f77afac947 user: Antoine Pitrou date: Fri May 13 00:16:28 2011 +0200 summary: Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence on a file opened in read+write mode (namely: reading, seeking a bit forward, writing, then seeking before the previous write but still within buffered data, and writing again). files: Lib/test/test_io.py | 26 ++++++++++++++++++++++++++ Misc/NEWS | 6 ++++++ Modules/_io/bufferedio.c | 2 +- 3 files changed, 33 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1490,6 +1490,32 @@ self.assertEqual(s, b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size)) + def test_write_rewind_write(self): + # Various combinations of reading / writing / seeking backwards / writing again + def mutate(bufio, pos1, pos2): + assert pos2 >= pos1 + # Fill the buffer + bufio.seek(pos1) + bufio.read(pos2 - pos1) + bufio.write(b'\x02') + # This writes earlier than the previous write, but still inside + # the buffer. + bufio.seek(pos1) + bufio.write(b'\x01') + + b = b"\x80\x81\x82\x83\x84" + for i in range(0, len(b)): + for j in range(i, len(b)): + raw = self.BytesIO(b) + bufio = self.tp(raw, 100) + mutate(bufio, i, j) + bufio.flush() + expected = bytearray(b) + expected[j] = 2 + expected[i] = 1 + self.assertEqual(raw.getvalue(), expected, + "failed result for i=%d, j=%d" % (i, j)) + def test_truncate_after_read_or_write(self): raw = self.BytesIO(b"A" * 10) bufio = self.tp(raw, 100) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -89,6 +89,12 @@ Library ------- + +- Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence + on a file opened in read+write mode (namely: reading, seeking a bit forward, + writing, then seeking before the previous write but still within buffered + data, and writing again). + - Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused IDLE to exit. Converted to valid Unicode null in PythonCmd(). diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1838,7 +1838,7 @@ avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t); if (buf.len <= avail) { memcpy(self->buffer + self->pos, buf.buf, buf.len); - if (!VALID_WRITE_BUFFER(self)) { + if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) { self->write_pos = self->pos; } ADJUST_POSITION(self, self->pos + buf.len); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 00:28:31 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 May 2011 00:28:31 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence Message-ID: http://hg.python.org/cpython/rev/05e0227e3879 changeset: 70059:05e0227e3879 parent: 70056:87196154dec8 parent: 70058:47ca1244a929 user: Antoine Pitrou date: Fri May 13 00:25:53 2011 +0200 summary: Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence on a file opened in read+write mode (namely: reading, seeking a bit forward, writing, then seeking before the previous write but still within buffered data, and writing again). files: Lib/test/test_io.py | 26 ++++++++++++++++++++++++++ Misc/NEWS | 5 +++++ Modules/_io/bufferedio.c | 2 +- 3 files changed, 32 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1496,6 +1496,32 @@ self.assertEqual(s, b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size)) + def test_write_rewind_write(self): + # Various combinations of reading / writing / seeking backwards / writing again + def mutate(bufio, pos1, pos2): + assert pos2 >= pos1 + # Fill the buffer + bufio.seek(pos1) + bufio.read(pos2 - pos1) + bufio.write(b'\x02') + # This writes earlier than the previous write, but still inside + # the buffer. + bufio.seek(pos1) + bufio.write(b'\x01') + + b = b"\x80\x81\x82\x83\x84" + for i in range(0, len(b)): + for j in range(i, len(b)): + raw = self.BytesIO(b) + bufio = self.tp(raw, 100) + mutate(bufio, i, j) + bufio.flush() + expected = bytearray(b) + expected[j] = 2 + expected[i] = 1 + self.assertEqual(raw.getvalue(), expected, + "failed result for i=%d, j=%d" % (i, j)) + def test_truncate_after_read_or_write(self): raw = self.BytesIO(b"A" * 10) bufio = self.tp(raw, 100) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -147,6 +147,11 @@ Library ------- +- Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence + on a file opened in read+write mode (namely: reading, seeking a bit forward, + writing, then seeking before the previous write but still within buffered + data, and writing again). + - Issue #9971: Write an optimized implementation of BufferedReader.readinto(). Patch by John O'Connor. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1894,7 +1894,7 @@ avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t); if (buf.len <= avail) { memcpy(self->buffer + self->pos, buf.buf, buf.len); - if (!VALID_WRITE_BUFFER(self)) { + if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) { self->write_pos = self->pos; } ADJUST_POSITION(self, self->pos + buf.len); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 00:32:29 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 May 2011 00:32:29 +0200 Subject: [Python-checkins] cpython (2.7): Issue #12062: In the `io` module, fix a flushing bug when doing a certain Message-ID: http://hg.python.org/cpython/rev/0d24d4c537a6 changeset: 70060:0d24d4c537a6 branch: 2.7 parent: 70051:534a9e274d88 user: Antoine Pitrou date: Fri May 13 00:31:52 2011 +0200 summary: Issue #12062: In the `io` module, fix a flushing bug when doing a certain type of I/O sequence on a file opened in read+write mode (namely: reading, seeking a bit forward, writing, then seeking before the previous write but still within buffered data, and writing again). files: Lib/test/test_io.py | 26 ++++++++++++++++++++++++++ Misc/NEWS | 5 +++++ Modules/_io/bufferedio.c | 2 +- 3 files changed, 32 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1462,6 +1462,32 @@ self.assertEqual(s, b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size)) + def test_write_rewind_write(self): + # Various combinations of reading / writing / seeking backwards / writing again + def mutate(bufio, pos1, pos2): + assert pos2 >= pos1 + # Fill the buffer + bufio.seek(pos1) + bufio.read(pos2 - pos1) + bufio.write(b'\x02') + # This writes earlier than the previous write, but still inside + # the buffer. + bufio.seek(pos1) + bufio.write(b'\x01') + + b = b"\x80\x81\x82\x83\x84" + for i in range(0, len(b)): + for j in range(i, len(b)): + raw = self.BytesIO(b) + bufio = self.tp(raw, 100) + mutate(bufio, i, j) + bufio.flush() + expected = bytearray(b) + expected[j] = 2 + expected[i] = 1 + self.assertEqual(raw.getvalue(), expected, + "failed result for i=%d, j=%d" % (i, j)) + def test_truncate_after_read_or_write(self): raw = self.BytesIO(b"A" * 10) bufio = self.tp(raw, 100) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,11 @@ Library ------- +- Issue #12062: In the `io` module, fix a flushing bug when doing a certain + type of I/O sequence on a file opened in read+write mode (namely: reading, + seeking a bit forward, writing, then seeking before the previous write but + still within buffered data, and writing again). + - Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in order to accept exactly one connection. Patch by Daniel Evers. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1810,7 +1810,7 @@ avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t); if (buf.len <= avail) { memcpy(self->buffer + self->pos, buf.buf, buf.len); - if (!VALID_WRITE_BUFFER(self)) { + if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) { self->write_pos = self->pos; } ADJUST_POSITION(self, self->pos + buf.len); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 03:19:01 2011 From: python-checkins at python.org (kurt.kaiser) Date: Fri, 13 May 2011 03:19:01 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11896: Save on Close failed despite selecting "Yes" in dialog. Message-ID: http://hg.python.org/cpython/rev/ac14158462cf changeset: 70061:ac14158462cf branch: 2.7 user: Kurt B. Kaiser date: Thu May 12 21:18:47 2011 -0400 summary: Issue #11896: Save on Close failed despite selecting "Yes" in dialog. Backport 70055:35ed0efd7dd3 files: Lib/idlelib/IOBinding.py | 44 ++++++++++++------------ Lib/idlelib/NEWS.txt | 6 ++- Lib/idlelib/ScriptBinding.py | 16 +++---- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py --- a/Lib/idlelib/IOBinding.py +++ b/Lib/idlelib/IOBinding.py @@ -320,17 +320,20 @@ return "yes" message = "Do you want to save %s before closing?" % ( self.filename or "this untitled document") - m = tkMessageBox.Message( - title="Save On Close", - message=message, - icon=tkMessageBox.QUESTION, - type=tkMessageBox.YESNOCANCEL, - master=self.text) - reply = m.show() - if reply == "yes": + confirm = tkMessageBox.askyesnocancel( + title="Save On Close", + message=message, + default=tkMessageBox.YES, + master=self.text) + if confirm: + reply = "yes" self.save(None) if not self.get_saved(): reply = "cancel" + elif confirm is None: + reply = "cancel" + else: + reply = "no" self.text.focus_set() return reply @@ -339,7 +342,7 @@ self.save_as(event) else: if self.writefile(self.filename): - self.set_saved(1) + self.set_saved(True) try: self.editwin.store_file_breaks() except AttributeError: # may be a PyShell @@ -465,15 +468,12 @@ self.text.insert("end-1c", "\n") def print_window(self, event): - m = tkMessageBox.Message( - title="Print", - message="Print to Default Printer", - icon=tkMessageBox.QUESTION, - type=tkMessageBox.OKCANCEL, - default=tkMessageBox.OK, - master=self.text) - reply = m.show() - if reply != tkMessageBox.OK: + confirm = tkMessageBox.askokcancel( + title="Print", + message="Print to Default Printer", + default=tkMessageBox.OK, + master=self.text) + if not confirm: self.text.focus_set() return "break" tempfilename = None @@ -488,8 +488,8 @@ if not self.writefile(tempfilename): os.unlink(tempfilename) return "break" - platform=os.name - printPlatform=1 + platform = os.name + printPlatform = True if platform == 'posix': #posix platform command = idleConf.GetOption('main','General', 'print-command-posix') @@ -497,7 +497,7 @@ elif platform == 'nt': #win32 platform command = idleConf.GetOption('main','General','print-command-win') else: #no printing for this platform - printPlatform=0 + printPlatform = False if printPlatform: #we can try to print for this platform command = command % filename pipe = os.popen(command, "r") @@ -511,7 +511,7 @@ output = "Printing command: %s\n" % repr(command) + output tkMessageBox.showerror("Print status", output, master=self.text) else: #no printing for this platform - message="Printing is not enabled for this platform: %s" % platform + message = "Printing is not enabled for this platform: %s" % platform tkMessageBox.showinfo("Print status", message, master=self.text) if tempfilename: os.unlink(tempfilename) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,8 +3,12 @@ *Release date: XX-XX-XXXX* + +- Issue #11896: Save on Close failed despite selecting "Yes" in dialog. + - toggle failing on Tk 8.5, causing IDLE exits and strange selection behavior. Issue 4676. Improve selection extension behaviour. + - toggle non-functional when NumLock set on Windows. Issue 3851. @@ -31,7 +35,7 @@ - Tk 8.5 Text widget requires 'wordprocessor' tabstyle attr to handle mixed space/tab properly. Issue 5129, patch by Guilherme Polo. - + - Issue #3549: On MacOS the preferences menu was not present diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -184,9 +184,9 @@ if autosave and filename: self.editwin.io.save(None) else: - reply = self.ask_save_dialog() + confirm = self.ask_save_dialog() self.editwin.text.focus_set() - if reply == "ok": + if confirm: self.editwin.io.save(None) filename = self.editwin.io.filename else: @@ -195,13 +195,11 @@ def ask_save_dialog(self): msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?" - mb = tkMessageBox.Message(title="Save Before Run or Check", - message=msg, - icon=tkMessageBox.QUESTION, - type=tkMessageBox.OKCANCEL, - default=tkMessageBox.OK, - master=self.editwin.text) - return mb.show() + confirm = tkMessageBox.askokcancel(title="Save Before Run or Check", + message=msg, + default=tkMessageBox.OK, + master=self.editwin.text) + return confirm def errorbox(self, title, message): # XXX This should really be a function of EditorWindow... -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri May 13 04:58:05 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 13 May 2011 04:58:05 +0200 Subject: [Python-checkins] Daily reference leaks (05e0227e3879): sum=0 Message-ID: results for 05e0227e3879 on branch "default" -------------------------------------------- test_pydoc leaked [0, -323, 323] references, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogjtKPHd', '-x'] From python-checkins at python.org Fri May 13 06:50:59 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 13 May 2011 06:50:59 +0200 Subject: [Python-checkins] cpython (3.2): Bump to 3.2.1b1. Message-ID: http://hg.python.org/cpython/rev/9778abaa0e47 changeset: 70062:9778abaa0e47 branch: 3.2 parent: 69928:e3f807d52272 user: Georg Brandl date: Sun May 08 09:03:36 2011 +0200 summary: Bump to 3.2.1b1. files: Include/patchlevel.h | 8 +- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 122 +++++++++++++------------ Misc/RPM/python-3.2.spec | 2 +- README | 4 +- 6 files changed, 71 insertions(+), 69 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 2 -#define PY_MICRO_VERSION 0 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 +#define PY_MICRO_VERSION 1 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.2.1a0" +#define PY_VERSION "3.2.1b1" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -15,5 +15,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.2" +__version__ = "3.2.1b1" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.2" +IDLE_VERSION = "3.2.1b1" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,17 +2,17 @@ Python News +++++++++++ -What's New in Python 3.2.1? -=========================== - -*Release date: XX-XXX-20XX* +What's New in Python 3.2.1 beta 1? +================================== + +*Release date: 08-May-2011* Core and Builtins ----------------- - Issue #1856: Avoid crashes and lockups when daemon threads run while the - interpreter is shutting down; instead, these threads are now killed when - they try to take the GIL. + interpreter is shutting down; instead, these threads are now killed when they + try to take the GIL. - Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. @@ -24,15 +24,15 @@ the ISO-8859-15 codec. - Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* - APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch - by Charles-Fran?ois Natali. + APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch by + Charles-Fran?ois Natali. - Issue #6780: fix starts/endswith error message to mention that tuples are accepted too. - Issue #5057: fix a bug in the peepholer that led to non-portable pyc files - between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP - chars (e.g. "\U00012345"[0]). + between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP chars + (e.g. "\U00012345"[0]). - Issue #11845: Fix typo in rangeobject.c that caused a crash in compute_slice_indices. Patch by Daniel Urban. @@ -43,12 +43,12 @@ - Issue #11395: io.FileIO().write() clamps the data length to 32,767 bytes on Windows if the file is a TTY to workaround a Windows bug. The Windows console - returns an error (12: not enough space error) on writing into stdout if - stdout mode is binary and the length is greater than 66,000 bytes (or less, - depending on heap usage). - -- Issue #11320: fix bogus memory management in Modules/getpath.c, leading to - a possible crash when calling Py_SetPath(). + returns an error (12: not enough space error) on writing into stdout if stdout + mode is binary and the length is greater than 66,000 bytes (or less, depending + on heap usage). + +- Issue #11320: fix bogus memory management in Modules/getpath.c, leading to a + possible crash when calling Py_SetPath(). - Issue #11510: Fixed optimizer bug which turned "a,b={1,1}" into "a,b=(1,1)". @@ -56,21 +56,21 @@ 3.2.0 where the stdout or stderr file descriptor being the same as the stdin file descriptor would raise an exception. webbrowser.open would fail. fixed. -- Issue #11450: Don't truncate hg version info in Py_GetBuildInfo() when - there are many tags (e.g. when using mq). Patch by Nadeem Vawda. +- Issue #11450: Don't truncate hg version info in Py_GetBuildInfo() when there + are many tags (e.g. when using mq). Patch by Nadeem Vawda. - Issue #11246: Fix PyUnicode_FromFormat("%V") to decode the byte string from UTF-8 (with replace error handler) instead of ISO-8859-1 (in strict mode). Patch written by Ray Allen. -- Issue #11286: Raise a ValueError from calling PyMemoryView_FromBuffer with - a buffer struct having a NULL data pointer. +- Issue #11286: Raise a ValueError from calling PyMemoryView_FromBuffer with a + buffer struct having a NULL data pointer. - Issue #11272: On Windows, input() strips '\r' (and not only '\n'), and sys.stdin uses universal newline (replace '\r\n' by '\n'). -- issue #11828: startswith and endswith don't accept None as slice index. - Patch by Torsten Becker. +- issue #11828: startswith and endswith don't accept None as slice index. Patch + by Torsten Becker. - Issue #10830: Fix PyUnicode_FromFormatV("%c") for non-BMP characters on narrow build. @@ -83,25 +83,25 @@ Library ------- -- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch - by Kasun Herath. +- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by + Kasun Herath. - Issue #12002: ftplib's abort() method raises TypeError. -- Issue 11999: fixed sporadic sync failure mailbox.Maildir due to its trying to +- Issue #11999: fixed sporadic sync failure mailbox.Maildir due to its trying to detect mtime changes by comparing to the system clock instead of to the previous value of the mtime. - ntpath.samefile failed to notice that "a.txt" and "A.TXT" refer to the same file on Windows XP. As noticed in issue #10684. -- Issue #12000: When a SSL certificate has a subjectAltName without any - dNSName entry, ssl.match_hostname() should use the subject's commonName. - Patch by Nicolas Bareil. - -- Issue #11647: objects created using contextlib.contextmanager now support - more than one call to the function when used as a decorator. Initial patch - by Ysj Ray. +- Issue #12000: When a SSL certificate has a subjectAltName without any dNSName + entry, ssl.match_hostname() should use the subject's commonName. Patch by + Nicolas Bareil. + +- Issue #11647: objects created using contextlib.contextmanager now support more + than one call to the function when used as a decorator. Initial patch by Ysj + Ray. - logging: don't define QueueListener if Python has no thread support. @@ -159,13 +159,14 @@ difflib.unified_diff(). - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating - worker processes: new processes would be spawned while the pool is being - shut down. Patch by Charles-Fran?ois Natali. + worker processes: new processes would be spawned while the pool is being shut + down. Patch by Charles-Fran?ois Natali. - Issue #7311: fix html.parser to accept non-ASCII attribute values. -- Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart - subpararts with an 8bit CTE into unicode instead of preserving the bytes. +- Issue #11605: email.parser.BytesFeedParser was incorrectly converting + multipart subpararts with an 8bit CTE into unicode instead of preserving the + bytes. - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. @@ -230,8 +231,8 @@ relative to Python2 and the result is now the same as it was in Python2. - Issue #9298: base64 bodies weren't being folded to line lengths less than 78, - which was a regression relative to Python2. Unlike Python2, the last line - of the folded body now ends with a carriage return. + which was a regression relative to Python2. Unlike Python2, the last line of + the folded body now ends with a carriage return. - Issue #11560: shutil.unpack_archive now correctly handles the format parameter. Patch by Evan Dandrea. @@ -240,8 +241,8 @@ execution. Patch by Andreas St?hrk. - Issue #11569: use absolute path to the sysctl command in multiprocessing to - ensure that it will be found regardless of the shell PATH. This ensures - that multiprocessing.cpu_count works on default installs of MacOSX. + ensure that it will be found regardless of the shell PATH. This ensures that + multiprocessing.cpu_count works on default installs of MacOSX. - Issue #11501: disutils.archive_utils.make_zipfile no longer fails if zlib is not installed. Instead, the zipfile.ZIP_STORED compression is used to create @@ -250,15 +251,15 @@ - Issue #11554: Fixed support for Japanese codecs; previously the body output encoding was not done if euc-jp or shift-jis was specified as the charset. -- Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified - IP addresses in the proxy exception list. - -- Issue #11491: dbm.error is no longer raised when dbm.open is called with - the "n" as the flag argument and the file exists. The behavior matches - the documentation and general logic. - -- Issue #11131: Fix sign of zero in decimal.Decimal plus and minus - operations when the rounding mode is ROUND_FLOOR. +- Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified IP + addresses in the proxy exception list. + +- Issue #11491: dbm.error is no longer raised when dbm.open is called with the + "n" as the flag argument and the file exists. The behavior matches the + documentation and general logic. + +- Issue #11131: Fix sign of zero in decimal.Decimal plus and minus operations + when the rounding mode is ROUND_FLOOR. - Issue #5622: Fix curses.wrapper to raise correct exception if curses initialization fails. @@ -267,12 +268,12 @@ ``mmap.PROT_READ|mmap.PROT_EXEC`` would segfault instead of raising a TypeError. Patch by Charles-Fran?ois Natali. -- Issue #11306: mailbox in certain cases adapts to an inability to open - certain files in read-write mode. Previously it detected this by - checking for EACCES, now it also checks for EROFS. - -- Issue #11265: asyncore now correctly handles EPIPE, EBADF and EAGAIN errors - on accept(), send() and recv(). +- Issue #11306: mailbox in certain cases adapts to an inability to open certain + files in read-write mode. Previously it detected this by checking for EACCES, + now it also checks for EROFS. + +- Issue #11265: asyncore now correctly handles EPIPE, EBADF and EAGAIN errors on + accept(), send() and recv(). - Issue #11326: Add the missing connect_ex() implementation for SSL sockets, and make it work for non-blocking connects. @@ -315,14 +316,14 @@ - Issue #11411: Fix 'make DESTDIR=' with a relative destination. -- Issue #11268: Prevent Mac OS X Installer failure if Documentation - package had previously been installed. +- Issue #11268: Prevent Mac OS X Installer failure if Documentation package had + previously been installed. IDLE ---- -- Issue #11718: IDLE's open module dialog couldn't find the __init__.py - file in a package. +- Issue #11718: IDLE's open module dialog couldn't find the __init__.py file in + a package. Tools/Demos ----------- @@ -346,7 +347,8 @@ - Issue #10914: Add a minimal embedding test to test_capi. -- Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition. +- Issue #11790: Fix sporadic failures in + test_multiprocessing.WithProcessesTestCondition. - Fix possible "file already exists" error when running the tests in parallel. diff --git a/Misc/RPM/python-3.2.spec b/Misc/RPM/python-3.2.spec --- a/Misc/RPM/python-3.2.spec +++ b/Misc/RPM/python-3.2.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.2 +%define version 3.2.1b1 %define libvers 3.2 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Python version 3.2 -========================== +This is Python version 3.2.1 beta 1 +=================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Python Software Foundation. All rights reserved. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 06:51:00 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 13 May 2011 06:51:00 +0200 Subject: [Python-checkins] cpython (3.2): Update suspicious ignore file. Message-ID: http://hg.python.org/cpython/rev/8ffac2337a33 changeset: 70063:8ffac2337a33 branch: 3.2 tag: v3.2.1b1 user: Georg Brandl date: Sun May 08 09:10:29 2011 +0200 summary: Update suspicious ignore file. files: Doc/tools/sphinxext/susp-ignored.csv | 191 +++++++------- Lib/pydoc_data/topics.py | 2 +- 2 files changed, 99 insertions(+), 94 deletions(-) diff --git a/Doc/tools/sphinxext/susp-ignored.csv b/Doc/tools/sphinxext/susp-ignored.csv --- a/Doc/tools/sphinxext/susp-ignored.csv +++ b/Doc/tools/sphinxext/susp-ignored.csv @@ -186,99 +186,6 @@ documenting/fromlatex,162,.. describe:,.. describe:: a == b documenting/fromlatex,168,.. cmdoption:,.. cmdoption:: -O documenting/fromlatex,168,.. envvar:,.. envvar:: PYTHONINSPECT -documenting/markup,33,.. sectionauthor:,.. sectionauthor:: Guido van Rossum -documenting/markup,42,:mod,:mod:`parrot` -- Dead parrot access -documenting/markup,42,`,:mod:`parrot` -- Dead parrot access -documenting/markup,42,.. module:,.. module:: parrot -documenting/markup,42,:platform,":platform: Unix, Windows" -documenting/markup,42,:synopsis,:synopsis: Analyze and reanimate dead parrots. -documenting/markup,42,.. moduleauthor:,.. moduleauthor:: Eric Cleese -documenting/markup,42,.. moduleauthor:,.. moduleauthor:: John Idle -documenting/markup,88,:noindex,:noindex: -documenting/markup,95,.. function:,.. function:: spam(eggs) -documenting/markup,95,:noindex,:noindex: -documenting/markup,101,.. method:,.. method:: FileInput.input(...) -documenting/markup,121,:function,c:function -documenting/markup,121,.. c:,".. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)" -documenting/markup,121,::,".. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)" -documenting/markup,131,:member,c:member -documenting/markup,131,.. c:,.. c:member:: PyObject* PyTypeObject.tp_bases -documenting/markup,131,::,.. c:member:: PyObject* PyTypeObject.tp_bases -documenting/markup,139,:macro,c:macro -documenting/markup,143,:type,c:type -documenting/markup,150,:var,c:var -documenting/markup,150,.. cvar:,.. cvar:: PyObject* PyClass_Type -documenting/markup,179,.. function:,".. function:: Timer.repeat([repeat=3[, number=1000000]])" -documenting/markup,210,.. decorator:,.. decorator:: removename -documenting/markup,210,.. decorator:,.. decorator:: setnewname(name) -documenting/markup,210,:func,:func: -documenting/markup,233,:meth,:meth: -documenting/markup,246,.. cmdoption:,.. cmdoption:: -m -documenting/markup,264,.. describe:,.. describe:: opcode -documenting/markup,293,.. highlightlang:,.. highlightlang:: c -documenting/markup,313,.. literalinclude:,.. literalinclude:: example.py -documenting/markup,328,:rolename,:rolename:`content` -documenting/markup,328,`,:rolename:`content` -documenting/markup,333,:role,:role:`title ` -documenting/markup,333,`,:role:`title ` -documenting/markup,339,:meth,:meth:`~Queue.Queue.get` -documenting/markup,339,`,:meth:`~Queue.Queue.get` -documenting/markup,387,:func,:func:`filter` -documenting/markup,387,`,:func:`filter` -documenting/markup,387,:func,:func:`foo.filter` -documenting/markup,387,`,:func:`foo.filter` -documenting/markup,393,:func,:func:`open` -documenting/markup,393,`,:func:`open` -documenting/markup,393,:func,:func:`.open` -documenting/markup,393,`,:func:`.open` -documenting/markup,409,:data,c:data -documenting/markup,413,:func,c:func -documenting/markup,417,:macro,c:macro -documenting/markup,421,:type,c:type -documenting/markup,426,:member,c:member -documenting/markup,476,:file,... is installed in :file:`/usr/lib/python2.{x}/site-packages` ... -documenting/markup,476,`,... is installed in :file:`/usr/lib/python2.{x}/site-packages` ... -documenting/markup,495,:kbd,:kbd:`C-x C-f` -documenting/markup,495,`,:kbd:`C-x C-f` -documenting/markup,495,:kbd,:kbd:`Control-x Control-f` -documenting/markup,495,`,:kbd:`Control-x Control-f` -documenting/markup,509,:mailheader,:mailheader:`Content-Type` -documenting/markup,509,`,:mailheader:`Content-Type` -documenting/markup,518,:manpage,:manpage:`ls(1)` -documenting/markup,518,`,:manpage:`ls(1)` -documenting/markup,534,:menuselection,:menuselection:`Start --> Programs` -documenting/markup,534,`,:menuselection:`Start --> Programs` -documenting/markup,549,`,``code`` -documenting/markup,567,:file,:file: -documenting/markup,567,`,``code`` -documenting/markup,602,:ref,:ref:`label-name` -documenting/markup,602,`,:ref:`label-name` -documenting/markup,606,:ref,"It refers to the section itself, see :ref:`my-reference-label`." -documenting/markup,606,`,"It refers to the section itself, see :ref:`my-reference-label`." -documenting/markup,615,:ref,:ref: -documenting/markup,636,.. note:,.. note:: -documenting/markup,663,.. versionadded:,.. versionadded:: 3.1 -documenting/markup,688,::,.. impl-detail:: -documenting/markup,688,::,.. impl-detail:: This shortly mentions an implementation detail. -documenting/markup,708,.. seealso:,.. seealso:: -documenting/markup,708,:mod,Module :mod:`zipfile` -documenting/markup,708,`,Module :mod:`zipfile` -documenting/markup,708,:mod,Documentation of the :mod:`zipfile` standard module. -documenting/markup,708,`,Documentation of the :mod:`zipfile` standard module. -documenting/markup,708,`,"`GNU tar manual, Basic Tar Format `_" -documenting/markup,722,.. centered:,.. centered:: -documenting/markup,767,.. toctree:,.. toctree:: -documenting/markup,767,:maxdepth,:maxdepth: 2 -documenting/markup,783,.. index:,.. index:: -documenting/markup,813,.. index:,".. index:: BNF, grammar, syntax, notation" -documenting/markup,844,`,"unaryneg ::= ""-"" `integer`" -documenting/markup,849,.. productionlist:,.. productionlist:: -documenting/markup,849,`,"try1_stmt: ""try"" "":"" `suite`" -documenting/markup,849,`,": (""except"" [`expression` ["","" `target`]] "":"" `suite`)+" -documenting/markup,849,`,": [""else"" "":"" `suite`]" -documenting/markup,849,`,": [""finally"" "":"" `suite`]" -documenting/markup,849,`,"try2_stmt: ""try"" "":"" `suite`" -documenting/markup,849,`,": ""finally"" "":"" `suite`" documenting/rest,33,`,``text`` documenting/rest,47,:rolename,:rolename:`content` documenting/rest,47,`,:rolename:`content` @@ -386,3 +293,101 @@ whatsnew/3.2,,:affe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," whatsnew/3.2,,:deaf,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," whatsnew/3.2,,:feed,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +documenting/markup,33,.. sectionauthor:,.. sectionauthor:: Guido van Rossum +documenting/markup,42,:mod,:mod:`parrot` -- Dead parrot access +documenting/markup,42,`,:mod:`parrot` -- Dead parrot access +documenting/markup,42,.. module:,.. module:: parrot +documenting/markup,42,:platform,":platform: Unix, Windows" +documenting/markup,42,:synopsis,:synopsis: Analyze and reanimate dead parrots. +documenting/markup,42,.. moduleauthor:,.. moduleauthor:: Eric Cleese +documenting/markup,42,.. moduleauthor:,.. moduleauthor:: John Idle +documenting/markup,88,:noindex,:noindex: +documenting/markup,95,.. function:,.. function:: spam(eggs) +documenting/markup,95,:noindex,:noindex: +documenting/markup,101,.. method:,.. method:: FileInput.input(...) +documenting/markup,121,:function,c:function +documenting/markup,121,.. c:,".. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)" +documenting/markup,121,::,".. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)" +documenting/markup,131,:member,c:member +documenting/markup,131,.. c:,.. c:member:: PyObject* PyTypeObject.tp_bases +documenting/markup,131,::,.. c:member:: PyObject* PyTypeObject.tp_bases +documenting/markup,139,:macro,c:macro +documenting/markup,143,:type,c:type +documenting/markup,150,:var,c:var +documenting/markup,150,.. cvar:,.. cvar:: PyObject* PyClass_Type +documenting/markup,179,.. function:,".. function:: repeat([repeat=3[, number=1000000]])" +documenting/markup,210,.. decorator:,.. decorator:: removename +documenting/markup,210,.. decorator:,.. decorator:: setnewname(name) +documenting/markup,210,:func,:func: +documenting/markup,237,.. class:,.. class:: Spam +documenting/markup,237,.. data:,.. data:: ham +documenting/markup,237,.. data:,.. data:: Spam.eggs +documenting/markup,250,:meth,:meth: +documenting/markup,263,.. cmdoption:,.. cmdoption:: -m +documenting/markup,281,.. describe:,.. describe:: opcode +documenting/markup,310,.. highlightlang:,.. highlightlang:: c +documenting/markup,330,.. literalinclude:,.. literalinclude:: example.py +documenting/markup,345,:rolename,:rolename:`content` +documenting/markup,345,`,:rolename:`content` +documenting/markup,350,:role,:role:`title ` +documenting/markup,350,`,:role:`title ` +documenting/markup,356,:meth,:meth:`~Queue.Queue.get` +documenting/markup,356,`,:meth:`~Queue.Queue.get` +documenting/markup,404,:func,:func:`filter` +documenting/markup,404,`,:func:`filter` +documenting/markup,404,:func,:func:`foo.filter` +documenting/markup,404,`,:func:`foo.filter` +documenting/markup,410,:func,:func:`open` +documenting/markup,410,`,:func:`open` +documenting/markup,410,:func,:func:`.open` +documenting/markup,410,`,:func:`.open` +documenting/markup,426,:data,c:data +documenting/markup,430,:func,c:func +documenting/markup,434,:macro,c:macro +documenting/markup,438,:type,c:type +documenting/markup,443,:member,c:member +documenting/markup,493,:file,... is installed in :file:`/usr/lib/python2.{x}/site-packages` ... +documenting/markup,493,`,... is installed in :file:`/usr/lib/python2.{x}/site-packages` ... +documenting/markup,512,:kbd,:kbd:`C-x C-f` +documenting/markup,512,`,:kbd:`C-x C-f` +documenting/markup,512,:kbd,:kbd:`Control-x Control-f` +documenting/markup,512,`,:kbd:`Control-x Control-f` +documenting/markup,526,:mailheader,:mailheader:`Content-Type` +documenting/markup,526,`,:mailheader:`Content-Type` +documenting/markup,535,:manpage,:manpage:`ls(1)` +documenting/markup,535,`,:manpage:`ls(1)` +documenting/markup,551,:menuselection,:menuselection:`Start --> Programs` +documenting/markup,551,`,:menuselection:`Start --> Programs` +documenting/markup,566,`,``code`` +documenting/markup,585,:file,:file: +documenting/markup,585,`,``code`` +documenting/markup,615,:ref,:ref:`label-name` +documenting/markup,615,`,:ref:`label-name` +documenting/markup,619,:ref,"It refers to the section itself, see :ref:`my-reference-label`." +documenting/markup,619,`,"It refers to the section itself, see :ref:`my-reference-label`." +documenting/markup,628,:ref,:ref: +documenting/markup,630,:ref,:ref:`link text ` +documenting/markup,630,`,:ref:`link text ` +documenting/markup,651,.. note:,.. note:: +documenting/markup,678,.. versionadded:,.. versionadded:: 3.1 +documenting/markup,703,::,.. impl-detail:: +documenting/markup,703,::,.. impl-detail:: This shortly mentions an implementation detail. +documenting/markup,723,.. seealso:,.. seealso:: +documenting/markup,723,:mod,Module :mod:`zipfile` +documenting/markup,723,`,Module :mod:`zipfile` +documenting/markup,723,:mod,Documentation of the :mod:`zipfile` standard module. +documenting/markup,723,`,Documentation of the :mod:`zipfile` standard module. +documenting/markup,723,`,"`GNU tar manual, Basic Tar Format `_" +documenting/markup,737,.. centered:,.. centered:: +documenting/markup,782,.. toctree:,.. toctree:: +documenting/markup,782,:maxdepth,:maxdepth: 2 +documenting/markup,798,.. index:,.. index:: +documenting/markup,828,.. index:,".. index:: BNF, grammar, syntax, notation" +documenting/markup,859,`,"unaryneg ::= ""-"" `integer`" +documenting/markup,864,.. productionlist:,.. productionlist:: +documenting/markup,864,`,"try1_stmt: ""try"" "":"" `suite`" +documenting/markup,864,`,": (""except"" [`expression` ["","" `target`]] "":"" `suite`)+" +documenting/markup,864,`,": [""else"" "":"" `suite`]" +documenting/markup,864,`,": [""finally"" "":"" `suite`]" +documenting/markup,864,`,"try2_stmt: ""try"" "":"" `suite`" +documenting/markup,864,`,": ""finally"" "":"" `suite`" diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Thu Apr 28 07:47:47 2011 +# Autogenerated by Sphinx on Sun May 8 09:06:25 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.\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', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 06:51:00 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 13 May 2011 06:51:00 +0200 Subject: [Python-checkins] cpython (3.2): Added tag v3.2.1b1 for changeset 8ffac2337a33 Message-ID: http://hg.python.org/cpython/rev/5b34f84ca773 changeset: 70064:5b34f84ca773 branch: 3.2 user: Georg Brandl date: Sun May 08 09:32:00 2011 +0200 summary: Added tag v3.2.1b1 for changeset 8ffac2337a33 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -85,3 +85,4 @@ acf3e24dd0d0dfd1e20c907d696d3da965a8f56f v3.2rc2 18c1f52896501c7ee13b038454a39acb45a87979 v3.2rc3 a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 +8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 06:51:01 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 13 May 2011 06:51:01 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): Merge in changes from 3.2.1b1 release repo. Message-ID: http://hg.python.org/cpython/rev/e7698ce2d2bf changeset: 70065:e7698ce2d2bf branch: 3.2 parent: 70058:47ca1244a929 parent: 70064:5b34f84ca773 user: Georg Brandl date: Fri May 13 06:50:56 2011 +0200 summary: Merge in changes from 3.2.1b1 release repo. files: .hgtags | 1 + Doc/tools/sphinxext/susp-ignored.csv | 191 +++++++------- Include/patchlevel.h | 8 +- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Lib/pydoc_data/topics.py | 2 +- Misc/NEWS | 120 ++++---- Misc/RPM/python-3.2.spec | 2 +- README | 4 +- 9 files changed, 170 insertions(+), 162 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -85,3 +85,4 @@ acf3e24dd0d0dfd1e20c907d696d3da965a8f56f v3.2rc2 18c1f52896501c7ee13b038454a39acb45a87979 v3.2rc3 a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 +8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 diff --git a/Doc/tools/sphinxext/susp-ignored.csv b/Doc/tools/sphinxext/susp-ignored.csv --- a/Doc/tools/sphinxext/susp-ignored.csv +++ b/Doc/tools/sphinxext/susp-ignored.csv @@ -186,99 +186,6 @@ documenting/fromlatex,162,.. describe:,.. describe:: a == b documenting/fromlatex,168,.. cmdoption:,.. cmdoption:: -O documenting/fromlatex,168,.. envvar:,.. envvar:: PYTHONINSPECT -documenting/markup,33,.. sectionauthor:,.. sectionauthor:: Guido van Rossum -documenting/markup,42,:mod,:mod:`parrot` -- Dead parrot access -documenting/markup,42,`,:mod:`parrot` -- Dead parrot access -documenting/markup,42,.. module:,.. module:: parrot -documenting/markup,42,:platform,":platform: Unix, Windows" -documenting/markup,42,:synopsis,:synopsis: Analyze and reanimate dead parrots. -documenting/markup,42,.. moduleauthor:,.. moduleauthor:: Eric Cleese -documenting/markup,42,.. moduleauthor:,.. moduleauthor:: John Idle -documenting/markup,88,:noindex,:noindex: -documenting/markup,95,.. function:,.. function:: spam(eggs) -documenting/markup,95,:noindex,:noindex: -documenting/markup,101,.. method:,.. method:: FileInput.input(...) -documenting/markup,121,:function,c:function -documenting/markup,121,.. c:,".. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)" -documenting/markup,121,::,".. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)" -documenting/markup,131,:member,c:member -documenting/markup,131,.. c:,.. c:member:: PyObject* PyTypeObject.tp_bases -documenting/markup,131,::,.. c:member:: PyObject* PyTypeObject.tp_bases -documenting/markup,139,:macro,c:macro -documenting/markup,143,:type,c:type -documenting/markup,150,:var,c:var -documenting/markup,150,.. cvar:,.. cvar:: PyObject* PyClass_Type -documenting/markup,179,.. function:,".. function:: Timer.repeat([repeat=3[, number=1000000]])" -documenting/markup,210,.. decorator:,.. decorator:: removename -documenting/markup,210,.. decorator:,.. decorator:: setnewname(name) -documenting/markup,210,:func,:func: -documenting/markup,233,:meth,:meth: -documenting/markup,246,.. cmdoption:,.. cmdoption:: -m -documenting/markup,264,.. describe:,.. describe:: opcode -documenting/markup,293,.. highlightlang:,.. highlightlang:: c -documenting/markup,313,.. literalinclude:,.. literalinclude:: example.py -documenting/markup,328,:rolename,:rolename:`content` -documenting/markup,328,`,:rolename:`content` -documenting/markup,333,:role,:role:`title ` -documenting/markup,333,`,:role:`title ` -documenting/markup,339,:meth,:meth:`~Queue.Queue.get` -documenting/markup,339,`,:meth:`~Queue.Queue.get` -documenting/markup,387,:func,:func:`filter` -documenting/markup,387,`,:func:`filter` -documenting/markup,387,:func,:func:`foo.filter` -documenting/markup,387,`,:func:`foo.filter` -documenting/markup,393,:func,:func:`open` -documenting/markup,393,`,:func:`open` -documenting/markup,393,:func,:func:`.open` -documenting/markup,393,`,:func:`.open` -documenting/markup,409,:data,c:data -documenting/markup,413,:func,c:func -documenting/markup,417,:macro,c:macro -documenting/markup,421,:type,c:type -documenting/markup,426,:member,c:member -documenting/markup,476,:file,... is installed in :file:`/usr/lib/python2.{x}/site-packages` ... -documenting/markup,476,`,... is installed in :file:`/usr/lib/python2.{x}/site-packages` ... -documenting/markup,495,:kbd,:kbd:`C-x C-f` -documenting/markup,495,`,:kbd:`C-x C-f` -documenting/markup,495,:kbd,:kbd:`Control-x Control-f` -documenting/markup,495,`,:kbd:`Control-x Control-f` -documenting/markup,509,:mailheader,:mailheader:`Content-Type` -documenting/markup,509,`,:mailheader:`Content-Type` -documenting/markup,518,:manpage,:manpage:`ls(1)` -documenting/markup,518,`,:manpage:`ls(1)` -documenting/markup,534,:menuselection,:menuselection:`Start --> Programs` -documenting/markup,534,`,:menuselection:`Start --> Programs` -documenting/markup,549,`,``code`` -documenting/markup,567,:file,:file: -documenting/markup,567,`,``code`` -documenting/markup,602,:ref,:ref:`label-name` -documenting/markup,602,`,:ref:`label-name` -documenting/markup,606,:ref,"It refers to the section itself, see :ref:`my-reference-label`." -documenting/markup,606,`,"It refers to the section itself, see :ref:`my-reference-label`." -documenting/markup,615,:ref,:ref: -documenting/markup,636,.. note:,.. note:: -documenting/markup,663,.. versionadded:,.. versionadded:: 3.1 -documenting/markup,688,::,.. impl-detail:: -documenting/markup,688,::,.. impl-detail:: This shortly mentions an implementation detail. -documenting/markup,708,.. seealso:,.. seealso:: -documenting/markup,708,:mod,Module :mod:`zipfile` -documenting/markup,708,`,Module :mod:`zipfile` -documenting/markup,708,:mod,Documentation of the :mod:`zipfile` standard module. -documenting/markup,708,`,Documentation of the :mod:`zipfile` standard module. -documenting/markup,708,`,"`GNU tar manual, Basic Tar Format `_" -documenting/markup,722,.. centered:,.. centered:: -documenting/markup,767,.. toctree:,.. toctree:: -documenting/markup,767,:maxdepth,:maxdepth: 2 -documenting/markup,783,.. index:,.. index:: -documenting/markup,813,.. index:,".. index:: BNF, grammar, syntax, notation" -documenting/markup,844,`,"unaryneg ::= ""-"" `integer`" -documenting/markup,849,.. productionlist:,.. productionlist:: -documenting/markup,849,`,"try1_stmt: ""try"" "":"" `suite`" -documenting/markup,849,`,": (""except"" [`expression` ["","" `target`]] "":"" `suite`)+" -documenting/markup,849,`,": [""else"" "":"" `suite`]" -documenting/markup,849,`,": [""finally"" "":"" `suite`]" -documenting/markup,849,`,"try2_stmt: ""try"" "":"" `suite`" -documenting/markup,849,`,": ""finally"" "":"" `suite`" documenting/rest,33,`,``text`` documenting/rest,47,:rolename,:rolename:`content` documenting/rest,47,`,:rolename:`content` @@ -386,3 +293,101 @@ whatsnew/3.2,,:affe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," whatsnew/3.2,,:deaf,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," whatsnew/3.2,,:feed,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +documenting/markup,33,.. sectionauthor:,.. sectionauthor:: Guido van Rossum +documenting/markup,42,:mod,:mod:`parrot` -- Dead parrot access +documenting/markup,42,`,:mod:`parrot` -- Dead parrot access +documenting/markup,42,.. module:,.. module:: parrot +documenting/markup,42,:platform,":platform: Unix, Windows" +documenting/markup,42,:synopsis,:synopsis: Analyze and reanimate dead parrots. +documenting/markup,42,.. moduleauthor:,.. moduleauthor:: Eric Cleese +documenting/markup,42,.. moduleauthor:,.. moduleauthor:: John Idle +documenting/markup,88,:noindex,:noindex: +documenting/markup,95,.. function:,.. function:: spam(eggs) +documenting/markup,95,:noindex,:noindex: +documenting/markup,101,.. method:,.. method:: FileInput.input(...) +documenting/markup,121,:function,c:function +documenting/markup,121,.. c:,".. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)" +documenting/markup,121,::,".. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)" +documenting/markup,131,:member,c:member +documenting/markup,131,.. c:,.. c:member:: PyObject* PyTypeObject.tp_bases +documenting/markup,131,::,.. c:member:: PyObject* PyTypeObject.tp_bases +documenting/markup,139,:macro,c:macro +documenting/markup,143,:type,c:type +documenting/markup,150,:var,c:var +documenting/markup,150,.. cvar:,.. cvar:: PyObject* PyClass_Type +documenting/markup,179,.. function:,".. function:: repeat([repeat=3[, number=1000000]])" +documenting/markup,210,.. decorator:,.. decorator:: removename +documenting/markup,210,.. decorator:,.. decorator:: setnewname(name) +documenting/markup,210,:func,:func: +documenting/markup,237,.. class:,.. class:: Spam +documenting/markup,237,.. data:,.. data:: ham +documenting/markup,237,.. data:,.. data:: Spam.eggs +documenting/markup,250,:meth,:meth: +documenting/markup,263,.. cmdoption:,.. cmdoption:: -m +documenting/markup,281,.. describe:,.. describe:: opcode +documenting/markup,310,.. highlightlang:,.. highlightlang:: c +documenting/markup,330,.. literalinclude:,.. literalinclude:: example.py +documenting/markup,345,:rolename,:rolename:`content` +documenting/markup,345,`,:rolename:`content` +documenting/markup,350,:role,:role:`title ` +documenting/markup,350,`,:role:`title ` +documenting/markup,356,:meth,:meth:`~Queue.Queue.get` +documenting/markup,356,`,:meth:`~Queue.Queue.get` +documenting/markup,404,:func,:func:`filter` +documenting/markup,404,`,:func:`filter` +documenting/markup,404,:func,:func:`foo.filter` +documenting/markup,404,`,:func:`foo.filter` +documenting/markup,410,:func,:func:`open` +documenting/markup,410,`,:func:`open` +documenting/markup,410,:func,:func:`.open` +documenting/markup,410,`,:func:`.open` +documenting/markup,426,:data,c:data +documenting/markup,430,:func,c:func +documenting/markup,434,:macro,c:macro +documenting/markup,438,:type,c:type +documenting/markup,443,:member,c:member +documenting/markup,493,:file,... is installed in :file:`/usr/lib/python2.{x}/site-packages` ... +documenting/markup,493,`,... is installed in :file:`/usr/lib/python2.{x}/site-packages` ... +documenting/markup,512,:kbd,:kbd:`C-x C-f` +documenting/markup,512,`,:kbd:`C-x C-f` +documenting/markup,512,:kbd,:kbd:`Control-x Control-f` +documenting/markup,512,`,:kbd:`Control-x Control-f` +documenting/markup,526,:mailheader,:mailheader:`Content-Type` +documenting/markup,526,`,:mailheader:`Content-Type` +documenting/markup,535,:manpage,:manpage:`ls(1)` +documenting/markup,535,`,:manpage:`ls(1)` +documenting/markup,551,:menuselection,:menuselection:`Start --> Programs` +documenting/markup,551,`,:menuselection:`Start --> Programs` +documenting/markup,566,`,``code`` +documenting/markup,585,:file,:file: +documenting/markup,585,`,``code`` +documenting/markup,615,:ref,:ref:`label-name` +documenting/markup,615,`,:ref:`label-name` +documenting/markup,619,:ref,"It refers to the section itself, see :ref:`my-reference-label`." +documenting/markup,619,`,"It refers to the section itself, see :ref:`my-reference-label`." +documenting/markup,628,:ref,:ref: +documenting/markup,630,:ref,:ref:`link text ` +documenting/markup,630,`,:ref:`link text ` +documenting/markup,651,.. note:,.. note:: +documenting/markup,678,.. versionadded:,.. versionadded:: 3.1 +documenting/markup,703,::,.. impl-detail:: +documenting/markup,703,::,.. impl-detail:: This shortly mentions an implementation detail. +documenting/markup,723,.. seealso:,.. seealso:: +documenting/markup,723,:mod,Module :mod:`zipfile` +documenting/markup,723,`,Module :mod:`zipfile` +documenting/markup,723,:mod,Documentation of the :mod:`zipfile` standard module. +documenting/markup,723,`,Documentation of the :mod:`zipfile` standard module. +documenting/markup,723,`,"`GNU tar manual, Basic Tar Format `_" +documenting/markup,737,.. centered:,.. centered:: +documenting/markup,782,.. toctree:,.. toctree:: +documenting/markup,782,:maxdepth,:maxdepth: 2 +documenting/markup,798,.. index:,.. index:: +documenting/markup,828,.. index:,".. index:: BNF, grammar, syntax, notation" +documenting/markup,859,`,"unaryneg ::= ""-"" `integer`" +documenting/markup,864,.. productionlist:,.. productionlist:: +documenting/markup,864,`,"try1_stmt: ""try"" "":"" `suite`" +documenting/markup,864,`,": (""except"" [`expression` ["","" `target`]] "":"" `suite`)+" +documenting/markup,864,`,": [""else"" "":"" `suite`]" +documenting/markup,864,`,": [""finally"" "":"" `suite`]" +documenting/markup,864,`,"try2_stmt: ""try"" "":"" `suite`" +documenting/markup,864,`,": ""finally"" "":"" `suite`" diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 2 -#define PY_MICRO_VERSION 0 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 +#define PY_MICRO_VERSION 1 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.2.1a0" +#define PY_VERSION "3.2.1b1" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -15,5 +15,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.2" +__version__ = "3.2.1b1" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.2" +IDLE_VERSION = "3.2.1b1" diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Thu Apr 28 07:47:47 2011 +# Autogenerated by Sphinx on Sun May 8 09:06:25 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.\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', diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,10 +2,10 @@ Python News +++++++++++ -What's New in Python 3.2.1? -=========================== - -*Release date: XX-XXX-20XX* +What's New in Python 3.2.1 beta 1? +================================== + +*Release date: 08-May-2011* Core and Builtins ----------------- @@ -18,8 +18,8 @@ clear the end-of-file indicator after CTRL+d. - Issue #1856: Avoid crashes and lockups when daemon threads run while the - interpreter is shutting down; instead, these threads are now killed when - they try to take the GIL. + interpreter is shutting down; instead, these threads are now killed when they + try to take the GIL. - Issue #9756: When calling a method descriptor or a slot wrapper descriptor, the check of the object type doesn't read the __class__ attribute anymore. @@ -31,15 +31,15 @@ the ISO-8859-15 codec. - Issue #10517: After fork(), reinitialize the TLS used by the PyGILState_* - APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch - by Charles-Fran?ois Natali. + APIs, to avoid a crash with the pthread implementation in RHEL 5. Patch by + Charles-Fran?ois Natali. - Issue #6780: fix starts/endswith error message to mention that tuples are accepted too. - Issue #5057: fix a bug in the peepholer that led to non-portable pyc files - between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP - chars (e.g. "\U00012345"[0]). + between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP chars + (e.g. "\U00012345"[0]). - Issue #11845: Fix typo in rangeobject.c that caused a crash in compute_slice_indices. Patch by Daniel Urban. @@ -50,12 +50,12 @@ - Issue #11395: io.FileIO().write() clamps the data length to 32,767 bytes on Windows if the file is a TTY to workaround a Windows bug. The Windows console - returns an error (12: not enough space error) on writing into stdout if - stdout mode is binary and the length is greater than 66,000 bytes (or less, - depending on heap usage). - -- Issue #11320: fix bogus memory management in Modules/getpath.c, leading to - a possible crash when calling Py_SetPath(). + returns an error (12: not enough space error) on writing into stdout if stdout + mode is binary and the length is greater than 66,000 bytes (or less, depending + on heap usage). + +- Issue #11320: fix bogus memory management in Modules/getpath.c, leading to a + possible crash when calling Py_SetPath(). - Issue #11510: Fixed optimizer bug which turned "a,b={1,1}" into "a,b=(1,1)". @@ -63,21 +63,21 @@ 3.2.0 where the stdout or stderr file descriptor being the same as the stdin file descriptor would raise an exception. webbrowser.open would fail. fixed. -- Issue #11450: Don't truncate hg version info in Py_GetBuildInfo() when - there are many tags (e.g. when using mq). Patch by Nadeem Vawda. +- Issue #11450: Don't truncate hg version info in Py_GetBuildInfo() when there + are many tags (e.g. when using mq). Patch by Nadeem Vawda. - Issue #11246: Fix PyUnicode_FromFormat("%V") to decode the byte string from UTF-8 (with replace error handler) instead of ISO-8859-1 (in strict mode). Patch written by Ray Allen. -- Issue #11286: Raise a ValueError from calling PyMemoryView_FromBuffer with - a buffer struct having a NULL data pointer. +- Issue #11286: Raise a ValueError from calling PyMemoryView_FromBuffer with a + buffer struct having a NULL data pointer. - Issue #11272: On Windows, input() strips '\r' (and not only '\n'), and sys.stdin uses universal newline (replace '\r\n' by '\n'). -- issue #11828: startswith and endswith don't accept None as slice index. - Patch by Torsten Becker. +- issue #11828: startswith and endswith don't accept None as slice index. Patch + by Torsten Becker. - Issue #10830: Fix PyUnicode_FromFormatV("%c") for non-BMP characters on narrow build. @@ -112,8 +112,8 @@ - Issue #11164: Stop trying to use _xmlplus in the xml module. -- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch - by Kasun Herath. +- Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by + Kasun Herath. - Issue #12002: ftplib's abort() method raises TypeError. @@ -124,13 +124,13 @@ - ntpath.samefile failed to notice that "a.txt" and "A.TXT" refer to the same file on Windows XP. As noticed in issue #10684. -- Issue #12000: When a SSL certificate has a subjectAltName without any - dNSName entry, ssl.match_hostname() should use the subject's commonName. - Patch by Nicolas Bareil. - -- Issue #11647: objects created using contextlib.contextmanager now support - more than one call to the function when used as a decorator. Initial patch - by Ysj Ray. +- Issue #12000: When a SSL certificate has a subjectAltName without any dNSName + entry, ssl.match_hostname() should use the subject's commonName. Patch by + Nicolas Bareil. + +- Issue #11647: objects created using contextlib.contextmanager now support more + than one call to the function when used as a decorator. Initial patch by Ysj + Ray. - logging: don't define QueueListener if Python has no thread support. @@ -188,13 +188,14 @@ difflib.unified_diff(). - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating - worker processes: new processes would be spawned while the pool is being - shut down. Patch by Charles-Fran?ois Natali. + worker processes: new processes would be spawned while the pool is being shut + down. Patch by Charles-Fran?ois Natali. - Issue #7311: fix html.parser to accept non-ASCII attribute values. -- Issue #11605: email.parser.BytesFeedParser was incorrectly converting multipart - subpararts with an 8bit CTE into unicode instead of preserving the bytes. +- Issue #11605: email.parser.BytesFeedParser was incorrectly converting + multipart subpararts with an 8bit CTE into unicode instead of preserving the + bytes. - Issue #10963: Ensure that subprocess.communicate() never raises EPIPE. @@ -259,8 +260,8 @@ relative to Python2 and the result is now the same as it was in Python2. - Issue #9298: base64 bodies weren't being folded to line lengths less than 78, - which was a regression relative to Python2. Unlike Python2, the last line - of the folded body now ends with a carriage return. + which was a regression relative to Python2. Unlike Python2, the last line of + the folded body now ends with a carriage return. - Issue #11560: shutil.unpack_archive now correctly handles the format parameter. Patch by Evan Dandrea. @@ -269,8 +270,8 @@ execution. Patch by Andreas St?hrk. - Issue #11569: use absolute path to the sysctl command in multiprocessing to - ensure that it will be found regardless of the shell PATH. This ensures - that multiprocessing.cpu_count works on default installs of MacOSX. + ensure that it will be found regardless of the shell PATH. This ensures that + multiprocessing.cpu_count works on default installs of MacOSX. - Issue #11501: disutils.archive_utils.make_zipfile no longer fails if zlib is not installed. Instead, the zipfile.ZIP_STORED compression is used to create @@ -279,15 +280,15 @@ - Issue #11554: Fixed support for Japanese codecs; previously the body output encoding was not done if euc-jp or shift-jis was specified as the charset. -- Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified - IP addresses in the proxy exception list. - -- Issue #11491: dbm.error is no longer raised when dbm.open is called with - the "n" as the flag argument and the file exists. The behavior matches - the documentation and general logic. - -- Issue #11131: Fix sign of zero in decimal.Decimal plus and minus - operations when the rounding mode is ROUND_FLOOR. +- Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified IP + addresses in the proxy exception list. + +- Issue #11491: dbm.error is no longer raised when dbm.open is called with the + "n" as the flag argument and the file exists. The behavior matches the + documentation and general logic. + +- Issue #11131: Fix sign of zero in decimal.Decimal plus and minus operations + when the rounding mode is ROUND_FLOOR. - Issue #5622: Fix curses.wrapper to raise correct exception if curses initialization fails. @@ -296,12 +297,12 @@ ``mmap.PROT_READ|mmap.PROT_EXEC`` would segfault instead of raising a TypeError. Patch by Charles-Fran?ois Natali. -- Issue #11306: mailbox in certain cases adapts to an inability to open - certain files in read-write mode. Previously it detected this by - checking for EACCES, now it also checks for EROFS. - -- Issue #11265: asyncore now correctly handles EPIPE, EBADF and EAGAIN errors - on accept(), send() and recv(). +- Issue #11306: mailbox in certain cases adapts to an inability to open certain + files in read-write mode. Previously it detected this by checking for EACCES, + now it also checks for EROFS. + +- Issue #11265: asyncore now correctly handles EPIPE, EBADF and EAGAIN errors on + accept(), send() and recv(). - Issue #11326: Add the missing connect_ex() implementation for SSL sockets, and make it work for non-blocking connects. @@ -346,14 +347,14 @@ - Issue #11411: Fix 'make DESTDIR=' with a relative destination. -- Issue #11268: Prevent Mac OS X Installer failure if Documentation - package had previously been installed. +- Issue #11268: Prevent Mac OS X Installer failure if Documentation package had + previously been installed. IDLE ---- -- Issue #11718: IDLE's open module dialog couldn't find the __init__.py - file in a package. +- Issue #11718: IDLE's open module dialog couldn't find the __init__.py file in + a package. Tools/Demos ----------- @@ -380,7 +381,8 @@ - Issue #10914: Add a minimal embedding test to test_capi. -- Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition. +- Issue #11790: Fix sporadic failures in + test_multiprocessing.WithProcessesTestCondition. - Fix possible "file already exists" error when running the tests in parallel. diff --git a/Misc/RPM/python-3.2.spec b/Misc/RPM/python-3.2.spec --- a/Misc/RPM/python-3.2.spec +++ b/Misc/RPM/python-3.2.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.2 +%define version 3.2.1b1 %define libvers 3.2 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Python version 3.2 -========================== +This is Python version 3.2.1 beta 1 +=================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Python Software Foundation. All rights reserved. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 07:01:57 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 13 May 2011 07:01:57 +0200 Subject: [Python-checkins] cpython (3.2): Fix unbound local error in RE tokenizer example. Thanks to Herman L. Jackson. Message-ID: http://hg.python.org/cpython/rev/538a6b23b18f changeset: 70066:538a6b23b18f branch: 3.2 user: Georg Brandl date: Fri May 13 06:54:23 2011 +0200 summary: Fix unbound local error in RE tokenizer example. Thanks to Herman L. Jackson. files: Doc/library/re.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1322,9 +1322,10 @@ line_start = pos line += 1 elif typ != 'SKIP': + val = mo.group(typ) if typ == 'ID' and val in keywords: typ = val - yield Token(typ, mo.group(typ), line, mo.start()-line_start) + yield Token(typ, val, line, mo.start()-line_start) pos = mo.end() mo = gettok(s, pos) if pos != len(s): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 07:01:57 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 13 May 2011 07:01:57 +0200 Subject: [Python-checkins] cpython (3.2): Use singular they. Thanks to Mark Summerfield. Message-ID: http://hg.python.org/cpython/rev/856739c3aceb changeset: 70067:856739c3aceb branch: 3.2 user: Georg Brandl date: Fri May 13 06:55:28 2011 +0200 summary: Use singular they. Thanks to Mark Summerfield. files: Doc/library/sys.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -814,7 +814,7 @@ Python. The highest possible limit is platform-dependent. A user may need to set the - limit higher when she has a program that requires deep recursion and a platform + limit higher when they have a program that requires deep recursion and a platform that supports a higher limit. This should be done with care, because a too-high limit can lead to a crash. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 07:01:58 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 13 May 2011 07:01:58 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge 3.2.1 release changes into default branch (a null merge except for the Message-ID: http://hg.python.org/cpython/rev/35fb619bf1b1 changeset: 70068:35fb619bf1b1 parent: 70059:05e0227e3879 parent: 70065:e7698ce2d2bf user: Georg Brandl date: Fri May 13 07:01:42 2011 +0200 summary: Merge 3.2.1 release changes into default branch (a null merge except for the new tag.) files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -85,3 +85,4 @@ acf3e24dd0d0dfd1e20c907d696d3da965a8f56f v3.2rc2 18c1f52896501c7ee13b038454a39acb45a87979 v3.2rc3 a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 +8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 07:01:59 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 13 May 2011 07:01:59 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge two minor doc changes into default. Message-ID: http://hg.python.org/cpython/rev/12a2c1085621 changeset: 70069:12a2c1085621 parent: 70068:35fb619bf1b1 parent: 70067:856739c3aceb user: Georg Brandl date: Fri May 13 07:01:58 2011 +0200 summary: Merge two minor doc changes into default. files: Doc/library/re.rst | 3 ++- Doc/library/sys.rst | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1325,9 +1325,10 @@ line_start = pos line += 1 elif typ != 'SKIP': + val = mo.group(typ) if typ == 'ID' and val in keywords: typ = val - yield Token(typ, mo.group(typ), line, mo.start()-line_start) + yield Token(typ, val, line, mo.start()-line_start) pos = mo.end() mo = gettok(s, pos) if pos != len(s): diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -805,7 +805,7 @@ Python. The highest possible limit is platform-dependent. A user may need to set the - limit higher when she has a program that requires deep recursion and a platform + limit higher when they have a program that requires deep recursion and a platform that supports a higher limit. This should be done with care, because a too-high limit can lead to a crash. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 08:09:47 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 13 May 2011 08:09:47 +0200 Subject: [Python-checkins] cpython: Added diagnostics to test_logging, after reverting last change. Message-ID: http://hg.python.org/cpython/rev/b609a1701976 changeset: 70070:b609a1701976 user: Vinay Sajip date: Fri May 13 07:09:40 2011 +0100 summary: Added diagnostics to test_logging, after reverting last change. files: Lib/test/test_logging.py | 21 ++++++++++++--------- 1 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3502,7 +3502,6 @@ fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S', backupCount=1) r = logging.makeLogRecord({'msg': 'testing'}) - start = datetime.datetime.now() fh.emit(r) self.assertLogFile(self.fn) time.sleep(1.0) @@ -3511,21 +3510,25 @@ # At this point, we should have a recent rotated file which we # can test for the existence of. However, in practice, on some # machines which run really slowly, we don't know how far back - # in time to go to look for the log file. So, we go back as far as - # when the test started, and stop as soon as we see a rotated file. + # in time to go to look for the log file. So, we go back a fair + # bit, and stop as soon as we see a rotated file. In theory this + # could of course still fail, but the chances are lower. found = False now = datetime.datetime.now() - secs = 1 - prev = now - datetime.timedelta(seconds=secs) - while prev > start: + GO_BACK = 2 * 60 # seconds + for secs in range(GO_BACK): + prev = now - datetime.timedelta(seconds=secs) fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S") found = os.path.exists(fn) if found: self.rmfiles.append(fn) break - secs += 1 - prev -= datetime.timedelta(seconds=1) - msg = 'No rotated files found, went back %d seconds' % secs + msg = 'No rotated files found, went back %d seconds' % GO_BACK + if not found: + #print additional diagnostics + dn = os.path.dirname(self.fn) + files = [f for f in os.listdir(dn) if f.startswith(self.fn)] + print('The only matching files are: %s' % files) self.assertTrue(found, msg=msg) def test_invalid(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 10:04:53 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 13 May 2011 10:04:53 +0200 Subject: [Python-checkins] cpython (3.2): Neaten up example so it can be cut and pasted. Message-ID: http://hg.python.org/cpython/rev/512f638dc9e9 changeset: 70071:512f638dc9e9 branch: 3.2 parent: 70067:856739c3aceb user: Raymond Hettinger date: Fri May 13 01:03:50 2011 -0700 summary: Neaten up example so it can be cut and pasted. files: Doc/library/re.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1336,8 +1336,8 @@ tax := price * 0.05; ''' >>> for token in tokenize(statements): - ... print(token) - ... + print(token) + Token(typ='ID', value='total', line=1, column=8) Token(typ='ASSIGN', value=':=', line=1, column=14) Token(typ='ID', value='total', line=1, column=17) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 10:04:55 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 13 May 2011 10:04:55 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Neaten up example so it can be cut and pasted. Message-ID: http://hg.python.org/cpython/rev/ee7312a1eeb7 changeset: 70072:ee7312a1eeb7 parent: 70070:b609a1701976 parent: 70071:512f638dc9e9 user: Raymond Hettinger date: Fri May 13 01:04:45 2011 -0700 summary: Neaten up example so it can be cut and pasted. files: Doc/library/re.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1339,8 +1339,8 @@ tax := price * 0.05; ''' >>> for token in tokenize(statements): - ... print(token) - ... + print(token) + Token(typ='ID', value='total', line=1, column=8) Token(typ='ASSIGN', value=':=', line=1, column=14) Token(typ='ID', value='total', line=1, column=17) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 10:39:31 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 13 May 2011 10:39:31 +0200 Subject: [Python-checkins] cpython (3.2): Further beautification of the example Message-ID: http://hg.python.org/cpython/rev/486112dcba0c changeset: 70073:486112dcba0c branch: 3.2 parent: 70071:512f638dc9e9 user: Raymond Hettinger date: Fri May 13 01:38:31 2011 -0700 summary: Further beautification of the example files: Doc/library/re.rst | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1331,12 +1331,15 @@ if pos != len(s): raise RuntimeError('Unexpected character %r on line %d' %(s[pos], line)) - >>> statements = '''\ + statements = '''\ total := total + price * quantity; tax := price * 0.05; ''' - >>> for token in tokenize(statements): - print(token) + + for token in tokenize(statements): + print(token) + +The tokenizer produces the following output:: Token(typ='ID', value='total', line=1, column=8) Token(typ='ASSIGN', value=':=', line=1, column=14) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 10:39:32 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 13 May 2011 10:39:32 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Further beautification of the example Message-ID: http://hg.python.org/cpython/rev/6d8678555c04 changeset: 70074:6d8678555c04 parent: 70072:ee7312a1eeb7 parent: 70073:486112dcba0c user: Raymond Hettinger date: Fri May 13 01:39:22 2011 -0700 summary: Further beautification of the example files: Doc/library/re.rst | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1334,12 +1334,15 @@ if pos != len(s): raise RuntimeError('Unexpected character %r on line %d' %(s[pos], line)) - >>> statements = '''\ + statements = '''\ total := total + price * quantity; tax := price * 0.05; ''' - >>> for token in tokenize(statements): - print(token) + + for token in tokenize(statements): + print(token) + +The tokenizer produces the following output:: Token(typ='ID', value='total', line=1, column=8) Token(typ='ASSIGN', value=':=', line=1, column=14) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 13:16:10 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 13 May 2011 13:16:10 +0200 Subject: [Python-checkins] cpython: Issue #12068: Fix appears to have worked; added more diagnostics for rare Message-ID: http://hg.python.org/cpython/rev/660a4a6dc2cd changeset: 70075:660a4a6dc2cd user: Vinay Sajip date: Fri May 13 12:16:04 2011 +0100 summary: Issue #12068: Fix appears to have worked; added more diagnostics for rare failures. files: Lib/test/test_logging.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3528,6 +3528,7 @@ #print additional diagnostics dn = os.path.dirname(self.fn) files = [f for f in os.listdir(dn) if f.startswith(self.fn)] + print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S")) print('The only matching files are: %s' % files) self.assertTrue(found, msg=msg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 15:45:15 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 13 May 2011 15:45:15 +0200 Subject: [Python-checkins] cpython: test_logging: fixed bug in failure diagnostics. Message-ID: http://hg.python.org/cpython/rev/dfa442d1ce12 changeset: 70076:dfa442d1ce12 user: Vinay Sajip date: Fri May 13 14:45:08 2011 +0100 summary: test_logging: fixed bug in failure diagnostics. files: Lib/test/test_logging.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3526,8 +3526,8 @@ msg = 'No rotated files found, went back %d seconds' % GO_BACK if not found: #print additional diagnostics - dn = os.path.dirname(self.fn) - files = [f for f in os.listdir(dn) if f.startswith(self.fn)] + dn, fn = os.path.split(self.fn) + files = [f for f in os.listdir(dn) if f.startswith(fn)] print('Test time: %s' % now.strftime("%Y-%m-%d %H-%M-%S")) print('The only matching files are: %s' % files) self.assertTrue(found, msg=msg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 17:42:04 2011 From: python-checkins at python.org (vinay.sajip) Date: Fri, 13 May 2011 17:42:04 +0200 Subject: [Python-checkins] cpython: test_logging: extended time range for rollover test. Message-ID: http://hg.python.org/cpython/rev/806f136bb9f2 changeset: 70077:806f136bb9f2 user: Vinay Sajip date: Fri May 13 16:41:57 2011 +0100 summary: test_logging: extended time range for rollover test. files: Lib/test/test_logging.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3515,7 +3515,7 @@ # could of course still fail, but the chances are lower. found = False now = datetime.datetime.now() - GO_BACK = 2 * 60 # seconds + GO_BACK = 5 * 60 # seconds for secs in range(GO_BACK): prev = now - datetime.timedelta(seconds=secs) fn = self.fn + prev.strftime(".%Y-%m-%d_%H-%M-%S") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 17:53:26 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 13 May 2011 17:53:26 +0200 Subject: [Python-checkins] cpython (3.2): Issue #11996: libpython (gdb), replace "py-bt" command by "py-bt-full" and add Message-ID: http://hg.python.org/cpython/rev/b340d1577dc5 changeset: 70078:b340d1577dc5 branch: 3.2 parent: 70073:486112dcba0c user: Victor Stinner date: Fri May 13 17:40:15 2011 +0200 summary: Issue #11996: libpython (gdb), replace "py-bt" command by "py-bt-full" and add a smarter "py-bt" command printing a classic Python traceback. files: Lib/test/test_gdb.py | 19 +++++++++++++- Misc/NEWS | 3 ++ Tools/gdb/libpython.py | 41 +++++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -611,12 +611,29 @@ $''') class PyBtTests(DebuggerTests): - def test_basic_command(self): + def test_bt(self): 'Verify that the "py-bt" command works' bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-bt']) self.assertMultilineMatches(bt, r'''^.* +Traceback \(most recent call first\): + File ".*gdb_sample.py", line 10, in baz + id\(42\) + File ".*gdb_sample.py", line 7, in bar + baz\(a, b, c\) + File ".*gdb_sample.py", line 4, in foo + bar\(a, b, c\) + File ".*gdb_sample.py", line 12, in + foo\(1, 2, 3\) +''') + + def test_bt_full(self): + 'Verify that the "py-bt-full" command works' + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-bt-full']) + self.assertMultilineMatches(bt, + r'''^.* #[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) baz\(a, b, c\) #[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -359,6 +359,9 @@ Tools/Demos ----------- +- Issue #11996: libpython (gdb), replace "py-bt" command by "py-bt-full" and + add a smarter "py-bt" command printing a classic Python traceback. + - Issue #11179: Make ccbench work under Python 3.1 and 2.7 again. Extension Modules diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -931,6 +931,15 @@ out.write(')') + def print_traceback(self): + if self.is_optimized_out(): + sys.stdout.write(' (frame information optimized out)\n') + visited = set() + sys.stdout.write(' File "%s", line %i, in %s\n' + % (self.co_filename.proxyval(visited), + self.current_line_num(), + self.co_name.proxyval(visited))) + class PySetObjectPtr(PyObjectPtr): _typename = 'PySetObject' @@ -1427,6 +1436,17 @@ else: sys.stdout.write('#%i\n' % self.get_index()) + def print_traceback(self): + if self.is_evalframeex(): + pyop = self.get_pyop() + if pyop: + pyop.print_traceback() + sys.stdout.write(' %s\n' % pyop.current_line().strip()) + else: + sys.stdout.write(' (unable to read python frame information)\n') + else: + sys.stdout.write(' (not a python frame)\n') + class PyList(gdb.Command): '''List the current Python source code, if any @@ -1551,6 +1571,24 @@ PyUp() PyDown() +class PyBacktraceFull(gdb.Command): + 'Display the current python frame and all the frames within its call stack (if any)' + def __init__(self): + gdb.Command.__init__ (self, + "py-bt-full", + gdb.COMMAND_STACK, + gdb.COMPLETE_NONE) + + + def invoke(self, args, from_tty): + frame = Frame.get_selected_python_frame() + while frame: + if frame.is_evalframeex(): + frame.print_summary() + frame = frame.older() + +PyBacktraceFull() + class PyBacktrace(gdb.Command): 'Display the current python frame and all the frames within its call stack (if any)' def __init__(self): @@ -1561,10 +1599,11 @@ def invoke(self, args, from_tty): + sys.stdout.write('Traceback (most recent call first):\n') frame = Frame.get_selected_python_frame() while frame: if frame.is_evalframeex(): - frame.print_summary() + frame.print_traceback() frame = frame.older() PyBacktrace() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 13 17:53:27 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 13 May 2011 17:53:27 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #11996: libpython (gdb), replace "py-bt" command by Message-ID: http://hg.python.org/cpython/rev/804abc2c60de changeset: 70079:804abc2c60de parent: 70077:806f136bb9f2 parent: 70078:b340d1577dc5 user: Victor Stinner date: Fri May 13 17:53:22 2011 +0200 summary: (Merge 3.2) Issue #11996: libpython (gdb), replace "py-bt" command by "py-bt-full" and add a smarter "py-bt" command printing a classic Python traceback. files: Lib/test/test_gdb.py | 19 +++++++++++++- Misc/NEWS | 3 ++ Tools/gdb/libpython.py | 41 +++++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -611,12 +611,29 @@ $''') class PyBtTests(DebuggerTests): - def test_basic_command(self): + def test_bt(self): 'Verify that the "py-bt" command works' bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-bt']) self.assertMultilineMatches(bt, r'''^.* +Traceback \(most recent call first\): + File ".*gdb_sample.py", line 10, in baz + id\(42\) + File ".*gdb_sample.py", line 7, in bar + baz\(a, b, c\) + File ".*gdb_sample.py", line 4, in foo + bar\(a, b, c\) + File ".*gdb_sample.py", line 12, in + foo\(1, 2, 3\) +''') + + def test_bt_full(self): + 'Verify that the "py-bt-full" command works' + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-bt-full']) + self.assertMultilineMatches(bt, + r'''^.* #[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) baz\(a, b, c\) #[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -639,6 +639,9 @@ Tools/Demos ----------- +- Issue #11996: libpython (gdb), replace "py-bt" command by "py-bt-full" and + add a smarter "py-bt" command printing a classic Python traceback. + - Issue #11179: Make ccbench work under Python 3.1 and 2.7 again. Extension Modules diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -931,6 +931,15 @@ out.write(')') + def print_traceback(self): + if self.is_optimized_out(): + sys.stdout.write(' (frame information optimized out)\n') + visited = set() + sys.stdout.write(' File "%s", line %i, in %s\n' + % (self.co_filename.proxyval(visited), + self.current_line_num(), + self.co_name.proxyval(visited))) + class PySetObjectPtr(PyObjectPtr): _typename = 'PySetObject' @@ -1427,6 +1436,17 @@ else: sys.stdout.write('#%i\n' % self.get_index()) + def print_traceback(self): + if self.is_evalframeex(): + pyop = self.get_pyop() + if pyop: + pyop.print_traceback() + sys.stdout.write(' %s\n' % pyop.current_line().strip()) + else: + sys.stdout.write(' (unable to read python frame information)\n') + else: + sys.stdout.write(' (not a python frame)\n') + class PyList(gdb.Command): '''List the current Python source code, if any @@ -1551,6 +1571,24 @@ PyUp() PyDown() +class PyBacktraceFull(gdb.Command): + 'Display the current python frame and all the frames within its call stack (if any)' + def __init__(self): + gdb.Command.__init__ (self, + "py-bt-full", + gdb.COMMAND_STACK, + gdb.COMPLETE_NONE) + + + def invoke(self, args, from_tty): + frame = Frame.get_selected_python_frame() + while frame: + if frame.is_evalframeex(): + frame.print_summary() + frame = frame.older() + +PyBacktraceFull() + class PyBacktrace(gdb.Command): 'Display the current python frame and all the frames within its call stack (if any)' def __init__(self): @@ -1561,10 +1599,11 @@ def invoke(self, args, from_tty): + sys.stdout.write('Traceback (most recent call first):\n') frame = Frame.get_selected_python_frame() while frame: if frame.is_evalframeex(): - frame.print_summary() + frame.print_traceback() frame = frame.older() PyBacktrace() -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat May 14 05:00:43 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 14 May 2011 05:00:43 +0200 Subject: [Python-checkins] Daily reference leaks (804abc2c60de): sum=0 Message-ID: results for 804abc2c60de on branch "default" -------------------------------------------- test_pydoc leaked [0, -323, 323] references, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogdgIa5D', '-x'] From python-checkins at python.org Sat May 14 05:24:30 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 05:24:30 +0200 Subject: [Python-checkins] cpython (2.7): Change import_fresh_module to work with packages. Message-ID: http://hg.python.org/cpython/rev/49ffa5c30951 changeset: 70080:49ffa5c30951 branch: 2.7 parent: 70061:ac14158462cf user: Ezio Melotti date: Sat May 14 06:02:25 2011 +0300 summary: Change import_fresh_module to work with packages. files: Lib/test/test_support.py | 16 ++++++---------- 1 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -84,19 +84,15 @@ def _save_and_remove_module(name, orig_modules): """Helper function to save and remove a module from sys.modules - Return True if the module was in sys.modules, False otherwise. Raise ImportError if the module can't be imported.""" - saved = True - try: - orig_modules[name] = sys.modules[name] - except KeyError: - # try to import the module and raise an error if it can't be imported + # try to import the module and raise an error if it can't be imported + if name not in sys.modules: __import__(name) - saved = False - else: del sys.modules[name] - return saved - + for modname in list(sys.modules): + if modname == name or modname.startswith(name + '.'): + orig_modules[modname] = sys.modules[modname] + del sys.modules[modname] def _save_and_block_module(name, orig_modules): """Helper function to save and block a module in sys.modules -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 05:24:31 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 05:24:31 +0200 Subject: [Python-checkins] cpython (3.1): Change import_fresh_module to work with packages. Message-ID: http://hg.python.org/cpython/rev/9b7bfe86f04d changeset: 70081:9b7bfe86f04d branch: 3.1 parent: 70057:89f77afac947 user: Ezio Melotti date: Sat May 14 06:02:25 2011 +0300 summary: Change import_fresh_module to work with packages. files: Lib/test/support.py | 16 ++++++---------- 1 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -80,19 +80,15 @@ def _save_and_remove_module(name, orig_modules): """Helper function to save and remove a module from sys.modules - Return True if the module was in sys.modules, False otherwise. Raise ImportError if the module can't be imported.""" - saved = True - try: - orig_modules[name] = sys.modules[name] - except KeyError: - # try to import the module and raise an error if it can't be imported + # try to import the module and raise an error if it can't be imported + if name not in sys.modules: __import__(name) - saved = False - else: del sys.modules[name] - return saved - + for modname in list(sys.modules): + if modname == name or modname.startswith(name + '.'): + orig_modules[modname] = sys.modules[modname] + del sys.modules[modname] def _save_and_block_module(name, orig_modules): """Helper function to save and block a module in sys.modules -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 05:24:32 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 05:24:32 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/688962b8a175 changeset: 70082:688962b8a175 branch: 3.2 parent: 70078:b340d1577dc5 parent: 70081:9b7bfe86f04d user: Ezio Melotti date: Sat May 14 06:23:20 2011 +0300 summary: Merge with 3.1. files: Lib/test/support.py | 16 ++++++---------- 1 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -92,19 +92,15 @@ def _save_and_remove_module(name, orig_modules): """Helper function to save and remove a module from sys.modules - Return True if the module was in sys.modules, False otherwise. Raise ImportError if the module can't be imported.""" - saved = True - try: - orig_modules[name] = sys.modules[name] - except KeyError: - # try to import the module and raise an error if it can't be imported + # try to import the module and raise an error if it can't be imported + if name not in sys.modules: __import__(name) - saved = False - else: del sys.modules[name] - return saved - + for modname in list(sys.modules): + if modname == name or modname.startswith(name + '.'): + orig_modules[modname] = sys.modules[modname] + del sys.modules[modname] def _save_and_block_module(name, orig_modules): """Helper function to save and block a module in sys.modules -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 05:24:33 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 05:24:33 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/d6d222a96172 changeset: 70083:d6d222a96172 parent: 70079:804abc2c60de parent: 70082:688962b8a175 user: Ezio Melotti date: Sat May 14 06:24:18 2011 +0300 summary: Merge with 3.2. files: Lib/test/support.py | 16 ++++++---------- 1 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -91,19 +91,15 @@ def _save_and_remove_module(name, orig_modules): """Helper function to save and remove a module from sys.modules - Return True if the module was in sys.modules, False otherwise. Raise ImportError if the module can't be imported.""" - saved = True - try: - orig_modules[name] = sys.modules[name] - except KeyError: - # try to import the module and raise an error if it can't be imported + # try to import the module and raise an error if it can't be imported + if name not in sys.modules: __import__(name) - saved = False - else: del sys.modules[name] - return saved - + for modname in list(sys.modules): + if modname == name or modname.startswith(name + '.'): + orig_modules[modname] = sys.modules[modname] + del sys.modules[modname] def _save_and_block_module(name, orig_modules): """Helper function to save and block a module in sys.modules -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 05:53:16 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 05:53:16 +0200 Subject: [Python-checkins] cpython (2.7): #5723: Improve json tests to be executed with and without accelerations. Message-ID: http://hg.python.org/cpython/rev/5b0fecd2eba0 changeset: 70084:5b0fecd2eba0 branch: 2.7 parent: 70080:49ffa5c30951 user: Ezio Melotti date: Sat May 14 06:24:53 2011 +0300 summary: #5723: Improve json tests to be executed with and without accelerations. files: Lib/json/decoder.py | 4 +- Lib/json/tests/__init__.py | 46 ++++++- Lib/json/tests/test_check_circular.py | 24 ++- Lib/json/tests/test_decode.py | 37 +++-- Lib/json/tests/test_default.py | 13 +- Lib/json/tests/test_dump.py | 16 +- Lib/json/tests/test_encode_basestring_ascii.py | 28 +-- Lib/json/tests/test_fail.py | 18 +- Lib/json/tests/test_float.py | 23 +- Lib/json/tests/test_indent.py | 23 +- Lib/json/tests/test_pass1.py | 17 +- Lib/json/tests/test_pass2.py | 16 +- Lib/json/tests/test_pass3.py | 16 +- Lib/json/tests/test_recursion.py | 66 +++++---- Lib/json/tests/test_scanstring.py | 32 +--- Lib/json/tests/test_separators.py | 18 +- Lib/json/tests/test_speedups.py | 28 +-- Lib/json/tests/test_unicode.py | 53 ++++--- Lib/test/test_support.py | 4 +- Misc/NEWS | 2 + 20 files changed, 271 insertions(+), 213 deletions(-) diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -4,7 +4,7 @@ import sys import struct -from json.scanner import make_scanner +from json import scanner try: from _json import scanstring as c_scanstring except ImportError: @@ -356,7 +356,7 @@ self.parse_object = JSONObject self.parse_array = JSONArray self.parse_string = scanstring - self.scan_once = make_scanner(self) + self.scan_once = scanner.make_scanner(self) def decode(self, s, _w=WHITESPACE.match): """Return the Python representation of ``s`` (a ``str`` or ``unicode`` diff --git a/Lib/json/tests/__init__.py b/Lib/json/tests/__init__.py --- a/Lib/json/tests/__init__.py +++ b/Lib/json/tests/__init__.py @@ -1,7 +1,46 @@ import os import sys +import json +import doctest import unittest -import doctest + +from test import test_support + +# import json with and without accelerations +cjson = test_support.import_fresh_module('json', fresh=['_json']) +pyjson = test_support.import_fresh_module('json', blocked=['_json']) + +# create two base classes that will be used by the other tests +class PyTest(unittest.TestCase): + json = pyjson + loads = staticmethod(pyjson.loads) + dumps = staticmethod(pyjson.dumps) + + at unittest.skipUnless(cjson, 'requires _json') +class CTest(unittest.TestCase): + if cjson is not None: + json = cjson + loads = staticmethod(cjson.loads) + dumps = staticmethod(cjson.dumps) + +# test PyTest and CTest checking if the functions come from the right module +class TestPyTest(PyTest): + def test_pyjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, + 'json.scanner') + self.assertEqual(self.json.decoder.scanstring.__module__, + 'json.decoder') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + 'json.encoder') + +class TestCTest(CTest): + def test_cjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, '_json') + self.assertEqual(self.json.decoder.scanstring.__module__, '_json') + self.assertEqual(self.json.encoder.c_make_encoder.__module__, '_json') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + '_json') + here = os.path.dirname(__file__) @@ -17,12 +56,11 @@ return suite def additional_tests(): - import json - import json.encoder - import json.decoder suite = unittest.TestSuite() for mod in (json, json.encoder, json.decoder): suite.addTest(doctest.DocTestSuite(mod)) + suite.addTest(TestPyTest('test_pyjson')) + suite.addTest(TestCTest('test_cjson')) return suite def main(): diff --git a/Lib/json/tests/test_check_circular.py b/Lib/json/tests/test_check_circular.py --- a/Lib/json/tests/test_check_circular.py +++ b/Lib/json/tests/test_check_circular.py @@ -1,30 +1,34 @@ -from unittest import TestCase -import json +from json.tests import PyTest, CTest + def default_iterable(obj): return list(obj) -class TestCheckCircular(TestCase): +class TestCheckCircular(object): def test_circular_dict(self): dct = {} dct['a'] = dct - self.assertRaises(ValueError, json.dumps, dct) + self.assertRaises(ValueError, self.dumps, dct) def test_circular_list(self): lst = [] lst.append(lst) - self.assertRaises(ValueError, json.dumps, lst) + self.assertRaises(ValueError, self.dumps, lst) def test_circular_composite(self): dct2 = {} dct2['a'] = [] dct2['a'].append(dct2) - self.assertRaises(ValueError, json.dumps, dct2) + self.assertRaises(ValueError, self.dumps, dct2) def test_circular_default(self): - json.dumps([set()], default=default_iterable) - self.assertRaises(TypeError, json.dumps, [set()]) + self.dumps([set()], default=default_iterable) + self.assertRaises(TypeError, self.dumps, [set()]) def test_circular_off_default(self): - json.dumps([set()], default=default_iterable, check_circular=False) - self.assertRaises(TypeError, json.dumps, [set()], check_circular=False) + self.dumps([set()], default=default_iterable, check_circular=False) + self.assertRaises(TypeError, self.dumps, [set()], check_circular=False) + + +class TestPyCheckCircular(TestCheckCircular, PyTest): pass +class TestCCheckCircular(TestCheckCircular, CTest): pass diff --git a/Lib/json/tests/test_decode.py b/Lib/json/tests/test_decode.py --- a/Lib/json/tests/test_decode.py +++ b/Lib/json/tests/test_decode.py @@ -1,18 +1,17 @@ import decimal -from unittest import TestCase from StringIO import StringIO +from collections import OrderedDict +from json.tests import PyTest, CTest -import json -from collections import OrderedDict -class TestDecode(TestCase): +class TestDecode(object): def test_decimal(self): - rval = json.loads('1.1', parse_float=decimal.Decimal) + rval = self.loads('1.1', parse_float=decimal.Decimal) self.assertTrue(isinstance(rval, decimal.Decimal)) self.assertEqual(rval, decimal.Decimal('1.1')) def test_float(self): - rval = json.loads('1', parse_int=float) + rval = self.loads('1', parse_int=float) self.assertTrue(isinstance(rval, float)) self.assertEqual(rval, 1.0) @@ -20,28 +19,32 @@ # Several optimizations were made that skip over calls to # the whitespace regex, so this test is designed to try and # exercise the uncommon cases. The array cases are already covered. - rval = json.loads('{ "key" : "value" , "k":"v" }') + rval = self.loads('{ "key" : "value" , "k":"v" }') self.assertEqual(rval, {"key":"value", "k":"v"}) def test_empty_objects(self): - self.assertEqual(json.loads('{}'), {}) - self.assertEqual(json.loads('[]'), []) - self.assertEqual(json.loads('""'), u"") - self.assertIsInstance(json.loads('""'), unicode) + self.assertEqual(self.loads('{}'), {}) + self.assertEqual(self.loads('[]'), []) + self.assertEqual(self.loads('""'), u"") + self.assertIsInstance(self.loads('""'), unicode) def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook=lambda x: x), p) - self.assertEqual(json.load(StringIO(s), - object_pairs_hook=lambda x: x), p) - od = json.loads(s, object_pairs_hook=OrderedDict) + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook=lambda x: x), p) + self.assertEqual(self.json.load(StringIO(s), + object_pairs_hook=lambda x: x), p) + od = self.loads(s, object_pairs_hook=OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, + self.assertEqual(self.loads(s, object_pairs_hook=OrderedDict, object_hook=lambda x: None), OrderedDict(p)) + + +class TestPyDecode(TestDecode, PyTest): pass +class TestCDecode(TestDecode, CTest): pass diff --git a/Lib/json/tests/test_default.py b/Lib/json/tests/test_default.py --- a/Lib/json/tests/test_default.py +++ b/Lib/json/tests/test_default.py @@ -1,9 +1,12 @@ -from unittest import TestCase +from json.tests import PyTest, CTest -import json -class TestDefault(TestCase): +class TestDefault(object): def test_default(self): self.assertEqual( - json.dumps(type, default=repr), - json.dumps(repr(type))) + self.dumps(type, default=repr), + self.dumps(repr(type))) + + +class TestPyDefault(TestDefault, PyTest): pass +class TestCDefault(TestDefault, CTest): pass diff --git a/Lib/json/tests/test_dump.py b/Lib/json/tests/test_dump.py --- a/Lib/json/tests/test_dump.py +++ b/Lib/json/tests/test_dump.py @@ -1,21 +1,23 @@ -from unittest import TestCase from cStringIO import StringIO +from json.tests import PyTest, CTest -import json -class TestDump(TestCase): +class TestDump(object): def test_dump(self): sio = StringIO() - json.dump({}, sio) + self.json.dump({}, sio) self.assertEqual(sio.getvalue(), '{}') def test_dumps(self): - self.assertEqual(json.dumps({}), '{}') + self.assertEqual(self.dumps({}), '{}') def test_encode_truefalse(self): - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {True: False, False: True}, sort_keys=True), '{"false": true, "true": false}') - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {2: 3.0, 4.0: 5L, False: 1, 6L: True}, sort_keys=True), '{"false": 1, "2": 3.0, "4.0": 5, "6": true}') + +class TestPyDump(TestDump, PyTest): pass +class TestCDump(TestDump, CTest): pass diff --git a/Lib/json/tests/test_encode_basestring_ascii.py b/Lib/json/tests/test_encode_basestring_ascii.py --- a/Lib/json/tests/test_encode_basestring_ascii.py +++ b/Lib/json/tests/test_encode_basestring_ascii.py @@ -1,8 +1,6 @@ -from unittest import TestCase +from collections import OrderedDict +from json.tests import PyTest, CTest -import json.encoder -from json import dumps -from collections import OrderedDict CASES = [ (u'/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'), @@ -23,19 +21,11 @@ (u'\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), ] -class TestEncodeBaseStringAscii(TestCase): - def test_py_encode_basestring_ascii(self): - self._test_encode_basestring_ascii(json.encoder.py_encode_basestring_ascii) - - def test_c_encode_basestring_ascii(self): - if not json.encoder.c_encode_basestring_ascii: - return - self._test_encode_basestring_ascii(json.encoder.c_encode_basestring_ascii) - - def _test_encode_basestring_ascii(self, encode_basestring_ascii): - fname = encode_basestring_ascii.__name__ +class TestEncodeBasestringAscii(object): + def test_encode_basestring_ascii(self): + fname = self.json.encoder.encode_basestring_ascii.__name__ for input_string, expect in CASES: - result = encode_basestring_ascii(input_string) + result = self.json.encoder.encode_basestring_ascii(input_string) self.assertEqual(result, expect, '{0!r} != {1!r} for {2}({3!r})'.format( result, expect, fname, input_string)) @@ -43,5 +33,9 @@ def test_ordered_dict(self): # See issue 6105 items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(OrderedDict(items)) + s = self.dumps(OrderedDict(items)) self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}') + + +class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass +class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): pass diff --git a/Lib/json/tests/test_fail.py b/Lib/json/tests/test_fail.py --- a/Lib/json/tests/test_fail.py +++ b/Lib/json/tests/test_fail.py @@ -1,6 +1,4 @@ -from unittest import TestCase - -import json +from json.tests import PyTest, CTest # Fri Dec 30 18:57:26 2005 JSONDOCS = [ @@ -61,15 +59,15 @@ 18: "spec doesn't specify any nesting limitations", } -class TestFail(TestCase): +class TestFail(object): def test_failures(self): for idx, doc in enumerate(JSONDOCS): idx = idx + 1 if idx in SKIPS: - json.loads(doc) + self.loads(doc) continue try: - json.loads(doc) + self.loads(doc) except ValueError: pass else: @@ -79,7 +77,11 @@ data = {'a' : 1, (1, 2) : 2} #This is for c encoder - self.assertRaises(TypeError, json.dumps, data) + self.assertRaises(TypeError, self.dumps, data) #This is for python encoder - self.assertRaises(TypeError, json.dumps, data, indent=True) + self.assertRaises(TypeError, self.dumps, data, indent=True) + + +class TestPyFail(TestFail, PyTest): pass +class TestCFail(TestFail, CTest): pass diff --git a/Lib/json/tests/test_float.py b/Lib/json/tests/test_float.py --- a/Lib/json/tests/test_float.py +++ b/Lib/json/tests/test_float.py @@ -1,19 +1,22 @@ import math -from unittest import TestCase +from json.tests import PyTest, CTest -import json -class TestFloat(TestCase): +class TestFloat(object): def test_floats(self): for num in [1617161771.7650001, math.pi, math.pi**100, math.pi**-100, 3.1]: - self.assertEqual(float(json.dumps(num)), num) - self.assertEqual(json.loads(json.dumps(num)), num) - self.assertEqual(json.loads(unicode(json.dumps(num))), num) + self.assertEqual(float(self.dumps(num)), num) + self.assertEqual(self.loads(self.dumps(num)), num) + self.assertEqual(self.loads(unicode(self.dumps(num))), num) def test_ints(self): for num in [1, 1L, 1<<32, 1<<64]: - self.assertEqual(json.dumps(num), str(num)) - self.assertEqual(int(json.dumps(num)), num) - self.assertEqual(json.loads(json.dumps(num)), num) - self.assertEqual(json.loads(unicode(json.dumps(num))), num) + self.assertEqual(self.dumps(num), str(num)) + self.assertEqual(int(self.dumps(num)), num) + self.assertEqual(self.loads(self.dumps(num)), num) + self.assertEqual(self.loads(unicode(self.dumps(num))), num) + + +class TestPyFloat(TestFloat, PyTest): pass +class TestCFloat(TestFloat, CTest): pass diff --git a/Lib/json/tests/test_indent.py b/Lib/json/tests/test_indent.py --- a/Lib/json/tests/test_indent.py +++ b/Lib/json/tests/test_indent.py @@ -1,10 +1,9 @@ -from unittest import TestCase - -import json import textwrap from StringIO import StringIO +from json.tests import PyTest, CTest -class TestIndent(TestCase): + +class TestIndent(object): def test_indent(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -31,11 +30,11 @@ ]""") - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) - h1 = json.loads(d1) - h2 = json.loads(d2) + h1 = self.loads(d1) + h2 = self.loads(d2) self.assertEqual(h1, h) self.assertEqual(h2, h) @@ -44,14 +43,18 @@ def test_indent0(self): h = {3: 1} def check(indent, expected): - d1 = json.dumps(h, indent=indent) + d1 = self.dumps(h, indent=indent) self.assertEqual(d1, expected) sio = StringIO() - json.dump(h, sio, indent=indent) + self.json.dump(h, sio, indent=indent) self.assertEqual(sio.getvalue(), expected) # indent=0 should emit newlines check(0, '{\n"3": 1\n}') # indent=None is more compact check(None, '{"3": 1}') + + +class TestPyIndent(TestIndent, PyTest): pass +class TestCIndent(TestIndent, CTest): pass diff --git a/Lib/json/tests/test_pass1.py b/Lib/json/tests/test_pass1.py --- a/Lib/json/tests/test_pass1.py +++ b/Lib/json/tests/test_pass1.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from json.tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass1.json JSON = r''' @@ -62,15 +61,19 @@ ,"rosebud"] ''' -class TestPass1(TestCase): +class TestPass1(object): def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) try: - json.dumps(res, allow_nan=False) + self.dumps(res, allow_nan=False) except ValueError: pass else: self.fail("23456789012E666 should be out of range") + + +class TestPyPass1(TestPass1, PyTest): pass +class TestCPass1(TestPass1, CTest): pass diff --git a/Lib/json/tests/test_pass2.py b/Lib/json/tests/test_pass2.py --- a/Lib/json/tests/test_pass2.py +++ b/Lib/json/tests/test_pass2.py @@ -1,14 +1,18 @@ -from unittest import TestCase -import json +from json.tests import PyTest, CTest + # from http://json.org/JSON_checker/test/pass2.json JSON = r''' [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] ''' -class TestPass2(TestCase): +class TestPass2(object): def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass2(TestPass2, PyTest): pass +class TestCPass2(TestPass2, CTest): pass diff --git a/Lib/json/tests/test_pass3.py b/Lib/json/tests/test_pass3.py --- a/Lib/json/tests/test_pass3.py +++ b/Lib/json/tests/test_pass3.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from json.tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass3.json JSON = r''' @@ -12,9 +11,14 @@ } ''' -class TestPass3(TestCase): + +class TestPass3(object): def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass3(TestPass3, PyTest): pass +class TestCPass3(TestPass3, CTest): pass diff --git a/Lib/json/tests/test_recursion.py b/Lib/json/tests/test_recursion.py --- a/Lib/json/tests/test_recursion.py +++ b/Lib/json/tests/test_recursion.py @@ -1,33 +1,16 @@ -from unittest import TestCase +from json.tests import PyTest, CTest -import json class JSONTestObject: pass -class RecursiveJSONEncoder(json.JSONEncoder): - recurse = False - def default(self, o): - if o is JSONTestObject: - if self.recurse: - return [JSONTestObject] - else: - return 'JSONTestObject' - return json.JSONEncoder.default(o) - -class EndlessJSONEncoder(json.JSONEncoder): - def default(self, o): - """If check_circular is False, this will keep adding another list.""" - return [o] - - -class TestRecursion(TestCase): +class TestRecursion(object): def test_listrecursion(self): x = [] x.append(x) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -36,7 +19,7 @@ y = [x] x.append(y) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -44,13 +27,13 @@ y = [] x = [y, y] # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_dictrecursion(self): x = {} x["test"] = x try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -58,9 +41,19 @@ x = {} y = {"a": x, "b": x} # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_defaultrecursion(self): + class RecursiveJSONEncoder(self.json.JSONEncoder): + recurse = False + def default(self, o): + if o is JSONTestObject: + if self.recurse: + return [JSONTestObject] + else: + return 'JSONTestObject' + return pyjson.JSONEncoder.default(o) + enc = RecursiveJSONEncoder() self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"') enc.recurse = True @@ -77,18 +70,18 @@ # accelerations are used. See #12017 # str with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '1' + '}' * 100000) + self.loads('{"a":' * 100000 + '1' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) + self.loads('{"a":' * 100000 + '[1]' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('[' * 100000 + '1' + ']' * 100000) + self.loads('[' * 100000 + '1' + ']' * 100000) # unicode with self.assertRaises(RuntimeError): - json.loads(u'{"a":' * 100000 + u'1' + u'}' * 100000) + self.loads(u'{"a":' * 100000 + u'1' + u'}' * 100000) with self.assertRaises(RuntimeError): - json.loads(u'{"a":' * 100000 + u'[1]' + u'}' * 100000) + self.loads(u'{"a":' * 100000 + u'[1]' + u'}' * 100000) with self.assertRaises(RuntimeError): - json.loads(u'[' * 100000 + u'1' + u']' * 100000) + self.loads(u'[' * 100000 + u'1' + u']' * 100000) def test_highly_nested_objects_encoding(self): # See #12051 @@ -96,11 +89,20 @@ for x in xrange(100000): l, d = [l], {'k':d} with self.assertRaises(RuntimeError): - json.dumps(l) + self.dumps(l) with self.assertRaises(RuntimeError): - json.dumps(d) + self.dumps(d) def test_endless_recursion(self): # See #12051 + class EndlessJSONEncoder(self.json.JSONEncoder): + def default(self, o): + """If check_circular is False, this will keep adding another list.""" + return [o] + with self.assertRaises(RuntimeError): EndlessJSONEncoder(check_circular=False).encode(5j) + + +class TestPyRecursion(TestRecursion, PyTest): pass +class TestCRecursion(TestRecursion, CTest): pass diff --git a/Lib/json/tests/test_scanstring.py b/Lib/json/tests/test_scanstring.py --- a/Lib/json/tests/test_scanstring.py +++ b/Lib/json/tests/test_scanstring.py @@ -1,23 +1,10 @@ import sys -from unittest import TestCase, skipUnless +from json.tests import PyTest, CTest -import json -import json.decoder -try: - import _json -except ImportError: - _json = None - -class TestScanString(TestCase): - def test_py_scanstring(self): - self._test_scanstring(json.decoder.py_scanstring) - - @skipUnless(_json, 'test requires the _json module') - def test_c_scanstring(self): - self._test_scanstring(json.decoder.c_scanstring) - - def _test_scanstring(self, scanstring): +class TestScanstring(object): + def test_scanstring(self): + scanstring = self.json.decoder.scanstring self.assertEqual( scanstring('"z\\ud834\\udd20x"', 1, None, True), (u'z\U0001d120x', 16)) @@ -108,10 +95,15 @@ (u'Bad value', 12)) def test_issue3623(self): - self.assertRaises(ValueError, json.decoder.scanstring, b"xxx", 1, + self.assertRaises(ValueError, self.json.decoder.scanstring, b"xxx", 1, "xxx") self.assertRaises(UnicodeDecodeError, - json.encoder.encode_basestring_ascii, b"xx\xff") + self.json.encoder.encode_basestring_ascii, b"xx\xff") def test_overflow(self): - self.assertRaises(OverflowError, json.decoder.scanstring, b"xxx", sys.maxsize+1) + with self.assertRaises(OverflowError): + self.json.decoder.scanstring(b"xxx", sys.maxsize+1) + + +class TestPyScanstring(TestScanstring, PyTest): pass +class TestCScanstring(TestScanstring, CTest): pass diff --git a/Lib/json/tests/test_separators.py b/Lib/json/tests/test_separators.py --- a/Lib/json/tests/test_separators.py +++ b/Lib/json/tests/test_separators.py @@ -1,10 +1,8 @@ import textwrap -from unittest import TestCase +from json.tests import PyTest, CTest -import json - -class TestSeparators(TestCase): +class TestSeparators(object): def test_separators(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -31,12 +29,16 @@ ]""") - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) - h1 = json.loads(d1) - h2 = json.loads(d2) + h1 = self.loads(d1) + h2 = self.loads(d2) self.assertEqual(h1, h) self.assertEqual(h2, h) self.assertEqual(d2, expect) + + +class TestPySeparators(TestSeparators, PyTest): pass +class TestCSeparators(TestSeparators, CTest): pass diff --git a/Lib/json/tests/test_speedups.py b/Lib/json/tests/test_speedups.py --- a/Lib/json/tests/test_speedups.py +++ b/Lib/json/tests/test_speedups.py @@ -1,29 +1,23 @@ -from unittest import TestCase, skipUnless +from json.tests import CTest -from json import decoder, encoder, scanner -try: - import _json -except ImportError: - _json = None - - at skipUnless(_json, 'test requires the _json module') -class TestSpeedups(TestCase): +class TestSpeedups(CTest): def test_scanstring(self): - self.assertEqual(decoder.scanstring.__module__, "_json") - self.assertIs(decoder.scanstring, decoder.c_scanstring) + self.assertEqual(self.json.decoder.scanstring.__module__, "_json") + self.assertIs(self.json.decoder.scanstring, self.json.decoder.c_scanstring) def test_encode_basestring_ascii(self): - self.assertEqual(encoder.encode_basestring_ascii.__module__, "_json") - self.assertIs(encoder.encode_basestring_ascii, - encoder.c_encode_basestring_ascii) + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + "_json") + self.assertIs(self.json.encoder.encode_basestring_ascii, + self.json.encoder.c_encode_basestring_ascii) -class TestDecode(TestCase): +class TestDecode(CTest): def test_make_scanner(self): - self.assertRaises(AttributeError, scanner.c_make_scanner, 1) + self.assertRaises(AttributeError, self.json.scanner.c_make_scanner, 1) def test_make_encoder(self): - self.assertRaises(TypeError, encoder.c_make_encoder, + self.assertRaises(TypeError, self.json.encoder.c_make_encoder, None, "\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75", None) diff --git a/Lib/json/tests/test_unicode.py b/Lib/json/tests/test_unicode.py --- a/Lib/json/tests/test_unicode.py +++ b/Lib/json/tests/test_unicode.py @@ -1,11 +1,10 @@ -from unittest import TestCase +from collections import OrderedDict +from json.tests import PyTest, CTest -import json -from collections import OrderedDict -class TestUnicode(TestCase): +class TestUnicode(object): def test_encoding1(self): - encoder = json.JSONEncoder(encoding='utf-8') + encoder = self.json.JSONEncoder(encoding='utf-8') u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' s = u.encode('utf-8') ju = encoder.encode(u) @@ -15,68 +14,72 @@ def test_encoding2(self): u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' s = u.encode('utf-8') - ju = json.dumps(u, encoding='utf-8') - js = json.dumps(s, encoding='utf-8') + ju = self.dumps(u, encoding='utf-8') + js = self.dumps(s, encoding='utf-8') self.assertEqual(ju, js) def test_encoding3(self): u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u) + j = self.dumps(u) self.assertEqual(j, '"\\u03b1\\u03a9"') def test_encoding4(self): u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u]) + j = self.dumps([u]) self.assertEqual(j, '["\\u03b1\\u03a9"]') def test_encoding5(self): u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u, ensure_ascii=False) + j = self.dumps(u, ensure_ascii=False) self.assertEqual(j, u'"{0}"'.format(u)) def test_encoding6(self): u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u], ensure_ascii=False) + j = self.dumps([u], ensure_ascii=False) self.assertEqual(j, u'["{0}"]'.format(u)) def test_big_unicode_encode(self): u = u'\U0001d120' - self.assertEqual(json.dumps(u), '"\\ud834\\udd20"') - self.assertEqual(json.dumps(u, ensure_ascii=False), u'"\U0001d120"') + self.assertEqual(self.dumps(u), '"\\ud834\\udd20"') + self.assertEqual(self.dumps(u, ensure_ascii=False), u'"\U0001d120"') def test_big_unicode_decode(self): u = u'z\U0001d120x' - self.assertEqual(json.loads('"' + u + '"'), u) - self.assertEqual(json.loads('"z\\ud834\\udd20x"'), u) + self.assertEqual(self.loads('"' + u + '"'), u) + self.assertEqual(self.loads('"z\\ud834\\udd20x"'), u) def test_unicode_decode(self): for i in range(0, 0xd7ff): u = unichr(i) s = '"\\u{0:04x}"'.format(i) - self.assertEqual(json.loads(s), u) + self.assertEqual(self.loads(s), u) def test_object_pairs_hook_with_unicode(self): s = u'{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [(u"xkd", 1), (u"kcw", 2), (u"art", 3), (u"hxm", 4), (u"qrt", 5), (u"pad", 6), (u"hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) - od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p) + od = self.loads(s, object_pairs_hook = OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, + self.assertEqual(self.loads(s, object_pairs_hook = OrderedDict, object_hook = lambda x: None), OrderedDict(p)) def test_default_encoding(self): - self.assertEqual(json.loads(u'{"a": "\xe9"}'.encode('utf-8')), + self.assertEqual(self.loads(u'{"a": "\xe9"}'.encode('utf-8')), {'a': u'\xe9'}) def test_unicode_preservation(self): - self.assertEqual(type(json.loads(u'""')), unicode) - self.assertEqual(type(json.loads(u'"a"')), unicode) - self.assertEqual(type(json.loads(u'["a"]')[0]), unicode) + self.assertEqual(type(self.loads(u'""')), unicode) + self.assertEqual(type(self.loads(u'"a"')), unicode) + self.assertEqual(type(self.loads(u'["a"]')[0]), unicode) # Issue 10038. - self.assertEqual(type(json.loads('"foo"')), unicode) + self.assertEqual(type(self.loads('"foo"')), unicode) + + +class TestPyUnicode(TestUnicode, PyTest): pass +class TestCUnicode(TestUnicode, CTest): pass diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -120,8 +120,8 @@ If deprecated is True, any module or package deprecation messages will be suppressed.""" - # NOTE: test_heapq and test_warnings include extra sanity checks to make - # sure that this utility function is working as expected + # NOTE: test_heapq, test_json, and test_warnings include extra sanity + # checks to make sure that this utility function is working as expected with _ignore_deprecated_imports(deprecated): # Keep track of modules saved for later restoration as well # as those which just need a blocking entry removed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -439,6 +439,8 @@ Tests ----- +- Issue #5723: Improve json tests to be executed with and without accelerations. + - Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. - Fix test_startfile to wait for child process to terminate before finishing. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 05:53:17 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 05:53:17 +0200 Subject: [Python-checkins] cpython (3.1): #5723: Improve json tests to be executed with and without accelerations. Message-ID: http://hg.python.org/cpython/rev/c2853a54b29e changeset: 70085:c2853a54b29e branch: 3.1 parent: 70081:9b7bfe86f04d user: Ezio Melotti date: Sat May 14 06:38:03 2011 +0300 summary: #5723: Improve json tests to be executed with and without accelerations. files: Lib/json/decoder.py | 4 +- Lib/json/tests/__init__.py | 46 +++++++- Lib/json/tests/test_decode.py | 33 +++-- Lib/json/tests/test_default.py | 13 +- Lib/json/tests/test_dump.py | 17 +- Lib/json/tests/test_encode_basestring_ascii.py | 30 ++--- Lib/json/tests/test_fail.py | 18 +- Lib/json/tests/test_float.py | 17 +- Lib/json/tests/test_indent.py | 23 ++- Lib/json/tests/test_pass1.py | 17 +- Lib/json/tests/test_pass2.py | 16 +- Lib/json/tests/test_pass3.py | 16 +- Lib/json/tests/test_recursion.py | 60 +++++---- Lib/json/tests/test_scanstring.py | 29 +--- Lib/json/tests/test_separators.py | 18 +- Lib/json/tests/test_speedups.py | 29 ++-- Lib/json/tests/test_unicode.py | 52 ++++---- Lib/test/support.py | 4 +- Misc/NEWS | 2 + 19 files changed, 249 insertions(+), 195 deletions(-) diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -5,7 +5,7 @@ import sys import struct -from json.scanner import make_scanner +from json import scanner try: from _json import scanstring as c_scanstring except ImportError: @@ -334,7 +334,7 @@ self.parse_object = JSONObject self.parse_array = JSONArray self.parse_string = scanstring - self.scan_once = make_scanner(self) + self.scan_once = scanner.make_scanner(self) def decode(self, s, _w=WHITESPACE.match): diff --git a/Lib/json/tests/__init__.py b/Lib/json/tests/__init__.py --- a/Lib/json/tests/__init__.py +++ b/Lib/json/tests/__init__.py @@ -1,7 +1,46 @@ import os import sys +import json +import doctest import unittest -import doctest + +from test import support + +# import json with and without accelerations +cjson = support.import_fresh_module('json', fresh=['_json']) +pyjson = support.import_fresh_module('json', blocked=['_json']) + +# create two base classes that will be used by the other tests +class PyTest(unittest.TestCase): + json = pyjson + loads = staticmethod(pyjson.loads) + dumps = staticmethod(pyjson.dumps) + + at unittest.skipUnless(cjson, 'requires _json') +class CTest(unittest.TestCase): + if cjson is not None: + json = cjson + loads = staticmethod(cjson.loads) + dumps = staticmethod(cjson.dumps) + +# test PyTest and CTest checking if the functions come from the right module +class TestPyTest(PyTest): + def test_pyjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, + 'json.scanner') + self.assertEqual(self.json.decoder.scanstring.__module__, + 'json.decoder') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + 'json.encoder') + +class TestCTest(CTest): + def test_cjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, '_json') + self.assertEqual(self.json.decoder.scanstring.__module__, '_json') + self.assertEqual(self.json.encoder.c_make_encoder.__module__, '_json') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + '_json') + here = os.path.dirname(__file__) @@ -17,12 +56,11 @@ return suite def additional_tests(): - import json - import json.encoder - import json.decoder suite = unittest.TestSuite() for mod in (json, json.encoder, json.decoder): suite.addTest(doctest.DocTestSuite(mod)) + suite.addTest(TestPyTest('test_pyjson')) + suite.addTest(TestCTest('test_cjson')) return suite def main(): diff --git a/Lib/json/tests/test_decode.py b/Lib/json/tests/test_decode.py --- a/Lib/json/tests/test_decode.py +++ b/Lib/json/tests/test_decode.py @@ -1,39 +1,38 @@ import decimal -from unittest import TestCase from io import StringIO +from collections import OrderedDict +from json.tests import PyTest, CTest -import json -from collections import OrderedDict -class TestDecode(TestCase): +class TestDecode: def test_decimal(self): - rval = json.loads('1.1', parse_float=decimal.Decimal) + rval = self.loads('1.1', parse_float=decimal.Decimal) self.assertTrue(isinstance(rval, decimal.Decimal)) self.assertEqual(rval, decimal.Decimal('1.1')) def test_float(self): - rval = json.loads('1', parse_int=float) + rval = self.loads('1', parse_int=float) self.assertTrue(isinstance(rval, float)) self.assertEqual(rval, 1.0) def test_empty_objects(self): - self.assertEqual(json.loads('{}'), {}) - self.assertEqual(json.loads('[]'), []) - self.assertEqual(json.loads('""'), "") + self.assertEqual(self.loads('{}'), {}) + self.assertEqual(self.loads('[]'), []) + self.assertEqual(self.loads('""'), "") def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) - self.assertEqual(json.load(StringIO(s), + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p) + self.assertEqual(self.json.load(StringIO(s), object_pairs_hook=lambda x: x), p) - od = json.loads(s, object_pairs_hook = OrderedDict) + od = self.loads(s, object_pairs_hook = OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, + self.assertEqual(self.loads(s, object_pairs_hook = OrderedDict, object_hook = lambda x: None), OrderedDict(p)) @@ -42,5 +41,9 @@ # Several optimizations were made that skip over calls to # the whitespace regex, so this test is designed to try and # exercise the uncommon cases. The array cases are already covered. - rval = json.loads('{ "key" : "value" , "k":"v" }') + rval = self.loads('{ "key" : "value" , "k":"v" }') self.assertEqual(rval, {"key":"value", "k":"v"}) + + +class TestPyDecode(TestDecode, PyTest): pass +class TestCDecode(TestDecode, CTest): pass diff --git a/Lib/json/tests/test_default.py b/Lib/json/tests/test_default.py --- a/Lib/json/tests/test_default.py +++ b/Lib/json/tests/test_default.py @@ -1,9 +1,12 @@ -from unittest import TestCase +from json.tests import PyTest, CTest -import json -class TestDefault(TestCase): +class TestDefault: def test_default(self): self.assertEqual( - json.dumps(type, default=repr), - json.dumps(repr(type))) + self.dumps(type, default=repr), + self.dumps(repr(type))) + + +class TestPyDefault(TestDefault, PyTest): pass +class TestCDefault(TestDefault, CTest): pass diff --git a/Lib/json/tests/test_dump.py b/Lib/json/tests/test_dump.py --- a/Lib/json/tests/test_dump.py +++ b/Lib/json/tests/test_dump.py @@ -1,21 +1,24 @@ -from unittest import TestCase from io import StringIO +from json.tests import PyTest, CTest -import json -class TestDump(TestCase): +class TestDump: def test_dump(self): sio = StringIO() - json.dump({}, sio) + self.json.dump({}, sio) self.assertEqual(sio.getvalue(), '{}') def test_dumps(self): - self.assertEqual(json.dumps({}), '{}') + self.assertEqual(self.dumps({}), '{}') def test_encode_truefalse(self): - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {True: False, False: True}, sort_keys=True), '{"false": true, "true": false}') - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {2: 3.0, 4.0: 5, False: 1, 6: True}, sort_keys=True), '{"false": 1, "2": 3.0, "4.0": 5, "6": true}') + + +class TestPyDump(TestDump, PyTest): pass +class TestCDump(TestDump, CTest): pass diff --git a/Lib/json/tests/test_encode_basestring_ascii.py b/Lib/json/tests/test_encode_basestring_ascii.py --- a/Lib/json/tests/test_encode_basestring_ascii.py +++ b/Lib/json/tests/test_encode_basestring_ascii.py @@ -1,8 +1,6 @@ -from unittest import TestCase +from collections import OrderedDict +from json.tests import PyTest, CTest -import json.encoder -from json import dumps -from collections import OrderedDict CASES = [ ('/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'), @@ -21,19 +19,11 @@ ('\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), ] -class TestEncodeBaseStringAscii(TestCase): - def test_py_encode_basestring_ascii(self): - self._test_encode_basestring_ascii(json.encoder.py_encode_basestring_ascii) - - def test_c_encode_basestring_ascii(self): - if not json.encoder.c_encode_basestring_ascii: - return - self._test_encode_basestring_ascii(json.encoder.c_encode_basestring_ascii) - - def _test_encode_basestring_ascii(self, encode_basestring_ascii): - fname = encode_basestring_ascii.__name__ +class TestEncodeBasestringAscii: + def test_encode_basestring_ascii(self): + fname = self.json.encoder.encode_basestring_ascii.__name__ for input_string, expect in CASES: - result = encode_basestring_ascii(input_string) + result = self.json.encoder.encode_basestring_ascii(input_string) self.assertEqual(result, expect, '{0!r} != {1!r} for {2}({3!r})'.format( result, expect, fname, input_string)) @@ -41,10 +31,14 @@ def test_ordered_dict(self): # See issue 6105 items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(OrderedDict(items)) + s = self.dumps(OrderedDict(items)) self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}') def test_sorted_dict(self): items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(dict(items), sort_keys=True) + s = self.dumps(dict(items), sort_keys=True) self.assertEqual(s, '{"five": 5, "four": 4, "one": 1, "three": 3, "two": 2}') + + +class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass +class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): pass diff --git a/Lib/json/tests/test_fail.py b/Lib/json/tests/test_fail.py --- a/Lib/json/tests/test_fail.py +++ b/Lib/json/tests/test_fail.py @@ -1,6 +1,4 @@ -from unittest import TestCase - -import json +from json.tests import PyTest, CTest # Fri Dec 30 18:57:26 2005 JSONDOCS = [ @@ -61,15 +59,15 @@ 18: "spec doesn't specify any nesting limitations", } -class TestFail(TestCase): +class TestFail: def test_failures(self): for idx, doc in enumerate(JSONDOCS): idx = idx + 1 if idx in SKIPS: - json.loads(doc) + self.loads(doc) continue try: - json.loads(doc) + self.loads(doc) except ValueError: pass else: @@ -79,7 +77,11 @@ data = {'a' : 1, (1, 2) : 2} #This is for c encoder - self.assertRaises(TypeError, json.dumps, data) + self.assertRaises(TypeError, self.dumps, data) #This is for python encoder - self.assertRaises(TypeError, json.dumps, data, indent=True) + self.assertRaises(TypeError, self.dumps, data, indent=True) + + +class TestPyFail(TestFail, PyTest): pass +class TestCFail(TestFail, CTest): pass diff --git a/Lib/json/tests/test_float.py b/Lib/json/tests/test_float.py --- a/Lib/json/tests/test_float.py +++ b/Lib/json/tests/test_float.py @@ -1,15 +1,18 @@ import math -from unittest import TestCase +from json.tests import PyTest, CTest -import json -class TestFloat(TestCase): +class TestFloat: def test_floats(self): for num in [1617161771.7650001, math.pi, math.pi**100, math.pi**-100, 3.1]: - self.assertEqual(float(json.dumps(num)), num) - self.assertEqual(json.loads(json.dumps(num)), num) + self.assertEqual(float(self.dumps(num)), num) + self.assertEqual(self.loads(self.dumps(num)), num) def test_ints(self): for num in [1, 1<<32, 1<<64]: - self.assertEqual(json.dumps(num), str(num)) - self.assertEqual(int(json.dumps(num)), num) + self.assertEqual(self.dumps(num), str(num)) + self.assertEqual(int(self.dumps(num)), num) + + +class TestPyFloat(TestFloat, PyTest): pass +class TestCFloat(TestFloat, CTest): pass diff --git a/Lib/json/tests/test_indent.py b/Lib/json/tests/test_indent.py --- a/Lib/json/tests/test_indent.py +++ b/Lib/json/tests/test_indent.py @@ -1,10 +1,9 @@ -from unittest import TestCase - -import json import textwrap from io import StringIO +from json.tests import PyTest, CTest -class TestIndent(TestCase): + +class TestIndent: def test_indent(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -31,11 +30,11 @@ ]""") - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) - h1 = json.loads(d1) - h2 = json.loads(d2) + h1 = self.loads(d1) + h2 = self.loads(d2) self.assertEqual(h1, h) self.assertEqual(h2, h) @@ -44,14 +43,18 @@ def test_indent0(self): h = {3: 1} def check(indent, expected): - d1 = json.dumps(h, indent=indent) + d1 = self.dumps(h, indent=indent) self.assertEqual(d1, expected) sio = StringIO() - json.dump(h, sio, indent=indent) + self.json.dump(h, sio, indent=indent) self.assertEqual(sio.getvalue(), expected) # indent=0 should emit newlines check(0, '{\n"3": 1\n}') # indent=None is more compact check(None, '{"3": 1}') + + +class TestPyIndent(TestIndent, PyTest): pass +class TestCIndent(TestIndent, CTest): pass diff --git a/Lib/json/tests/test_pass1.py b/Lib/json/tests/test_pass1.py --- a/Lib/json/tests/test_pass1.py +++ b/Lib/json/tests/test_pass1.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from json.tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass1.json JSON = r''' @@ -62,15 +61,19 @@ ,"rosebud"] ''' -class TestPass1(TestCase): +class TestPass1: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) try: - json.dumps(res, allow_nan=False) + self.dumps(res, allow_nan=False) except ValueError: pass else: self.fail("23456789012E666 should be out of range") + + +class TestPyPass1(TestPass1, PyTest): pass +class TestCPass1(TestPass1, CTest): pass diff --git a/Lib/json/tests/test_pass2.py b/Lib/json/tests/test_pass2.py --- a/Lib/json/tests/test_pass2.py +++ b/Lib/json/tests/test_pass2.py @@ -1,14 +1,18 @@ -from unittest import TestCase -import json +from json.tests import PyTest, CTest + # from http://json.org/JSON_checker/test/pass2.json JSON = r''' [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] ''' -class TestPass2(TestCase): +class TestPass2: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass2(TestPass2, PyTest): pass +class TestCPass2(TestPass2, CTest): pass diff --git a/Lib/json/tests/test_pass3.py b/Lib/json/tests/test_pass3.py --- a/Lib/json/tests/test_pass3.py +++ b/Lib/json/tests/test_pass3.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from json.tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass3.json JSON = r''' @@ -12,9 +11,14 @@ } ''' -class TestPass3(TestCase): + +class TestPass3: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass3(TestPass3, PyTest): pass +class TestCPass3(TestPass3, CTest): pass diff --git a/Lib/json/tests/test_recursion.py b/Lib/json/tests/test_recursion.py --- a/Lib/json/tests/test_recursion.py +++ b/Lib/json/tests/test_recursion.py @@ -1,33 +1,16 @@ -from unittest import TestCase +from json.tests import PyTest, CTest -import json class JSONTestObject: pass -class RecursiveJSONEncoder(json.JSONEncoder): - recurse = False - def default(self, o): - if o is JSONTestObject: - if self.recurse: - return [JSONTestObject] - else: - return 'JSONTestObject' - return json.JSONEncoder.default(o) - -class EndlessJSONEncoder(json.JSONEncoder): - def default(self, o): - """If check_circular is False, this will keep adding another list.""" - return [o] - - -class TestRecursion(TestCase): +class TestRecursion: def test_listrecursion(self): x = [] x.append(x) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -36,7 +19,7 @@ y = [x] x.append(y) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -44,13 +27,13 @@ y = [] x = [y, y] # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_dictrecursion(self): x = {} x["test"] = x try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -58,9 +41,19 @@ x = {} y = {"a": x, "b": x} # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_defaultrecursion(self): + class RecursiveJSONEncoder(self.json.JSONEncoder): + recurse = False + def default(self, o): + if o is JSONTestObject: + if self.recurse: + return [JSONTestObject] + else: + return 'JSONTestObject' + return pyjson.JSONEncoder.default(o) + enc = RecursiveJSONEncoder() self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"') enc.recurse = True @@ -76,11 +69,11 @@ # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '1' + '}' * 100000) + self.loads('{"a":' * 100000 + '1' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) + self.loads('{"a":' * 100000 + '[1]' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('[' * 100000 + '1' + ']' * 100000) + self.loads('[' * 100000 + '1' + ']' * 100000) def test_highly_nested_objects_encoding(self): # See #12051 @@ -88,11 +81,20 @@ for x in range(100000): l, d = [l], {'k':d} with self.assertRaises(RuntimeError): - json.dumps(l) + self.dumps(l) with self.assertRaises(RuntimeError): - json.dumps(d) + self.dumps(d) def test_endless_recursion(self): # See #12051 + class EndlessJSONEncoder(self.json.JSONEncoder): + def default(self, o): + """If check_circular is False, this will keep adding another list.""" + return [o] + with self.assertRaises(RuntimeError): EndlessJSONEncoder(check_circular=False).encode(5j) + + +class TestPyRecursion(TestRecursion, PyTest): pass +class TestCRecursion(TestRecursion, CTest): pass diff --git a/Lib/json/tests/test_scanstring.py b/Lib/json/tests/test_scanstring.py --- a/Lib/json/tests/test_scanstring.py +++ b/Lib/json/tests/test_scanstring.py @@ -1,24 +1,10 @@ import sys -from unittest import TestCase, skipUnless +from json.tests import PyTest, CTest -import json -import json.decoder -try: - import _json -except ImportError: - _json = None - -class TestScanString(TestCase): - def test_py_scanstring(self): - self._test_scanstring(json.decoder.py_scanstring) - - @skipUnless(_json, 'test requires the _json module') - def test_c_scanstring(self): - if json.decoder.c_scanstring is not None: - self._test_scanstring(json.decoder.c_scanstring) - - def _test_scanstring(self, scanstring): +class TestScanstring: + def test_scanstring(self): + scanstring = self.json.decoder.scanstring self.assertEqual( scanstring('"z\\ud834\\udd20x"', 1, True), ('z\U0001d120x', 16)) @@ -109,4 +95,9 @@ ('Bad value', 12)) def test_overflow(self): - self.assertRaises(OverflowError, json.decoder.scanstring, b"xxx", sys.maxsize+1) + with self.assertRaises(OverflowError): + self.json.decoder.scanstring(b"xxx", sys.maxsize+1) + + +class TestPyScanstring(TestScanstring, PyTest): pass +class TestCScanstring(TestScanstring, CTest): pass diff --git a/Lib/json/tests/test_separators.py b/Lib/json/tests/test_separators.py --- a/Lib/json/tests/test_separators.py +++ b/Lib/json/tests/test_separators.py @@ -1,10 +1,8 @@ import textwrap -from unittest import TestCase +from json.tests import PyTest, CTest -import json - -class TestSeparators(TestCase): +class TestSeparators: def test_separators(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -31,12 +29,16 @@ ]""") - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) - h1 = json.loads(d1) - h2 = json.loads(d2) + h1 = self.loads(d1) + h2 = self.loads(d2) self.assertEqual(h1, h) self.assertEqual(h2, h) self.assertEqual(d2, expect) + + +class TestPySeparators(TestSeparators, PyTest): pass +class TestCSeparators(TestSeparators, CTest): pass diff --git a/Lib/json/tests/test_speedups.py b/Lib/json/tests/test_speedups.py --- a/Lib/json/tests/test_speedups.py +++ b/Lib/json/tests/test_speedups.py @@ -1,29 +1,24 @@ -from unittest import TestCase, skipUnless +from json.tests import CTest -from json import decoder, encoder, scanner -try: - import _json -except ImportError: - _json = None - - at skipUnless(_json, 'test requires the _json module') -class TestSpeedups(TestCase): +class TestSpeedups(CTest): def test_scanstring(self): - self.assertEqual(decoder.scanstring.__module__, "_json") - self.assertIs(decoder.scanstring, decoder.c_scanstring) + self.assertEqual(self.json.decoder.scanstring.__module__, "_json") + self.assertIs(self.json.decoder.scanstring, self.json.decoder.c_scanstring) def test_encode_basestring_ascii(self): - self.assertEqual(encoder.encode_basestring_ascii.__module__, "_json") - self.assertIs(encoder.encode_basestring_ascii, - encoder.c_encode_basestring_ascii) + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + "_json") + self.assertIs(self.json.encoder.encode_basestring_ascii, + self.json.encoder.c_encode_basestring_ascii) -class TestDecode(TestCase): + +class TestDecode(CTest): def test_make_scanner(self): - self.assertRaises(AttributeError, scanner.c_make_scanner, 1) + self.assertRaises(AttributeError, self.json.scanner.c_make_scanner, 1) def test_make_encoder(self): - self.assertRaises(TypeError, encoder.c_make_encoder, + self.assertRaises(TypeError, self.json.encoder.c_make_encoder, (True, False), b"\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75", None) diff --git a/Lib/json/tests/test_unicode.py b/Lib/json/tests/test_unicode.py --- a/Lib/json/tests/test_unicode.py +++ b/Lib/json/tests/test_unicode.py @@ -1,73 +1,75 @@ -from unittest import TestCase +from collections import OrderedDict +from json.tests import PyTest, CTest -import json -from collections import OrderedDict -class TestUnicode(TestCase): +class TestUnicode: # test_encoding1 and test_encoding2 from 2.x are irrelevant (only str # is supported as input, not bytes). def test_encoding3(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u) + j = self.dumps(u) self.assertEqual(j, '"\\u03b1\\u03a9"') def test_encoding4(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u]) + j = self.dumps([u]) self.assertEqual(j, '["\\u03b1\\u03a9"]') def test_encoding5(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u, ensure_ascii=False) + j = self.dumps(u, ensure_ascii=False) self.assertEqual(j, '"{0}"'.format(u)) def test_encoding6(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u], ensure_ascii=False) + j = self.dumps([u], ensure_ascii=False) self.assertEqual(j, '["{0}"]'.format(u)) def test_big_unicode_encode(self): u = '\U0001d120' - self.assertEqual(json.dumps(u), '"\\ud834\\udd20"') - self.assertEqual(json.dumps(u, ensure_ascii=False), '"\U0001d120"') + self.assertEqual(self.dumps(u), '"\\ud834\\udd20"') + self.assertEqual(self.dumps(u, ensure_ascii=False), '"\U0001d120"') def test_big_unicode_decode(self): u = 'z\U0001d120x' - self.assertEqual(json.loads('"' + u + '"'), u) - self.assertEqual(json.loads('"z\\ud834\\udd20x"'), u) + self.assertEqual(self.loads('"' + u + '"'), u) + self.assertEqual(self.loads('"z\\ud834\\udd20x"'), u) def test_unicode_decode(self): for i in range(0, 0xd7ff): u = chr(i) s = '"\\u{0:04x}"'.format(i) - self.assertEqual(json.loads(s), u) + self.assertEqual(self.loads(s), u) def test_unicode_preservation(self): - self.assertEqual(type(json.loads('""')), str) - self.assertEqual(type(json.loads('"a"')), str) - self.assertEqual(type(json.loads('["a"]')[0]), str) + self.assertEqual(type(self.loads('""')), str) + self.assertEqual(type(self.loads('"a"')), str) + self.assertEqual(type(self.loads('["a"]')[0]), str) def test_bytes_encode(self): - self.assertRaises(TypeError, json.dumps, b"hi") - self.assertRaises(TypeError, json.dumps, [b"hi"]) + self.assertRaises(TypeError, self.dumps, b"hi") + self.assertRaises(TypeError, self.dumps, [b"hi"]) def test_bytes_decode(self): - self.assertRaises(TypeError, json.loads, b'"hi"') - self.assertRaises(TypeError, json.loads, b'["hi"]') + self.assertRaises(TypeError, self.loads, b'"hi"') + self.assertRaises(TypeError, self.loads, b'["hi"]') def test_object_pairs_hook_with_unicode(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) - od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p) + od = self.loads(s, object_pairs_hook = OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, - object_pairs_hook = OrderedDict, + self.assertEqual(self.loads(s, object_pairs_hook = OrderedDict, object_hook = lambda x: None), OrderedDict(p)) + + +class TestPyUnicode(TestUnicode, PyTest): pass +class TestCUnicode(TestUnicode, CTest): pass diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -116,8 +116,8 @@ If deprecated is True, any module or package deprecation messages will be suppressed.""" - # NOTE: test_heapq and test_warnings include extra sanity checks to make - # sure that this utility function is working as expected + # NOTE: test_heapq, test_json and test_warnings include extra sanity checks + # to make sure that this utility function is working as expected with _ignore_deprecated_imports(deprecated): # Keep track of modules saved for later restoration as well # as those which just need a blocking entry removed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -376,6 +376,8 @@ Tests ----- +- Issue #5723: Improve json tests to be executed with and without accelerations. + - Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. - Fix test_startfile to wait for child process to terminate before finishing. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 05:53:18 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 05:53:18 +0200 Subject: [Python-checkins] cpython (3.2): #5723: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/63fb2b811c9d changeset: 70086:63fb2b811c9d branch: 3.2 parent: 70082:688962b8a175 user: Ezio Melotti date: Sat May 14 06:47:51 2011 +0300 summary: #5723: merge with 3.1. files: Lib/json/decoder.py | 4 +- Lib/test/json_tests/__init__.py | 46 +++++++- Lib/test/json_tests/test_decode.py | 57 +++------ Lib/test/json_tests/test_default.py | 13 +- Lib/test/json_tests/test_dump.py | 17 +- Lib/test/json_tests/test_encode_basestring_ascii.py | 30 ++--- Lib/test/json_tests/test_fail.py | 18 +- Lib/test/json_tests/test_float.py | 17 +- Lib/test/json_tests/test_indent.py | 28 ++-- Lib/test/json_tests/test_pass1.py | 17 +- Lib/test/json_tests/test_pass2.py | 16 +- Lib/test/json_tests/test_pass3.py | 16 +- Lib/test/json_tests/test_recursion.py | 60 +++++---- Lib/test/json_tests/test_scanstring.py | 29 +--- Lib/test/json_tests/test_separators.py | 18 +- Lib/test/json_tests/test_speedups.py | 29 ++-- Lib/test/json_tests/test_unicode.py | 52 ++++---- Lib/test/support.py | 4 +- Misc/NEWS | 2 + 19 files changed, 254 insertions(+), 219 deletions(-) diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -5,7 +5,7 @@ import sys import struct -from json.scanner import make_scanner +from json import scanner try: from _json import scanstring as c_scanstring except ImportError: @@ -340,7 +340,7 @@ self.parse_array = JSONArray self.parse_string = scanstring self.memo = {} - self.scan_once = make_scanner(self) + self.scan_once = scanner.make_scanner(self) def decode(self, s, _w=WHITESPACE.match): diff --git a/Lib/test/json_tests/__init__.py b/Lib/test/json_tests/__init__.py --- a/Lib/test/json_tests/__init__.py +++ b/Lib/test/json_tests/__init__.py @@ -1,7 +1,46 @@ import os import sys +import json +import doctest import unittest -import doctest + +from test import support + +# import json with and without accelerations +cjson = support.import_fresh_module('json', fresh=['_json']) +pyjson = support.import_fresh_module('json', blocked=['_json']) + +# create two base classes that will be used by the other tests +class PyTest(unittest.TestCase): + json = pyjson + loads = staticmethod(pyjson.loads) + dumps = staticmethod(pyjson.dumps) + + at unittest.skipUnless(cjson, 'requires _json') +class CTest(unittest.TestCase): + if cjson is not None: + json = cjson + loads = staticmethod(cjson.loads) + dumps = staticmethod(cjson.dumps) + +# test PyTest and CTest checking if the functions come from the right module +class TestPyTest(PyTest): + def test_pyjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, + 'json.scanner') + self.assertEqual(self.json.decoder.scanstring.__module__, + 'json.decoder') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + 'json.encoder') + +class TestCTest(CTest): + def test_cjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, '_json') + self.assertEqual(self.json.decoder.scanstring.__module__, '_json') + self.assertEqual(self.json.encoder.c_make_encoder.__module__, '_json') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + '_json') + here = os.path.dirname(__file__) @@ -17,12 +56,11 @@ return suite def additional_tests(): - import json - import json.encoder - import json.decoder suite = unittest.TestSuite() for mod in (json, json.encoder, json.decoder): suite.addTest(doctest.DocTestSuite(mod)) + suite.addTest(TestPyTest('test_pyjson')) + suite.addTest(TestCTest('test_cjson')) return suite def main(): diff --git a/Lib/test/json_tests/test_decode.py b/Lib/test/json_tests/test_decode.py --- a/Lib/test/json_tests/test_decode.py +++ b/Lib/test/json_tests/test_decode.py @@ -1,55 +1,38 @@ import decimal -from unittest import TestCase from io import StringIO -from contextlib import contextmanager +from collections import OrderedDict +from test.json_tests import PyTest, CTest -import json -import json.decoder -import json.scanner -from collections import OrderedDict - - at contextmanager -def use_python_scanner(): - py_scanner = json.scanner.py_make_scanner - old_scanner = json.decoder.make_scanner - json.decoder.make_scanner = py_scanner - try: - yield - finally: - json.decoder.make_scanner = old_scanner - - -class TestDecode(TestCase): +class TestDecode: def test_decimal(self): - rval = json.loads('1.1', parse_float=decimal.Decimal) + rval = self.loads('1.1', parse_float=decimal.Decimal) self.assertTrue(isinstance(rval, decimal.Decimal)) self.assertEqual(rval, decimal.Decimal('1.1')) def test_float(self): - rval = json.loads('1', parse_int=float) + rval = self.loads('1', parse_int=float) self.assertTrue(isinstance(rval, float)) self.assertEqual(rval, 1.0) def test_empty_objects(self): - self.assertEqual(json.loads('{}'), {}) - self.assertEqual(json.loads('[]'), []) - self.assertEqual(json.loads('""'), "") + self.assertEqual(self.loads('{}'), {}) + self.assertEqual(self.loads('[]'), []) + self.assertEqual(self.loads('""'), "") def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) - self.assertEqual(json.load(StringIO(s), - object_pairs_hook=lambda x: x), p) - od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p) + self.assertEqual(self.json.load(StringIO(s), + object_pairs_hook=lambda x: x), p) + od = self.loads(s, object_pairs_hook = OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, - object_pairs_hook = OrderedDict, + self.assertEqual(self.loads(s, object_pairs_hook = OrderedDict, object_hook = lambda x: None), OrderedDict(p)) @@ -57,7 +40,7 @@ # Several optimizations were made that skip over calls to # the whitespace regex, so this test is designed to try and # exercise the uncommon cases. The array cases are already covered. - rval = json.loads('{ "key" : "value" , "k":"v" }') + rval = self.loads('{ "key" : "value" , "k":"v" }') self.assertEqual(rval, {"key":"value", "k":"v"}) def check_keys_reuse(self, source, loads): @@ -68,7 +51,9 @@ def test_keys_reuse(self): s = '[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]' - self.check_keys_reuse(s, json.loads) - # Disabled: the pure Python version of json simply doesn't work - with use_python_scanner(): - self.check_keys_reuse(s, json.decoder.JSONDecoder().decode) + self.check_keys_reuse(s, self.loads) + self.check_keys_reuse(s, self.json.decoder.JSONDecoder().decode) + + +class TestPyDecode(TestDecode, PyTest): pass +class TestCDecode(TestDecode, CTest): pass diff --git a/Lib/test/json_tests/test_default.py b/Lib/test/json_tests/test_default.py --- a/Lib/test/json_tests/test_default.py +++ b/Lib/test/json_tests/test_default.py @@ -1,9 +1,12 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json -class TestDefault(TestCase): +class TestDefault: def test_default(self): self.assertEqual( - json.dumps(type, default=repr), - json.dumps(repr(type))) + self.dumps(type, default=repr), + self.dumps(repr(type))) + + +class TestPyDefault(TestDefault, PyTest): pass +class TestCDefault(TestDefault, CTest): pass diff --git a/Lib/test/json_tests/test_dump.py b/Lib/test/json_tests/test_dump.py --- a/Lib/test/json_tests/test_dump.py +++ b/Lib/test/json_tests/test_dump.py @@ -1,21 +1,24 @@ -from unittest import TestCase from io import StringIO +from test.json_tests import PyTest, CTest -import json -class TestDump(TestCase): +class TestDump: def test_dump(self): sio = StringIO() - json.dump({}, sio) + self.json.dump({}, sio) self.assertEqual(sio.getvalue(), '{}') def test_dumps(self): - self.assertEqual(json.dumps({}), '{}') + self.assertEqual(self.dumps({}), '{}') def test_encode_truefalse(self): - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {True: False, False: True}, sort_keys=True), '{"false": true, "true": false}') - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {2: 3.0, 4.0: 5, False: 1, 6: True}, sort_keys=True), '{"false": 1, "2": 3.0, "4.0": 5, "6": true}') + + +class TestPyDump(TestDump, PyTest): pass +class TestCDump(TestDump, CTest): pass diff --git a/Lib/test/json_tests/test_encode_basestring_ascii.py b/Lib/test/json_tests/test_encode_basestring_ascii.py --- a/Lib/test/json_tests/test_encode_basestring_ascii.py +++ b/Lib/test/json_tests/test_encode_basestring_ascii.py @@ -1,8 +1,6 @@ -from unittest import TestCase +from collections import OrderedDict +from test.json_tests import PyTest, CTest -import json.encoder -from json import dumps -from collections import OrderedDict CASES = [ ('/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'), @@ -21,19 +19,11 @@ ('\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), ] -class TestEncodeBaseStringAscii(TestCase): - def test_py_encode_basestring_ascii(self): - self._test_encode_basestring_ascii(json.encoder.py_encode_basestring_ascii) - - def test_c_encode_basestring_ascii(self): - if not json.encoder.c_encode_basestring_ascii: - return - self._test_encode_basestring_ascii(json.encoder.c_encode_basestring_ascii) - - def _test_encode_basestring_ascii(self, encode_basestring_ascii): - fname = encode_basestring_ascii.__name__ +class TestEncodeBasestringAscii: + def test_encode_basestring_ascii(self): + fname = self.json.encoder.encode_basestring_ascii.__name__ for input_string, expect in CASES: - result = encode_basestring_ascii(input_string) + result = self.json.encoder.encode_basestring_ascii(input_string) self.assertEqual(result, expect, '{0!r} != {1!r} for {2}({3!r})'.format( result, expect, fname, input_string)) @@ -41,10 +31,14 @@ def test_ordered_dict(self): # See issue 6105 items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(OrderedDict(items)) + s = self.dumps(OrderedDict(items)) self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}') def test_sorted_dict(self): items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(dict(items), sort_keys=True) + s = self.dumps(dict(items), sort_keys=True) self.assertEqual(s, '{"five": 5, "four": 4, "one": 1, "three": 3, "two": 2}') + + +class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass +class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): pass diff --git a/Lib/test/json_tests/test_fail.py b/Lib/test/json_tests/test_fail.py --- a/Lib/test/json_tests/test_fail.py +++ b/Lib/test/json_tests/test_fail.py @@ -1,6 +1,4 @@ -from unittest import TestCase - -import json +from test.json_tests import PyTest, CTest # Fri Dec 30 18:57:26 2005 JSONDOCS = [ @@ -61,15 +59,15 @@ 18: "spec doesn't specify any nesting limitations", } -class TestFail(TestCase): +class TestFail: def test_failures(self): for idx, doc in enumerate(JSONDOCS): idx = idx + 1 if idx in SKIPS: - json.loads(doc) + self.loads(doc) continue try: - json.loads(doc) + self.loads(doc) except ValueError: pass else: @@ -79,7 +77,11 @@ data = {'a' : 1, (1, 2) : 2} #This is for c encoder - self.assertRaises(TypeError, json.dumps, data) + self.assertRaises(TypeError, self.dumps, data) #This is for python encoder - self.assertRaises(TypeError, json.dumps, data, indent=True) + self.assertRaises(TypeError, self.dumps, data, indent=True) + + +class TestPyFail(TestFail, PyTest): pass +class TestCFail(TestFail, CTest): pass diff --git a/Lib/test/json_tests/test_float.py b/Lib/test/json_tests/test_float.py --- a/Lib/test/json_tests/test_float.py +++ b/Lib/test/json_tests/test_float.py @@ -1,15 +1,18 @@ import math -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json -class TestFloat(TestCase): +class TestFloat: def test_floats(self): for num in [1617161771.7650001, math.pi, math.pi**100, math.pi**-100, 3.1]: - self.assertEqual(float(json.dumps(num)), num) - self.assertEqual(json.loads(json.dumps(num)), num) + self.assertEqual(float(self.dumps(num)), num) + self.assertEqual(self.loads(self.dumps(num)), num) def test_ints(self): for num in [1, 1<<32, 1<<64]: - self.assertEqual(json.dumps(num), str(num)) - self.assertEqual(int(json.dumps(num)), num) + self.assertEqual(self.dumps(num), str(num)) + self.assertEqual(int(self.dumps(num)), num) + + +class TestPyFloat(TestFloat, PyTest): pass +class TestCFloat(TestFloat, CTest): pass diff --git a/Lib/test/json_tests/test_indent.py b/Lib/test/json_tests/test_indent.py --- a/Lib/test/json_tests/test_indent.py +++ b/Lib/test/json_tests/test_indent.py @@ -1,10 +1,9 @@ -from unittest import TestCase - -import json import textwrap from io import StringIO +from test.json_tests import PyTest, CTest -class TestIndent(TestCase): + +class TestIndent: def test_indent(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -30,14 +29,13 @@ \t} ]""") + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) + d3 = self.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) - d3 = json.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) - - h1 = json.loads(d1) - h2 = json.loads(d2) - h3 = json.loads(d3) + h1 = self.loads(d1) + h2 = self.loads(d2) + h3 = self.loads(d3) self.assertEqual(h1, h) self.assertEqual(h2, h) @@ -48,14 +46,18 @@ def test_indent0(self): h = {3: 1} def check(indent, expected): - d1 = json.dumps(h, indent=indent) + d1 = self.dumps(h, indent=indent) self.assertEqual(d1, expected) sio = StringIO() - json.dump(h, sio, indent=indent) + self.json.dump(h, sio, indent=indent) self.assertEqual(sio.getvalue(), expected) # indent=0 should emit newlines check(0, '{\n"3": 1\n}') # indent=None is more compact check(None, '{"3": 1}') + + +class TestPyIndent(TestIndent, PyTest): pass +class TestCIndent(TestIndent, CTest): pass diff --git a/Lib/test/json_tests/test_pass1.py b/Lib/test/json_tests/test_pass1.py --- a/Lib/test/json_tests/test_pass1.py +++ b/Lib/test/json_tests/test_pass1.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass1.json JSON = r''' @@ -62,15 +61,19 @@ ,"rosebud"] ''' -class TestPass1(TestCase): +class TestPass1: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) try: - json.dumps(res, allow_nan=False) + self.dumps(res, allow_nan=False) except ValueError: pass else: self.fail("23456789012E666 should be out of range") + + +class TestPyPass1(TestPass1, PyTest): pass +class TestCPass1(TestPass1, CTest): pass diff --git a/Lib/test/json_tests/test_pass2.py b/Lib/test/json_tests/test_pass2.py --- a/Lib/test/json_tests/test_pass2.py +++ b/Lib/test/json_tests/test_pass2.py @@ -1,14 +1,18 @@ -from unittest import TestCase -import json +from test.json_tests import PyTest, CTest + # from http://json.org/JSON_checker/test/pass2.json JSON = r''' [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] ''' -class TestPass2(TestCase): +class TestPass2: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass2(TestPass2, PyTest): pass +class TestCPass2(TestPass2, CTest): pass diff --git a/Lib/test/json_tests/test_pass3.py b/Lib/test/json_tests/test_pass3.py --- a/Lib/test/json_tests/test_pass3.py +++ b/Lib/test/json_tests/test_pass3.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass3.json JSON = r''' @@ -12,9 +11,14 @@ } ''' -class TestPass3(TestCase): + +class TestPass3: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass3(TestPass3, PyTest): pass +class TestCPass3(TestPass3, CTest): pass diff --git a/Lib/test/json_tests/test_recursion.py b/Lib/test/json_tests/test_recursion.py --- a/Lib/test/json_tests/test_recursion.py +++ b/Lib/test/json_tests/test_recursion.py @@ -1,33 +1,16 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json class JSONTestObject: pass -class RecursiveJSONEncoder(json.JSONEncoder): - recurse = False - def default(self, o): - if o is JSONTestObject: - if self.recurse: - return [JSONTestObject] - else: - return 'JSONTestObject' - return json.JSONEncoder.default(o) - -class EndlessJSONEncoder(json.JSONEncoder): - def default(self, o): - """If check_circular is False, this will keep adding another list.""" - return [o] - - -class TestRecursion(TestCase): +class TestRecursion: def test_listrecursion(self): x = [] x.append(x) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -36,7 +19,7 @@ y = [x] x.append(y) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -44,13 +27,13 @@ y = [] x = [y, y] # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_dictrecursion(self): x = {} x["test"] = x try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -58,9 +41,19 @@ x = {} y = {"a": x, "b": x} # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_defaultrecursion(self): + class RecursiveJSONEncoder(self.json.JSONEncoder): + recurse = False + def default(self, o): + if o is JSONTestObject: + if self.recurse: + return [JSONTestObject] + else: + return 'JSONTestObject' + return pyjson.JSONEncoder.default(o) + enc = RecursiveJSONEncoder() self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"') enc.recurse = True @@ -76,11 +69,11 @@ # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '1' + '}' * 100000) + self.loads('{"a":' * 100000 + '1' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) + self.loads('{"a":' * 100000 + '[1]' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('[' * 100000 + '1' + ']' * 100000) + self.loads('[' * 100000 + '1' + ']' * 100000) def test_highly_nested_objects_encoding(self): # See #12051 @@ -88,11 +81,20 @@ for x in range(100000): l, d = [l], {'k':d} with self.assertRaises(RuntimeError): - json.dumps(l) + self.dumps(l) with self.assertRaises(RuntimeError): - json.dumps(d) + self.dumps(d) def test_endless_recursion(self): # See #12051 + class EndlessJSONEncoder(self.json.JSONEncoder): + def default(self, o): + """If check_circular is False, this will keep adding another list.""" + return [o] + with self.assertRaises(RuntimeError): EndlessJSONEncoder(check_circular=False).encode(5j) + + +class TestPyRecursion(TestRecursion, PyTest): pass +class TestCRecursion(TestRecursion, CTest): pass diff --git a/Lib/test/json_tests/test_scanstring.py b/Lib/test/json_tests/test_scanstring.py --- a/Lib/test/json_tests/test_scanstring.py +++ b/Lib/test/json_tests/test_scanstring.py @@ -1,24 +1,10 @@ import sys -from unittest import TestCase, skipUnless +from test.json_tests import PyTest, CTest -import json -import json.decoder -try: - import _json -except ImportError: - _json = None - -class TestScanString(TestCase): - def test_py_scanstring(self): - self._test_scanstring(json.decoder.py_scanstring) - - @skipUnless(_json, 'test requires the _json module') - def test_c_scanstring(self): - if json.decoder.c_scanstring is not None: - self._test_scanstring(json.decoder.c_scanstring) - - def _test_scanstring(self, scanstring): +class TestScanstring: + def test_scanstring(self): + scanstring = self.json.decoder.scanstring self.assertEqual( scanstring('"z\\ud834\\udd20x"', 1, True), ('z\U0001d120x', 16)) @@ -109,4 +95,9 @@ ('Bad value', 12)) def test_overflow(self): - self.assertRaises(OverflowError, json.decoder.scanstring, b"xxx", sys.maxsize+1) + with self.assertRaises(OverflowError): + self.json.decoder.scanstring(b"xxx", sys.maxsize+1) + + +class TestPyScanstring(TestScanstring, PyTest): pass +class TestCScanstring(TestScanstring, CTest): pass diff --git a/Lib/test/json_tests/test_separators.py b/Lib/test/json_tests/test_separators.py --- a/Lib/test/json_tests/test_separators.py +++ b/Lib/test/json_tests/test_separators.py @@ -1,10 +1,8 @@ import textwrap -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json - -class TestSeparators(TestCase): +class TestSeparators: def test_separators(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -31,12 +29,16 @@ ]""") - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) - h1 = json.loads(d1) - h2 = json.loads(d2) + h1 = self.loads(d1) + h2 = self.loads(d2) self.assertEqual(h1, h) self.assertEqual(h2, h) self.assertEqual(d2, expect) + + +class TestPySeparators(TestSeparators, PyTest): pass +class TestCSeparators(TestSeparators, CTest): pass diff --git a/Lib/test/json_tests/test_speedups.py b/Lib/test/json_tests/test_speedups.py --- a/Lib/test/json_tests/test_speedups.py +++ b/Lib/test/json_tests/test_speedups.py @@ -1,29 +1,24 @@ -from unittest import TestCase, skipUnless +from test.json_tests import CTest -from json import decoder, encoder, scanner -try: - import _json -except ImportError: - _json = None - - at skipUnless(_json, 'test requires the _json module') -class TestSpeedups(TestCase): +class TestSpeedups(CTest): def test_scanstring(self): - self.assertEqual(decoder.scanstring.__module__, "_json") - self.assertIs(decoder.scanstring, decoder.c_scanstring) + self.assertEqual(self.json.decoder.scanstring.__module__, "_json") + self.assertIs(self.json.decoder.scanstring, self.json.decoder.c_scanstring) def test_encode_basestring_ascii(self): - self.assertEqual(encoder.encode_basestring_ascii.__module__, "_json") - self.assertIs(encoder.encode_basestring_ascii, - encoder.c_encode_basestring_ascii) + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + "_json") + self.assertIs(self.json.encoder.encode_basestring_ascii, + self.json.encoder.c_encode_basestring_ascii) -class TestDecode(TestCase): + +class TestDecode(CTest): def test_make_scanner(self): - self.assertRaises(AttributeError, scanner.c_make_scanner, 1) + self.assertRaises(AttributeError, self.json.scanner.c_make_scanner, 1) def test_make_encoder(self): - self.assertRaises(TypeError, encoder.c_make_encoder, + self.assertRaises(TypeError, self.json.encoder.c_make_encoder, (True, False), b"\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75", None) diff --git a/Lib/test/json_tests/test_unicode.py b/Lib/test/json_tests/test_unicode.py --- a/Lib/test/json_tests/test_unicode.py +++ b/Lib/test/json_tests/test_unicode.py @@ -1,73 +1,75 @@ -from unittest import TestCase +from collections import OrderedDict +from test.json_tests import PyTest, CTest -import json -from collections import OrderedDict -class TestUnicode(TestCase): +class TestUnicode: # test_encoding1 and test_encoding2 from 2.x are irrelevant (only str # is supported as input, not bytes). def test_encoding3(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u) + j = self.dumps(u) self.assertEqual(j, '"\\u03b1\\u03a9"') def test_encoding4(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u]) + j = self.dumps([u]) self.assertEqual(j, '["\\u03b1\\u03a9"]') def test_encoding5(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u, ensure_ascii=False) + j = self.dumps(u, ensure_ascii=False) self.assertEqual(j, '"{0}"'.format(u)) def test_encoding6(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u], ensure_ascii=False) + j = self.dumps([u], ensure_ascii=False) self.assertEqual(j, '["{0}"]'.format(u)) def test_big_unicode_encode(self): u = '\U0001d120' - self.assertEqual(json.dumps(u), '"\\ud834\\udd20"') - self.assertEqual(json.dumps(u, ensure_ascii=False), '"\U0001d120"') + self.assertEqual(self.dumps(u), '"\\ud834\\udd20"') + self.assertEqual(self.dumps(u, ensure_ascii=False), '"\U0001d120"') def test_big_unicode_decode(self): u = 'z\U0001d120x' - self.assertEqual(json.loads('"' + u + '"'), u) - self.assertEqual(json.loads('"z\\ud834\\udd20x"'), u) + self.assertEqual(self.loads('"' + u + '"'), u) + self.assertEqual(self.loads('"z\\ud834\\udd20x"'), u) def test_unicode_decode(self): for i in range(0, 0xd7ff): u = chr(i) s = '"\\u{0:04x}"'.format(i) - self.assertEqual(json.loads(s), u) + self.assertEqual(self.loads(s), u) def test_unicode_preservation(self): - self.assertEqual(type(json.loads('""')), str) - self.assertEqual(type(json.loads('"a"')), str) - self.assertEqual(type(json.loads('["a"]')[0]), str) + self.assertEqual(type(self.loads('""')), str) + self.assertEqual(type(self.loads('"a"')), str) + self.assertEqual(type(self.loads('["a"]')[0]), str) def test_bytes_encode(self): - self.assertRaises(TypeError, json.dumps, b"hi") - self.assertRaises(TypeError, json.dumps, [b"hi"]) + self.assertRaises(TypeError, self.dumps, b"hi") + self.assertRaises(TypeError, self.dumps, [b"hi"]) def test_bytes_decode(self): - self.assertRaises(TypeError, json.loads, b'"hi"') - self.assertRaises(TypeError, json.loads, b'["hi"]') + self.assertRaises(TypeError, self.loads, b'"hi"') + self.assertRaises(TypeError, self.loads, b'["hi"]') def test_object_pairs_hook_with_unicode(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) - od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p) + od = self.loads(s, object_pairs_hook = OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, - object_pairs_hook = OrderedDict, + self.assertEqual(self.loads(s, object_pairs_hook = OrderedDict, object_hook = lambda x: None), OrderedDict(p)) + + +class TestPyUnicode(TestUnicode, PyTest): pass +class TestCUnicode(TestUnicode, CTest): pass diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -128,8 +128,8 @@ If deprecated is True, any module or package deprecation messages will be suppressed.""" - # NOTE: test_heapq and test_warnings include extra sanity checks to make - # sure that this utility function is working as expected + # NOTE: test_heapq, test_json and test_warnings include extra sanity checks + # to make sure that this utility function is working as expected with _ignore_deprecated_imports(deprecated): # Keep track of modules saved for later restoration as well # as those which just need a blocking entry removed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -379,6 +379,8 @@ Tests ----- +- Issue #5723: Improve json tests to be executed with and without accelerations. + - Issue #11873: Change regex in test_compileall to fix occasional failures when when the randomly generated temporary path happened to match the regex. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 05:53:19 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 05:53:19 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #5723: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/afdc06f2552f changeset: 70087:afdc06f2552f parent: 70083:d6d222a96172 parent: 70086:63fb2b811c9d user: Ezio Melotti date: Sat May 14 06:52:55 2011 +0300 summary: #5723: merge with 3.2. files: Lib/json/decoder.py | 4 +- Lib/test/json_tests/__init__.py | 46 +++++++- Lib/test/json_tests/test_decode.py | 57 +++------ Lib/test/json_tests/test_default.py | 13 +- Lib/test/json_tests/test_dump.py | 17 +- Lib/test/json_tests/test_encode_basestring_ascii.py | 30 ++--- Lib/test/json_tests/test_fail.py | 18 +- Lib/test/json_tests/test_float.py | 17 +- Lib/test/json_tests/test_indent.py | 28 ++-- Lib/test/json_tests/test_pass1.py | 17 +- Lib/test/json_tests/test_pass2.py | 16 +- Lib/test/json_tests/test_pass3.py | 16 +- Lib/test/json_tests/test_recursion.py | 60 +++++---- Lib/test/json_tests/test_scanstring.py | 29 +--- Lib/test/json_tests/test_separators.py | 18 +- Lib/test/json_tests/test_speedups.py | 29 ++-- Lib/test/json_tests/test_unicode.py | 52 ++++---- Lib/test/support.py | 4 +- Misc/NEWS | 2 + 19 files changed, 254 insertions(+), 219 deletions(-) diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -5,7 +5,7 @@ import sys import struct -from json.scanner import make_scanner +from json import scanner try: from _json import scanstring as c_scanstring except ImportError: @@ -340,7 +340,7 @@ self.parse_array = JSONArray self.parse_string = scanstring self.memo = {} - self.scan_once = make_scanner(self) + self.scan_once = scanner.make_scanner(self) def decode(self, s, _w=WHITESPACE.match): diff --git a/Lib/test/json_tests/__init__.py b/Lib/test/json_tests/__init__.py --- a/Lib/test/json_tests/__init__.py +++ b/Lib/test/json_tests/__init__.py @@ -1,7 +1,46 @@ import os import sys +import json +import doctest import unittest -import doctest + +from test import support + +# import json with and without accelerations +cjson = support.import_fresh_module('json', fresh=['_json']) +pyjson = support.import_fresh_module('json', blocked=['_json']) + +# create two base classes that will be used by the other tests +class PyTest(unittest.TestCase): + json = pyjson + loads = staticmethod(pyjson.loads) + dumps = staticmethod(pyjson.dumps) + + at unittest.skipUnless(cjson, 'requires _json') +class CTest(unittest.TestCase): + if cjson is not None: + json = cjson + loads = staticmethod(cjson.loads) + dumps = staticmethod(cjson.dumps) + +# test PyTest and CTest checking if the functions come from the right module +class TestPyTest(PyTest): + def test_pyjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, + 'json.scanner') + self.assertEqual(self.json.decoder.scanstring.__module__, + 'json.decoder') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + 'json.encoder') + +class TestCTest(CTest): + def test_cjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, '_json') + self.assertEqual(self.json.decoder.scanstring.__module__, '_json') + self.assertEqual(self.json.encoder.c_make_encoder.__module__, '_json') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + '_json') + here = os.path.dirname(__file__) @@ -17,12 +56,11 @@ return suite def additional_tests(): - import json - import json.encoder - import json.decoder suite = unittest.TestSuite() for mod in (json, json.encoder, json.decoder): suite.addTest(doctest.DocTestSuite(mod)) + suite.addTest(TestPyTest('test_pyjson')) + suite.addTest(TestCTest('test_cjson')) return suite def main(): diff --git a/Lib/test/json_tests/test_decode.py b/Lib/test/json_tests/test_decode.py --- a/Lib/test/json_tests/test_decode.py +++ b/Lib/test/json_tests/test_decode.py @@ -1,55 +1,38 @@ import decimal -from unittest import TestCase from io import StringIO -from contextlib import contextmanager +from collections import OrderedDict +from test.json_tests import PyTest, CTest -import json -import json.decoder -import json.scanner -from collections import OrderedDict - - at contextmanager -def use_python_scanner(): - py_scanner = json.scanner.py_make_scanner - old_scanner = json.decoder.make_scanner - json.decoder.make_scanner = py_scanner - try: - yield - finally: - json.decoder.make_scanner = old_scanner - - -class TestDecode(TestCase): +class TestDecode: def test_decimal(self): - rval = json.loads('1.1', parse_float=decimal.Decimal) + rval = self.loads('1.1', parse_float=decimal.Decimal) self.assertTrue(isinstance(rval, decimal.Decimal)) self.assertEqual(rval, decimal.Decimal('1.1')) def test_float(self): - rval = json.loads('1', parse_int=float) + rval = self.loads('1', parse_int=float) self.assertTrue(isinstance(rval, float)) self.assertEqual(rval, 1.0) def test_empty_objects(self): - self.assertEqual(json.loads('{}'), {}) - self.assertEqual(json.loads('[]'), []) - self.assertEqual(json.loads('""'), "") + self.assertEqual(self.loads('{}'), {}) + self.assertEqual(self.loads('[]'), []) + self.assertEqual(self.loads('""'), "") def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) - self.assertEqual(json.load(StringIO(s), - object_pairs_hook=lambda x: x), p) - od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p) + self.assertEqual(self.json.load(StringIO(s), + object_pairs_hook=lambda x: x), p) + od = self.loads(s, object_pairs_hook = OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, - object_pairs_hook = OrderedDict, + self.assertEqual(self.loads(s, object_pairs_hook = OrderedDict, object_hook = lambda x: None), OrderedDict(p)) @@ -57,7 +40,7 @@ # Several optimizations were made that skip over calls to # the whitespace regex, so this test is designed to try and # exercise the uncommon cases. The array cases are already covered. - rval = json.loads('{ "key" : "value" , "k":"v" }') + rval = self.loads('{ "key" : "value" , "k":"v" }') self.assertEqual(rval, {"key":"value", "k":"v"}) def check_keys_reuse(self, source, loads): @@ -68,7 +51,9 @@ def test_keys_reuse(self): s = '[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]' - self.check_keys_reuse(s, json.loads) - # Disabled: the pure Python version of json simply doesn't work - with use_python_scanner(): - self.check_keys_reuse(s, json.decoder.JSONDecoder().decode) + self.check_keys_reuse(s, self.loads) + self.check_keys_reuse(s, self.json.decoder.JSONDecoder().decode) + + +class TestPyDecode(TestDecode, PyTest): pass +class TestCDecode(TestDecode, CTest): pass diff --git a/Lib/test/json_tests/test_default.py b/Lib/test/json_tests/test_default.py --- a/Lib/test/json_tests/test_default.py +++ b/Lib/test/json_tests/test_default.py @@ -1,9 +1,12 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json -class TestDefault(TestCase): +class TestDefault: def test_default(self): self.assertEqual( - json.dumps(type, default=repr), - json.dumps(repr(type))) + self.dumps(type, default=repr), + self.dumps(repr(type))) + + +class TestPyDefault(TestDefault, PyTest): pass +class TestCDefault(TestDefault, CTest): pass diff --git a/Lib/test/json_tests/test_dump.py b/Lib/test/json_tests/test_dump.py --- a/Lib/test/json_tests/test_dump.py +++ b/Lib/test/json_tests/test_dump.py @@ -1,21 +1,24 @@ -from unittest import TestCase from io import StringIO +from test.json_tests import PyTest, CTest -import json -class TestDump(TestCase): +class TestDump: def test_dump(self): sio = StringIO() - json.dump({}, sio) + self.json.dump({}, sio) self.assertEqual(sio.getvalue(), '{}') def test_dumps(self): - self.assertEqual(json.dumps({}), '{}') + self.assertEqual(self.dumps({}), '{}') def test_encode_truefalse(self): - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {True: False, False: True}, sort_keys=True), '{"false": true, "true": false}') - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {2: 3.0, 4.0: 5, False: 1, 6: True}, sort_keys=True), '{"false": 1, "2": 3.0, "4.0": 5, "6": true}') + + +class TestPyDump(TestDump, PyTest): pass +class TestCDump(TestDump, CTest): pass diff --git a/Lib/test/json_tests/test_encode_basestring_ascii.py b/Lib/test/json_tests/test_encode_basestring_ascii.py --- a/Lib/test/json_tests/test_encode_basestring_ascii.py +++ b/Lib/test/json_tests/test_encode_basestring_ascii.py @@ -1,8 +1,6 @@ -from unittest import TestCase +from collections import OrderedDict +from test.json_tests import PyTest, CTest -import json.encoder -from json import dumps -from collections import OrderedDict CASES = [ ('/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'), @@ -21,19 +19,11 @@ ('\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), ] -class TestEncodeBaseStringAscii(TestCase): - def test_py_encode_basestring_ascii(self): - self._test_encode_basestring_ascii(json.encoder.py_encode_basestring_ascii) - - def test_c_encode_basestring_ascii(self): - if not json.encoder.c_encode_basestring_ascii: - return - self._test_encode_basestring_ascii(json.encoder.c_encode_basestring_ascii) - - def _test_encode_basestring_ascii(self, encode_basestring_ascii): - fname = encode_basestring_ascii.__name__ +class TestEncodeBasestringAscii: + def test_encode_basestring_ascii(self): + fname = self.json.encoder.encode_basestring_ascii.__name__ for input_string, expect in CASES: - result = encode_basestring_ascii(input_string) + result = self.json.encoder.encode_basestring_ascii(input_string) self.assertEqual(result, expect, '{0!r} != {1!r} for {2}({3!r})'.format( result, expect, fname, input_string)) @@ -41,10 +31,14 @@ def test_ordered_dict(self): # See issue 6105 items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(OrderedDict(items)) + s = self.dumps(OrderedDict(items)) self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}') def test_sorted_dict(self): items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(dict(items), sort_keys=True) + s = self.dumps(dict(items), sort_keys=True) self.assertEqual(s, '{"five": 5, "four": 4, "one": 1, "three": 3, "two": 2}') + + +class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass +class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): pass diff --git a/Lib/test/json_tests/test_fail.py b/Lib/test/json_tests/test_fail.py --- a/Lib/test/json_tests/test_fail.py +++ b/Lib/test/json_tests/test_fail.py @@ -1,6 +1,4 @@ -from unittest import TestCase - -import json +from test.json_tests import PyTest, CTest # Fri Dec 30 18:57:26 2005 JSONDOCS = [ @@ -61,15 +59,15 @@ 18: "spec doesn't specify any nesting limitations", } -class TestFail(TestCase): +class TestFail: def test_failures(self): for idx, doc in enumerate(JSONDOCS): idx = idx + 1 if idx in SKIPS: - json.loads(doc) + self.loads(doc) continue try: - json.loads(doc) + self.loads(doc) except ValueError: pass else: @@ -79,7 +77,11 @@ data = {'a' : 1, (1, 2) : 2} #This is for c encoder - self.assertRaises(TypeError, json.dumps, data) + self.assertRaises(TypeError, self.dumps, data) #This is for python encoder - self.assertRaises(TypeError, json.dumps, data, indent=True) + self.assertRaises(TypeError, self.dumps, data, indent=True) + + +class TestPyFail(TestFail, PyTest): pass +class TestCFail(TestFail, CTest): pass diff --git a/Lib/test/json_tests/test_float.py b/Lib/test/json_tests/test_float.py --- a/Lib/test/json_tests/test_float.py +++ b/Lib/test/json_tests/test_float.py @@ -1,15 +1,18 @@ import math -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json -class TestFloat(TestCase): +class TestFloat: def test_floats(self): for num in [1617161771.7650001, math.pi, math.pi**100, math.pi**-100, 3.1]: - self.assertEqual(float(json.dumps(num)), num) - self.assertEqual(json.loads(json.dumps(num)), num) + self.assertEqual(float(self.dumps(num)), num) + self.assertEqual(self.loads(self.dumps(num)), num) def test_ints(self): for num in [1, 1<<32, 1<<64]: - self.assertEqual(json.dumps(num), str(num)) - self.assertEqual(int(json.dumps(num)), num) + self.assertEqual(self.dumps(num), str(num)) + self.assertEqual(int(self.dumps(num)), num) + + +class TestPyFloat(TestFloat, PyTest): pass +class TestCFloat(TestFloat, CTest): pass diff --git a/Lib/test/json_tests/test_indent.py b/Lib/test/json_tests/test_indent.py --- a/Lib/test/json_tests/test_indent.py +++ b/Lib/test/json_tests/test_indent.py @@ -1,10 +1,9 @@ -from unittest import TestCase - -import json import textwrap from io import StringIO +from test.json_tests import PyTest, CTest -class TestIndent(TestCase): + +class TestIndent: def test_indent(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -30,14 +29,13 @@ \t} ]""") + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) + d3 = self.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) - d3 = json.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) - - h1 = json.loads(d1) - h2 = json.loads(d2) - h3 = json.loads(d3) + h1 = self.loads(d1) + h2 = self.loads(d2) + h3 = self.loads(d3) self.assertEqual(h1, h) self.assertEqual(h2, h) @@ -48,14 +46,18 @@ def test_indent0(self): h = {3: 1} def check(indent, expected): - d1 = json.dumps(h, indent=indent) + d1 = self.dumps(h, indent=indent) self.assertEqual(d1, expected) sio = StringIO() - json.dump(h, sio, indent=indent) + self.json.dump(h, sio, indent=indent) self.assertEqual(sio.getvalue(), expected) # indent=0 should emit newlines check(0, '{\n"3": 1\n}') # indent=None is more compact check(None, '{"3": 1}') + + +class TestPyIndent(TestIndent, PyTest): pass +class TestCIndent(TestIndent, CTest): pass diff --git a/Lib/test/json_tests/test_pass1.py b/Lib/test/json_tests/test_pass1.py --- a/Lib/test/json_tests/test_pass1.py +++ b/Lib/test/json_tests/test_pass1.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass1.json JSON = r''' @@ -62,15 +61,19 @@ ,"rosebud"] ''' -class TestPass1(TestCase): +class TestPass1: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) try: - json.dumps(res, allow_nan=False) + self.dumps(res, allow_nan=False) except ValueError: pass else: self.fail("23456789012E666 should be out of range") + + +class TestPyPass1(TestPass1, PyTest): pass +class TestCPass1(TestPass1, CTest): pass diff --git a/Lib/test/json_tests/test_pass2.py b/Lib/test/json_tests/test_pass2.py --- a/Lib/test/json_tests/test_pass2.py +++ b/Lib/test/json_tests/test_pass2.py @@ -1,14 +1,18 @@ -from unittest import TestCase -import json +from test.json_tests import PyTest, CTest + # from http://json.org/JSON_checker/test/pass2.json JSON = r''' [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] ''' -class TestPass2(TestCase): +class TestPass2: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass2(TestPass2, PyTest): pass +class TestCPass2(TestPass2, CTest): pass diff --git a/Lib/test/json_tests/test_pass3.py b/Lib/test/json_tests/test_pass3.py --- a/Lib/test/json_tests/test_pass3.py +++ b/Lib/test/json_tests/test_pass3.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass3.json JSON = r''' @@ -12,9 +11,14 @@ } ''' -class TestPass3(TestCase): + +class TestPass3: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass3(TestPass3, PyTest): pass +class TestCPass3(TestPass3, CTest): pass diff --git a/Lib/test/json_tests/test_recursion.py b/Lib/test/json_tests/test_recursion.py --- a/Lib/test/json_tests/test_recursion.py +++ b/Lib/test/json_tests/test_recursion.py @@ -1,33 +1,16 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json class JSONTestObject: pass -class RecursiveJSONEncoder(json.JSONEncoder): - recurse = False - def default(self, o): - if o is JSONTestObject: - if self.recurse: - return [JSONTestObject] - else: - return 'JSONTestObject' - return json.JSONEncoder.default(o) - -class EndlessJSONEncoder(json.JSONEncoder): - def default(self, o): - """If check_circular is False, this will keep adding another list.""" - return [o] - - -class TestRecursion(TestCase): +class TestRecursion: def test_listrecursion(self): x = [] x.append(x) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -36,7 +19,7 @@ y = [x] x.append(y) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -44,13 +27,13 @@ y = [] x = [y, y] # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_dictrecursion(self): x = {} x["test"] = x try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -58,9 +41,19 @@ x = {} y = {"a": x, "b": x} # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_defaultrecursion(self): + class RecursiveJSONEncoder(self.json.JSONEncoder): + recurse = False + def default(self, o): + if o is JSONTestObject: + if self.recurse: + return [JSONTestObject] + else: + return 'JSONTestObject' + return pyjson.JSONEncoder.default(o) + enc = RecursiveJSONEncoder() self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"') enc.recurse = True @@ -76,11 +69,11 @@ # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '1' + '}' * 100000) + self.loads('{"a":' * 100000 + '1' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) + self.loads('{"a":' * 100000 + '[1]' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('[' * 100000 + '1' + ']' * 100000) + self.loads('[' * 100000 + '1' + ']' * 100000) def test_highly_nested_objects_encoding(self): # See #12051 @@ -88,11 +81,20 @@ for x in range(100000): l, d = [l], {'k':d} with self.assertRaises(RuntimeError): - json.dumps(l) + self.dumps(l) with self.assertRaises(RuntimeError): - json.dumps(d) + self.dumps(d) def test_endless_recursion(self): # See #12051 + class EndlessJSONEncoder(self.json.JSONEncoder): + def default(self, o): + """If check_circular is False, this will keep adding another list.""" + return [o] + with self.assertRaises(RuntimeError): EndlessJSONEncoder(check_circular=False).encode(5j) + + +class TestPyRecursion(TestRecursion, PyTest): pass +class TestCRecursion(TestRecursion, CTest): pass diff --git a/Lib/test/json_tests/test_scanstring.py b/Lib/test/json_tests/test_scanstring.py --- a/Lib/test/json_tests/test_scanstring.py +++ b/Lib/test/json_tests/test_scanstring.py @@ -1,24 +1,10 @@ import sys -from unittest import TestCase, skipUnless +from test.json_tests import PyTest, CTest -import json -import json.decoder -try: - import _json -except ImportError: - _json = None - -class TestScanString(TestCase): - def test_py_scanstring(self): - self._test_scanstring(json.decoder.py_scanstring) - - @skipUnless(_json, 'test requires the _json module') - def test_c_scanstring(self): - if json.decoder.c_scanstring is not None: - self._test_scanstring(json.decoder.c_scanstring) - - def _test_scanstring(self, scanstring): +class TestScanstring: + def test_scanstring(self): + scanstring = self.json.decoder.scanstring self.assertEqual( scanstring('"z\\ud834\\udd20x"', 1, True), ('z\U0001d120x', 16)) @@ -109,4 +95,9 @@ ('Bad value', 12)) def test_overflow(self): - self.assertRaises(OverflowError, json.decoder.scanstring, b"xxx", sys.maxsize+1) + with self.assertRaises(OverflowError): + self.json.decoder.scanstring(b"xxx", sys.maxsize+1) + + +class TestPyScanstring(TestScanstring, PyTest): pass +class TestCScanstring(TestScanstring, CTest): pass diff --git a/Lib/test/json_tests/test_separators.py b/Lib/test/json_tests/test_separators.py --- a/Lib/test/json_tests/test_separators.py +++ b/Lib/test/json_tests/test_separators.py @@ -1,10 +1,8 @@ import textwrap -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json - -class TestSeparators(TestCase): +class TestSeparators: def test_separators(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -31,12 +29,16 @@ ]""") - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) - h1 = json.loads(d1) - h2 = json.loads(d2) + h1 = self.loads(d1) + h2 = self.loads(d2) self.assertEqual(h1, h) self.assertEqual(h2, h) self.assertEqual(d2, expect) + + +class TestPySeparators(TestSeparators, PyTest): pass +class TestCSeparators(TestSeparators, CTest): pass diff --git a/Lib/test/json_tests/test_speedups.py b/Lib/test/json_tests/test_speedups.py --- a/Lib/test/json_tests/test_speedups.py +++ b/Lib/test/json_tests/test_speedups.py @@ -1,29 +1,24 @@ -from unittest import TestCase, skipUnless +from test.json_tests import CTest -from json import decoder, encoder, scanner -try: - import _json -except ImportError: - _json = None - - at skipUnless(_json, 'test requires the _json module') -class TestSpeedups(TestCase): +class TestSpeedups(CTest): def test_scanstring(self): - self.assertEqual(decoder.scanstring.__module__, "_json") - self.assertIs(decoder.scanstring, decoder.c_scanstring) + self.assertEqual(self.json.decoder.scanstring.__module__, "_json") + self.assertIs(self.json.decoder.scanstring, self.json.decoder.c_scanstring) def test_encode_basestring_ascii(self): - self.assertEqual(encoder.encode_basestring_ascii.__module__, "_json") - self.assertIs(encoder.encode_basestring_ascii, - encoder.c_encode_basestring_ascii) + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + "_json") + self.assertIs(self.json.encoder.encode_basestring_ascii, + self.json.encoder.c_encode_basestring_ascii) -class TestDecode(TestCase): + +class TestDecode(CTest): def test_make_scanner(self): - self.assertRaises(AttributeError, scanner.c_make_scanner, 1) + self.assertRaises(AttributeError, self.json.scanner.c_make_scanner, 1) def test_make_encoder(self): - self.assertRaises(TypeError, encoder.c_make_encoder, + self.assertRaises(TypeError, self.json.encoder.c_make_encoder, (True, False), b"\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75", None) diff --git a/Lib/test/json_tests/test_unicode.py b/Lib/test/json_tests/test_unicode.py --- a/Lib/test/json_tests/test_unicode.py +++ b/Lib/test/json_tests/test_unicode.py @@ -1,73 +1,75 @@ -from unittest import TestCase +from collections import OrderedDict +from test.json_tests import PyTest, CTest -import json -from collections import OrderedDict -class TestUnicode(TestCase): +class TestUnicode: # test_encoding1 and test_encoding2 from 2.x are irrelevant (only str # is supported as input, not bytes). def test_encoding3(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u) + j = self.dumps(u) self.assertEqual(j, '"\\u03b1\\u03a9"') def test_encoding4(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u]) + j = self.dumps([u]) self.assertEqual(j, '["\\u03b1\\u03a9"]') def test_encoding5(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u, ensure_ascii=False) + j = self.dumps(u, ensure_ascii=False) self.assertEqual(j, '"{0}"'.format(u)) def test_encoding6(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u], ensure_ascii=False) + j = self.dumps([u], ensure_ascii=False) self.assertEqual(j, '["{0}"]'.format(u)) def test_big_unicode_encode(self): u = '\U0001d120' - self.assertEqual(json.dumps(u), '"\\ud834\\udd20"') - self.assertEqual(json.dumps(u, ensure_ascii=False), '"\U0001d120"') + self.assertEqual(self.dumps(u), '"\\ud834\\udd20"') + self.assertEqual(self.dumps(u, ensure_ascii=False), '"\U0001d120"') def test_big_unicode_decode(self): u = 'z\U0001d120x' - self.assertEqual(json.loads('"' + u + '"'), u) - self.assertEqual(json.loads('"z\\ud834\\udd20x"'), u) + self.assertEqual(self.loads('"' + u + '"'), u) + self.assertEqual(self.loads('"z\\ud834\\udd20x"'), u) def test_unicode_decode(self): for i in range(0, 0xd7ff): u = chr(i) s = '"\\u{0:04x}"'.format(i) - self.assertEqual(json.loads(s), u) + self.assertEqual(self.loads(s), u) def test_unicode_preservation(self): - self.assertEqual(type(json.loads('""')), str) - self.assertEqual(type(json.loads('"a"')), str) - self.assertEqual(type(json.loads('["a"]')[0]), str) + self.assertEqual(type(self.loads('""')), str) + self.assertEqual(type(self.loads('"a"')), str) + self.assertEqual(type(self.loads('["a"]')[0]), str) def test_bytes_encode(self): - self.assertRaises(TypeError, json.dumps, b"hi") - self.assertRaises(TypeError, json.dumps, [b"hi"]) + self.assertRaises(TypeError, self.dumps, b"hi") + self.assertRaises(TypeError, self.dumps, [b"hi"]) def test_bytes_decode(self): - self.assertRaises(TypeError, json.loads, b'"hi"') - self.assertRaises(TypeError, json.loads, b'["hi"]') + self.assertRaises(TypeError, self.loads, b'"hi"') + self.assertRaises(TypeError, self.loads, b'["hi"]') def test_object_pairs_hook_with_unicode(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) - od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p) + od = self.loads(s, object_pairs_hook = OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, - object_pairs_hook = OrderedDict, + self.assertEqual(self.loads(s, object_pairs_hook = OrderedDict, object_hook = lambda x: None), OrderedDict(p)) + + +class TestPyUnicode(TestUnicode, PyTest): pass +class TestCUnicode(TestUnicode, CTest): pass diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -127,8 +127,8 @@ If deprecated is True, any module or package deprecation messages will be suppressed.""" - # NOTE: test_heapq and test_warnings include extra sanity checks to make - # sure that this utility function is working as expected + # NOTE: test_heapq, test_json and test_warnings include extra sanity checks + # to make sure that this utility function is working as expected with _ignore_deprecated_imports(deprecated): # Keep track of modules saved for later restoration as well # as those which just need a blocking entry removed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -659,6 +659,8 @@ Tests ----- +- Issue #5723: Improve json tests to be executed with and without accelerations. + - Issue #12041: Make test_wait3 more robust. - Issue #11873: Change regex in test_compileall to fix occasional failures when -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 06:56:00 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 06:56:00 +0200 Subject: [Python-checkins] devguide: Now I like json. Message-ID: http://hg.python.org/devguide/rev/c9d5db7bef23 changeset: 418:c9d5db7bef23 user: Ezio Melotti date: Sat May 14 07:55:56 2011 +0300 summary: Now I like json. files: experts.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -45,7 +45,7 @@ Module Maintainers ==================== ============================================= __future__ -__main__ gvanrossum,ncoghlan +__main__ gvanrossum, ncoghlan _dummy_thread brett.cannon _thread pitrou abc @@ -128,7 +128,7 @@ inspect io pitrou, benjamin.peterson, stutzbach itertools rhettinger -json bob.ippolito (inactive), rhettinger +json bob.ippolito (inactive), ezio.melotti, rhettinger keyword lib2to3 benjamin.peterson linecache -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat May 14 07:44:24 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 07:44:24 +0200 Subject: [Python-checkins] cpython (2.7): #7960: fix docstrings for captured_output and captured_stdout. Message-ID: http://hg.python.org/cpython/rev/459e2c024420 changeset: 70088:459e2c024420 branch: 2.7 parent: 70084:5b0fecd2eba0 user: Ezio Melotti date: Sat May 14 08:19:43 2011 +0300 summary: #7960: fix docstrings for captured_output and captured_stdout. files: Lib/test/test_support.py | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -814,14 +814,8 @@ @contextlib.contextmanager def captured_output(stream_name): - """Run the 'with' statement body using a StringIO object in place of a - specific attribute on the sys module. - Example use (with 'stream_name=stdout'):: - - with captured_stdout() as s: - print "hello" - assert s.getvalue() == "hello" - """ + """Return a context manager used by captured_stdout and captured_stdin + that temporarily replaces the sys stream *stream_name* with a StringIO.""" import StringIO orig_stdout = getattr(sys, stream_name) setattr(sys, stream_name, StringIO.StringIO()) @@ -831,6 +825,12 @@ setattr(sys, stream_name, orig_stdout) def captured_stdout(): + """Capture the output of sys.stdout: + + with captured_stdout() as s: + print "hello" + self.assertEqual(s.getvalue(), "hello") + """ return captured_output("stdout") def captured_stdin(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 07:44:24 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 07:44:24 +0200 Subject: [Python-checkins] cpython (3.1): #7960: fix docstrings for captured_output and captured_stdout. Message-ID: http://hg.python.org/cpython/rev/c2126d89c29b changeset: 70089:c2126d89c29b branch: 3.1 parent: 70085:c2853a54b29e user: Ezio Melotti date: Sat May 14 08:22:47 2011 +0300 summary: #7960: fix docstrings for captured_output and captured_stdout. files: Lib/test/support.py | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -712,14 +712,8 @@ @contextlib.contextmanager def captured_output(stream_name): - """Run the 'with' statement body using a StringIO object in place of a - specific attribute on the sys module. - Example use (with 'stream_name=stdout'):: - - with captured_stdout() as s: - print("hello") - assert s.getvalue() == "hello" - """ + """Return a context manager used by captured_stdout and captured_stdin + that temporarily replaces the sys stream *stream_name* with a StringIO.""" import io orig_stdout = getattr(sys, stream_name) setattr(sys, stream_name, io.StringIO()) @@ -729,6 +723,12 @@ setattr(sys, stream_name, orig_stdout) def captured_stdout(): + """Capture the output of sys.stdout: + + with captured_stdout() as s: + print("hello") + self.assertEqual(s.getvalue(), "hello") + """ return captured_output("stdout") def gc_collect(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 07:44:25 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 07:44:25 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #7960: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/18a192ae6db9 changeset: 70090:18a192ae6db9 branch: 3.2 parent: 70086:63fb2b811c9d parent: 70089:c2126d89c29b user: Ezio Melotti date: Sat May 14 08:43:25 2011 +0300 summary: #7960: merge with 3.1. files: Lib/test/support.py | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -891,14 +891,8 @@ @contextlib.contextmanager def captured_output(stream_name): - """Run the 'with' statement body using a StringIO object in place of a - specific attribute on the sys module. - Example use (with 'stream_name=stdout'):: - - with captured_stdout() as s: - print("hello") - assert s.getvalue() == "hello" - """ + """Return a context manager used by captured_stdout and captured_stdin + that temporarily replaces the sys stream *stream_name* with a StringIO.""" import io orig_stdout = getattr(sys, stream_name) setattr(sys, stream_name, io.StringIO()) @@ -908,6 +902,12 @@ setattr(sys, stream_name, orig_stdout) def captured_stdout(): + """Capture the output of sys.stdout: + + with captured_stdout() as s: + print("hello") + self.assertEqual(s.getvalue(), "hello") + """ return captured_output("stdout") def captured_stderr(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 07:44:27 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 07:44:27 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #7960: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/7517add4aec9 changeset: 70091:7517add4aec9 parent: 70087:afdc06f2552f parent: 70090:18a192ae6db9 user: Ezio Melotti date: Sat May 14 08:44:12 2011 +0300 summary: #7960: merge with 3.2. files: Lib/test/support.py | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -887,14 +887,8 @@ @contextlib.contextmanager def captured_output(stream_name): - """Run the 'with' statement body using a StringIO object in place of a - specific attribute on the sys module. - Example use (with 'stream_name=stdout'):: - - with captured_stdout() as s: - print("hello") - assert s.getvalue() == "hello" - """ + """Return a context manager used by captured_stdout and captured_stdin + that temporarily replaces the sys stream *stream_name* with a StringIO.""" import io orig_stdout = getattr(sys, stream_name) setattr(sys, stream_name, io.StringIO()) @@ -904,6 +898,12 @@ setattr(sys, stream_name, orig_stdout) def captured_stdout(): + """Capture the output of sys.stdout: + + with captured_stdout() as s: + print("hello") + self.assertEqual(s.getvalue(), "hello") + """ return captured_output("stdout") def captured_stderr(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 08:24:42 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 08:24:42 +0200 Subject: [Python-checkins] cpython (2.7): #11979: improve wording and markup in sockets howto. Patch by Xavier Morel. Message-ID: http://hg.python.org/cpython/rev/4081f326e46c changeset: 70092:4081f326e46c branch: 2.7 parent: 70088:459e2c024420 user: Ezio Melotti date: Sat May 14 09:17:52 2011 +0300 summary: #11979: improve wording and markup in sockets howto. Patch by Xavier Morel. files: Doc/howto/sockets.rst | 33 +++++++++++++++--------------- 1 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -43,10 +43,10 @@ History ------- -Of the various forms of IPC (*Inter Process Communication*), sockets are by far -the most popular. On any given platform, there are likely to be other forms of -IPC that are faster, but for cross-platform communication, sockets are about the -only game in town. +Of the various forms of :abbr:`IPC (Inter Process Communication)`, +sockets are by far the most popular. On any given platform, there are +likely to be other forms of IPC that are faster, but for +cross-platform communication, sockets are about the only game in town. They were invented in Berkeley as part of the BSD flavor of Unix. They spread like wildfire with the Internet. With good reason --- the combination of sockets @@ -67,13 +67,14 @@ # - the normal http port s.connect(("www.mcmillan-inc.com", 80)) -When the ``connect`` completes, the socket ``s`` can now be used to send in a -request for the text of this page. The same socket will read the reply, and then -be destroyed. That's right - destroyed. Client sockets are normally only used -for one exchange (or a small set of sequential exchanges). +When the ``connect`` completes, the socket ``s`` can be used to send +in a request for the text of the page. The same socket will read the +reply, and then be destroyed. That's right, destroyed. Client sockets +are normally only used for one exchange (or a small set of sequential +exchanges). What happens in the web server is a bit more complex. First, the web server -creates a "server socket". :: +creates a "server socket":: #create an INET, STREAMing socket serversocket = socket.socket( @@ -97,7 +98,7 @@ queue up as many as 5 connect requests (the normal max) before refusing outside connections. If the rest of the code is written properly, that should be plenty. -OK, now we have a "server" socket, listening on port 80. Now we enter the +Now that we have a "server" socket, listening on port 80, we can enter the mainloop of the web server:: while 1: @@ -146,7 +147,7 @@ Now there are two sets of verbs to use for communication. You can use ``send`` and ``recv``, or you can transform your client socket into a file-like beast and -use ``read`` and ``write``. The latter is the way Java presents their sockets. +use ``read`` and ``write``. The latter is the way Java presents its sockets. I'm not going to talk about it here, except to warn you that you need to use ``flush`` on sockets. These are buffered "files", and a common mistake is to ``write`` something, and then ``read`` for a reply. Without a ``flush`` in @@ -167,11 +168,11 @@ about that some on the next page. A protocol like HTTP uses a socket for only one transfer. The client sends a -request, the reads a reply. That's it. The socket is discarded. This means that +request, then reads a reply. That's it. The socket is discarded. This means that a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize -that *there is no "EOT" (End of Transfer) on a socket.* I repeat: if a socket +that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* I repeat: if a socket ``send`` or ``recv`` returns after handling 0 bytes, the connection has been broken. If the connection has *not* been broken, you may wait on a ``recv`` forever, because the socket will *not* tell you that there's nothing more to @@ -337,7 +338,7 @@ In C, coding ``select`` is fairly complex. In Python, it's a piece of cake, but it's close enough to the C version that if you understand ``select`` in Python, -you'll have little trouble with it in C. :: +you'll have little trouble with it in C:: ready_to_read, ready_to_write, in_error = \ select.select( @@ -354,9 +355,9 @@ thing to do - give it a nice long timeout (say a minute) unless you have good reason to do otherwise. -In return, you will get three lists. They have the sockets that are actually +In return, you will get three lists. They contain the sockets that are actually readable, writable and in error. Each of these lists is a subset (possibly -empty) of the corresponding list you passed in. And if you put a socket in more +empty) of the corresponding list you passed in. If you put a socket in more than one input list, it will only be (at most) in one output list. If a socket is in the output readable list, you can be -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 08:24:42 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 08:24:42 +0200 Subject: [Python-checkins] cpython (3.1): #11979: improve wording and markup in sockets howto. Patch by Xavier Morel. Message-ID: http://hg.python.org/cpython/rev/85b9ad8b219b changeset: 70093:85b9ad8b219b branch: 3.1 parent: 70089:c2126d89c29b user: Ezio Melotti date: Sat May 14 09:17:52 2011 +0300 summary: #11979: improve wording and markup in sockets howto. Patch by Xavier Morel. files: Doc/howto/sockets.rst | 33 +++++++++++++++--------------- 1 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -43,10 +43,10 @@ History ------- -Of the various forms of IPC (*Inter Process Communication*), sockets are by far -the most popular. On any given platform, there are likely to be other forms of -IPC that are faster, but for cross-platform communication, sockets are about the -only game in town. +Of the various forms of :abbr:`IPC (Inter Process Communication)`, +sockets are by far the most popular. On any given platform, there are +likely to be other forms of IPC that are faster, but for +cross-platform communication, sockets are about the only game in town. They were invented in Berkeley as part of the BSD flavor of Unix. They spread like wildfire with the Internet. With good reason --- the combination of sockets @@ -66,13 +66,14 @@ # - the normal http port s.connect(("www.mcmillan-inc.com", 80)) -When the ``connect`` completes, the socket ``s`` can now be used to send in a -request for the text of this page. The same socket will read the reply, and then -be destroyed. That's right - destroyed. Client sockets are normally only used -for one exchange (or a small set of sequential exchanges). +When the ``connect`` completes, the socket ``s`` can be used to send +in a request for the text of the page. The same socket will read the +reply, and then be destroyed. That's right, destroyed. Client sockets +are normally only used for one exchange (or a small set of sequential +exchanges). What happens in the web server is a bit more complex. First, the web server -creates a "server socket". :: +creates a "server socket":: #create an INET, STREAMing socket serversocket = socket.socket( @@ -96,7 +97,7 @@ queue up as many as 5 connect requests (the normal max) before refusing outside connections. If the rest of the code is written properly, that should be plenty. -OK, now we have a "server" socket, listening on port 80. Now we enter the +Now that we have a "server" socket, listening on port 80, we can enter the mainloop of the web server:: while True: @@ -145,7 +146,7 @@ Now there are two sets of verbs to use for communication. You can use ``send`` and ``recv``, or you can transform your client socket into a file-like beast and -use ``read`` and ``write``. The latter is the way Java presents their sockets. +use ``read`` and ``write``. The latter is the way Java presents its sockets. I'm not going to talk about it here, except to warn you that you need to use ``flush`` on sockets. These are buffered "files", and a common mistake is to ``write`` something, and then ``read`` for a reply. Without a ``flush`` in @@ -166,11 +167,11 @@ about that some on the next page. A protocol like HTTP uses a socket for only one transfer. The client sends a -request, the reads a reply. That's it. The socket is discarded. This means that +request, then reads a reply. That's it. The socket is discarded. This means that a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize -that *there is no "EOT" (End of Transfer) on a socket.* I repeat: if a socket +that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* I repeat: if a socket ``send`` or ``recv`` returns after handling 0 bytes, the connection has been broken. If the connection has *not* been broken, you may wait on a ``recv`` forever, because the socket will *not* tell you that there's nothing more to @@ -336,7 +337,7 @@ In C, coding ``select`` is fairly complex. In Python, it's a piece of cake, but it's close enough to the C version that if you understand ``select`` in Python, -you'll have little trouble with it in C. :: +you'll have little trouble with it in C:: ready_to_read, ready_to_write, in_error = \ select.select( @@ -353,9 +354,9 @@ thing to do - give it a nice long timeout (say a minute) unless you have good reason to do otherwise. -In return, you will get three lists. They have the sockets that are actually +In return, you will get three lists. They contain the sockets that are actually readable, writable and in error. Each of these lists is a subset (possibly -empty) of the corresponding list you passed in. And if you put a socket in more +empty) of the corresponding list you passed in. If you put a socket in more than one input list, it will only be (at most) in one output list. If a socket is in the output readable list, you can be -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 08:24:43 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 08:24:43 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): #11979: merge with 3.1. Message-ID: http://hg.python.org/cpython/rev/bc251b65de1d changeset: 70094:bc251b65de1d branch: 3.2 parent: 70090:18a192ae6db9 parent: 70093:85b9ad8b219b user: Ezio Melotti date: Sat May 14 09:23:52 2011 +0300 summary: #11979: merge with 3.1. files: Doc/howto/sockets.rst | 33 +++++++++++++++--------------- 1 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -43,10 +43,10 @@ History ------- -Of the various forms of IPC (*Inter Process Communication*), sockets are by far -the most popular. On any given platform, there are likely to be other forms of -IPC that are faster, but for cross-platform communication, sockets are about the -only game in town. +Of the various forms of :abbr:`IPC (Inter Process Communication)`, +sockets are by far the most popular. On any given platform, there are +likely to be other forms of IPC that are faster, but for +cross-platform communication, sockets are about the only game in town. They were invented in Berkeley as part of the BSD flavor of Unix. They spread like wildfire with the Internet. With good reason --- the combination of sockets @@ -66,13 +66,14 @@ # - the normal http port s.connect(("www.mcmillan-inc.com", 80)) -When the ``connect`` completes, the socket ``s`` can now be used to send in a -request for the text of this page. The same socket will read the reply, and then -be destroyed. That's right - destroyed. Client sockets are normally only used -for one exchange (or a small set of sequential exchanges). +When the ``connect`` completes, the socket ``s`` can be used to send +in a request for the text of the page. The same socket will read the +reply, and then be destroyed. That's right, destroyed. Client sockets +are normally only used for one exchange (or a small set of sequential +exchanges). What happens in the web server is a bit more complex. First, the web server -creates a "server socket". :: +creates a "server socket":: #create an INET, STREAMing socket serversocket = socket.socket( @@ -96,7 +97,7 @@ queue up as many as 5 connect requests (the normal max) before refusing outside connections. If the rest of the code is written properly, that should be plenty. -OK, now we have a "server" socket, listening on port 80. Now we enter the +Now that we have a "server" socket, listening on port 80, we can enter the mainloop of the web server:: while True: @@ -145,7 +146,7 @@ Now there are two sets of verbs to use for communication. You can use ``send`` and ``recv``, or you can transform your client socket into a file-like beast and -use ``read`` and ``write``. The latter is the way Java presents their sockets. +use ``read`` and ``write``. The latter is the way Java presents its sockets. I'm not going to talk about it here, except to warn you that you need to use ``flush`` on sockets. These are buffered "files", and a common mistake is to ``write`` something, and then ``read`` for a reply. Without a ``flush`` in @@ -166,11 +167,11 @@ about that some on the next page. A protocol like HTTP uses a socket for only one transfer. The client sends a -request, the reads a reply. That's it. The socket is discarded. This means that +request, then reads a reply. That's it. The socket is discarded. This means that a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize -that *there is no "EOT" (End of Transfer) on a socket.* I repeat: if a socket +that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* I repeat: if a socket ``send`` or ``recv`` returns after handling 0 bytes, the connection has been broken. If the connection has *not* been broken, you may wait on a ``recv`` forever, because the socket will *not* tell you that there's nothing more to @@ -336,7 +337,7 @@ In C, coding ``select`` is fairly complex. In Python, it's a piece of cake, but it's close enough to the C version that if you understand ``select`` in Python, -you'll have little trouble with it in C. :: +you'll have little trouble with it in C:: ready_to_read, ready_to_write, in_error = \ select.select( @@ -353,9 +354,9 @@ thing to do - give it a nice long timeout (say a minute) unless you have good reason to do otherwise. -In return, you will get three lists. They have the sockets that are actually +In return, you will get three lists. They contain the sockets that are actually readable, writable and in error. Each of these lists is a subset (possibly -empty) of the corresponding list you passed in. And if you put a socket in more +empty) of the corresponding list you passed in. If you put a socket in more than one input list, it will only be (at most) in one output list. If a socket is in the output readable list, you can be -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 08:24:44 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 08:24:44 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): #11979: merge with 3.2. Message-ID: http://hg.python.org/cpython/rev/4b122cac7ac5 changeset: 70095:4b122cac7ac5 parent: 70091:7517add4aec9 parent: 70094:bc251b65de1d user: Ezio Melotti date: Sat May 14 09:24:33 2011 +0300 summary: #11979: merge with 3.2. files: Doc/howto/sockets.rst | 33 +++++++++++++++--------------- 1 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -43,10 +43,10 @@ History ------- -Of the various forms of IPC (*Inter Process Communication*), sockets are by far -the most popular. On any given platform, there are likely to be other forms of -IPC that are faster, but for cross-platform communication, sockets are about the -only game in town. +Of the various forms of :abbr:`IPC (Inter Process Communication)`, +sockets are by far the most popular. On any given platform, there are +likely to be other forms of IPC that are faster, but for +cross-platform communication, sockets are about the only game in town. They were invented in Berkeley as part of the BSD flavor of Unix. They spread like wildfire with the Internet. With good reason --- the combination of sockets @@ -66,13 +66,14 @@ # - the normal http port s.connect(("www.mcmillan-inc.com", 80)) -When the ``connect`` completes, the socket ``s`` can now be used to send in a -request for the text of this page. The same socket will read the reply, and then -be destroyed. That's right - destroyed. Client sockets are normally only used -for one exchange (or a small set of sequential exchanges). +When the ``connect`` completes, the socket ``s`` can be used to send +in a request for the text of the page. The same socket will read the +reply, and then be destroyed. That's right, destroyed. Client sockets +are normally only used for one exchange (or a small set of sequential +exchanges). What happens in the web server is a bit more complex. First, the web server -creates a "server socket". :: +creates a "server socket":: #create an INET, STREAMing socket serversocket = socket.socket( @@ -96,7 +97,7 @@ queue up as many as 5 connect requests (the normal max) before refusing outside connections. If the rest of the code is written properly, that should be plenty. -OK, now we have a "server" socket, listening on port 80. Now we enter the +Now that we have a "server" socket, listening on port 80, we can enter the mainloop of the web server:: while True: @@ -145,7 +146,7 @@ Now there are two sets of verbs to use for communication. You can use ``send`` and ``recv``, or you can transform your client socket into a file-like beast and -use ``read`` and ``write``. The latter is the way Java presents their sockets. +use ``read`` and ``write``. The latter is the way Java presents its sockets. I'm not going to talk about it here, except to warn you that you need to use ``flush`` on sockets. These are buffered "files", and a common mistake is to ``write`` something, and then ``read`` for a reply. Without a ``flush`` in @@ -166,11 +167,11 @@ about that some on the next page. A protocol like HTTP uses a socket for only one transfer. The client sends a -request, the reads a reply. That's it. The socket is discarded. This means that +request, then reads a reply. That's it. The socket is discarded. This means that a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize -that *there is no "EOT" (End of Transfer) on a socket.* I repeat: if a socket +that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* I repeat: if a socket ``send`` or ``recv`` returns after handling 0 bytes, the connection has been broken. If the connection has *not* been broken, you may wait on a ``recv`` forever, because the socket will *not* tell you that there's nothing more to @@ -336,7 +337,7 @@ In C, coding ``select`` is fairly complex. In Python, it's a piece of cake, but it's close enough to the C version that if you understand ``select`` in Python, -you'll have little trouble with it in C. :: +you'll have little trouble with it in C:: ready_to_read, ready_to_write, in_error = \ select.select( @@ -353,9 +354,9 @@ thing to do - give it a nice long timeout (say a minute) unless you have good reason to do otherwise. -In return, you will get three lists. They have the sockets that are actually +In return, you will get three lists. They contain the sockets that are actually readable, writable and in error. Each of these lists is a subset (possibly -empty) of the corresponding list you passed in. And if you put a socket in more +empty) of the corresponding list you passed in. If you put a socket in more than one input list, it will only be (at most) in one output list. If a socket is in the output readable list, you can be -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 09:11:05 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 09:11:05 +0200 Subject: [Python-checkins] cpython: Skip test in test_fileinput when zlib is missing. Message-ID: http://hg.python.org/cpython/rev/e0b4ed75b8e7 changeset: 70096:e0b4ed75b8e7 user: Ezio Melotti date: Sat May 14 10:10:53 2011 +0300 summary: Skip test in test_fileinput when zlib is missing. files: Lib/test/test_fileinput.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_fileinput.py b/Lib/test/test_fileinput.py --- a/Lib/test/test_fileinput.py +++ b/Lib/test/test_fileinput.py @@ -7,7 +7,6 @@ import re import fileinput import collections -import gzip import types import codecs import unittest @@ -16,6 +15,10 @@ import bz2 except ImportError: bz2 = None +try: + import gzip +except ImportError: + gzip = None from io import StringIO from fileinput import FileInput, hook_encoded @@ -758,6 +761,7 @@ def test_no_ext(self): self.do_test_use_builtin_open("abcd", 2) + @unittest.skipUnless(gzip, "Requires gzip and zlib") def test_gz_ext_fake(self): original_open = gzip.open gzip.open = self.fake_open -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 13:57:27 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 13:57:27 +0200 Subject: [Python-checkins] cpython (3.2): Update __all__ and docstring. Message-ID: http://hg.python.org/cpython/rev/b2bcddfb8b18 changeset: 70097:b2bcddfb8b18 branch: 3.2 parent: 70094:bc251b65de1d user: Ezio Melotti date: Sat May 14 14:51:18 2011 +0300 summary: Update __all__ and docstring. files: Lib/test/support.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -37,6 +37,7 @@ "findfile", "sortdict", "check_syntax_error", "open_urlresource", "check_warnings", "CleanImport", "EnvironmentVarGuard", "TransientResource", "captured_output", "captured_stdout", + "captured_stdin", "captured_stderr", "time_out", "socket_peer_reset", "ioerror_peer_reset", "run_with_locale", 'temp_umask', "transient_internet", "set_memlimit", "bigmemtest", "bigaddrspacetest", "BasicTestRunner", @@ -891,7 +892,7 @@ @contextlib.contextmanager def captured_output(stream_name): - """Return a context manager used by captured_stdout and captured_stdin + """Return a context manager used by captured_stdout/stdin/stderr that temporarily replaces the sys stream *stream_name* with a StringIO.""" import io orig_stdout = getattr(sys, stream_name) @@ -916,6 +917,7 @@ def captured_stdin(): return captured_output("stdin") + def gc_collect(): """Force as many objects as possible to be collected. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 13:57:28 2011 From: python-checkins at python.org (ezio.melotti) Date: Sat, 14 May 2011 13:57:28 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge with 3.2 and also remove captured_output from __all__ (see #7960). Message-ID: http://hg.python.org/cpython/rev/ec35f86efb0d changeset: 70098:ec35f86efb0d parent: 70096:e0b4ed75b8e7 parent: 70097:b2bcddfb8b18 user: Ezio Melotti date: Sat May 14 14:57:15 2011 +0300 summary: Merge with 3.2 and also remove captured_output from __all__ (see #7960). files: Lib/test/support.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -35,8 +35,8 @@ "is_resource_enabled", "requires", "find_unused_port", "bind_port", "IPV6_ENABLED", "is_jython", "TESTFN", "HOST", "SAVEDCWD", "temp_cwd", "findfile", "sortdict", "check_syntax_error", "open_urlresource", - "check_warnings", "CleanImport", "EnvironmentVarGuard", - "TransientResource", "captured_output", "captured_stdout", "time_out", + "check_warnings", "CleanImport", "EnvironmentVarGuard", "TransientResource", + "captured_stdout", "captured_stdin", "captured_stderr", "time_out", "socket_peer_reset", "ioerror_peer_reset", "run_with_locale", 'temp_umask', "transient_internet", "set_memlimit", "bigmemtest", "bigaddrspacetest", "BasicTestRunner", "run_unittest", "run_doctest", "threading_setup", @@ -887,7 +887,7 @@ @contextlib.contextmanager def captured_output(stream_name): - """Return a context manager used by captured_stdout and captured_stdin + """Return a context manager used by captured_stdout/stdin/stderr that temporarily replaces the sys stream *stream_name* with a StringIO.""" import io orig_stdout = getattr(sys, stream_name) @@ -912,6 +912,7 @@ def captured_stdin(): return captured_output("stdin") + def gc_collect(): """Force as many objects as possible to be collected. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 14:21:43 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 14 May 2011 14:21:43 +0200 Subject: [Python-checkins] cpython (3.1): Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail Message-ID: http://hg.python.org/cpython/rev/6a45567c7245 changeset: 70099:6a45567c7245 branch: 3.1 parent: 70093:85b9ad8b219b user: Nadeem Vawda date: Sat May 14 14:05:20 2011 +0200 summary: Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. files: Lib/test/test_zlib.py | 9 +++++++++ Misc/NEWS | 3 +++ Modules/zlibmodule.c | 19 ++++++++++++------- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -350,6 +350,15 @@ self.assertRaises(ValueError, dco.decompress, b"", -1) self.assertEqual(b'', dco.unconsumed_tail) + def test_clear_unconsumed_tail(self): + # Issue #12050: calling decompress() without providing max_length + # should clear the unconsumed_tail attribute. + cdata = b"x\x9cKLJ\x06\x00\x02M\x01" # "abc" + dco = zlib.decompressobj() + ddata = dco.decompress(cdata, 1) + ddata += dco.decompress(dco.unconsumed_tail) + self.assertEqual(dco.unconsumed_tail, b"") + def test_flushes(self): # Test flush() with the various options, using all the # different levels in order to provide more variations. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,9 @@ Library ------- +- Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail + attribute when called without a max_length argument. + - Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence on a file opened in read+write mode (namely: reading, seeking a bit forward, writing, then seeking before the previous write but still within buffered diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -560,17 +560,22 @@ Py_END_ALLOW_THREADS } - /* Not all of the compressed data could be accommodated in the output buffer - of specified size. Return the unconsumed tail in an attribute.*/ if(max_length) { + /* Not all of the compressed data could be accommodated in a buffer of + the specified size. Return the unconsumed tail in an attribute. */ Py_DECREF(self->unconsumed_tail); self->unconsumed_tail = PyBytes_FromStringAndSize((char *)self->zst.next_in, self->zst.avail_in); - if(!self->unconsumed_tail) { - Py_DECREF(RetVal); - RetVal = NULL; - goto error; - } + } + else if (PyBytes_GET_SIZE(self->unconsumed_tail) > 0) { + /* All of the compressed data was consumed. Clear unconsumed_tail. */ + Py_DECREF(self->unconsumed_tail); + self->unconsumed_tail = PyBytes_FromStringAndSize("", 0); + } + if (self->unconsumed_tail == NULL) { + Py_DECREF(RetVal); + RetVal = NULL; + goto error; } /* The end of the compressed data has been reached, so set the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 14:21:43 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 14 May 2011 14:21:43 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail Message-ID: http://hg.python.org/cpython/rev/49c998a88777 changeset: 70100:49c998a88777 branch: 3.2 parent: 70097:b2bcddfb8b18 parent: 70099:6a45567c7245 user: Nadeem Vawda date: Sat May 14 14:15:47 2011 +0200 summary: Merge: #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. files: Lib/test/test_zlib.py | 9 +++++++++ Misc/NEWS | 3 +++ Modules/zlibmodule.c | 19 ++++++++++++------- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -360,6 +360,15 @@ self.assertRaises(ValueError, dco.decompress, b"", -1) self.assertEqual(b'', dco.unconsumed_tail) + def test_clear_unconsumed_tail(self): + # Issue #12050: calling decompress() without providing max_length + # should clear the unconsumed_tail attribute. + cdata = b"x\x9cKLJ\x06\x00\x02M\x01" # "abc" + dco = zlib.decompressobj() + ddata = dco.decompress(cdata, 1) + ddata += dco.decompress(dco.unconsumed_tail) + self.assertEqual(dco.unconsumed_tail, b"") + def test_flushes(self): # Test flush() with the various options, using all the # different levels in order to provide more variations. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,9 @@ Library ------- +- Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail + attribute when called without a max_length argument. + - Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence on a file opened in read+write mode (namely: reading, seeking a bit forward, writing, then seeking before the previous write but still within buffered diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -574,17 +574,22 @@ Py_END_ALLOW_THREADS } - /* Not all of the compressed data could be accommodated in the output buffer - of specified size. Return the unconsumed tail in an attribute.*/ if(max_length) { + /* Not all of the compressed data could be accommodated in a buffer of + the specified size. Return the unconsumed tail in an attribute. */ Py_DECREF(self->unconsumed_tail); self->unconsumed_tail = PyBytes_FromStringAndSize((char *)self->zst.next_in, self->zst.avail_in); - if(!self->unconsumed_tail) { - Py_DECREF(RetVal); - RetVal = NULL; - goto error; - } + } + else if (PyBytes_GET_SIZE(self->unconsumed_tail) > 0) { + /* All of the compressed data was consumed. Clear unconsumed_tail. */ + Py_DECREF(self->unconsumed_tail); + self->unconsumed_tail = PyBytes_FromStringAndSize("", 0); + } + if (self->unconsumed_tail == NULL) { + Py_DECREF(RetVal); + RetVal = NULL; + goto error; } /* The end of the compressed data has been reached, so set the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 14:21:45 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 14 May 2011 14:21:45 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail Message-ID: http://hg.python.org/cpython/rev/088e5d705171 changeset: 70101:088e5d705171 parent: 70098:ec35f86efb0d parent: 70100:49c998a88777 user: Nadeem Vawda date: Sat May 14 14:19:56 2011 +0200 summary: Merge: #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. files: Lib/test/test_zlib.py | 9 +++++++++ Misc/NEWS | 3 +++ Modules/zlibmodule.c | 19 ++++++++++++------- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -360,6 +360,15 @@ self.assertRaises(ValueError, dco.decompress, b"", -1) self.assertEqual(b'', dco.unconsumed_tail) + def test_clear_unconsumed_tail(self): + # Issue #12050: calling decompress() without providing max_length + # should clear the unconsumed_tail attribute. + cdata = b"x\x9cKLJ\x06\x00\x02M\x01" # "abc" + dco = zlib.decompressobj() + ddata = dco.decompress(cdata, 1) + ddata += dco.decompress(dco.unconsumed_tail) + self.assertEqual(dco.unconsumed_tail, b"") + def test_flushes(self): # Test flush() with the various options, using all the # different levels in order to provide more variations. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -147,6 +147,9 @@ Library ------- +- Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail + attribute when called without a max_length argument. + - Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence on a file opened in read+write mode (namely: reading, seeking a bit forward, writing, then seeking before the previous write but still within buffered diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -574,17 +574,22 @@ Py_END_ALLOW_THREADS } - /* Not all of the compressed data could be accommodated in the output buffer - of specified size. Return the unconsumed tail in an attribute.*/ if(max_length) { + /* Not all of the compressed data could be accommodated in a buffer of + the specified size. Return the unconsumed tail in an attribute. */ Py_DECREF(self->unconsumed_tail); self->unconsumed_tail = PyBytes_FromStringAndSize((char *)self->zst.next_in, self->zst.avail_in); - if(!self->unconsumed_tail) { - Py_DECREF(RetVal); - RetVal = NULL; - goto error; - } + } + else if (PyBytes_GET_SIZE(self->unconsumed_tail) > 0) { + /* All of the compressed data was consumed. Clear unconsumed_tail. */ + Py_DECREF(self->unconsumed_tail); + self->unconsumed_tail = PyBytes_FromStringAndSize("", 0); + } + if (self->unconsumed_tail == NULL) { + Py_DECREF(RetVal); + RetVal = NULL; + goto error; } /* The end of the compressed data has been reached, so set the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 14:29:57 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 14 May 2011 14:29:57 +0200 Subject: [Python-checkins] cpython (2.7): Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail Message-ID: http://hg.python.org/cpython/rev/24543f7a87ce changeset: 70102:24543f7a87ce branch: 2.7 parent: 70092:4081f326e46c user: Nadeem Vawda date: Sat May 14 14:29:07 2011 +0200 summary: Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. files: Lib/test/test_zlib.py | 9 +++++++++ Misc/NEWS | 3 +++ Modules/zlibmodule.c | 19 ++++++++++++------- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -310,6 +310,15 @@ self.assertRaises(ValueError, dco.decompress, "", -1) self.assertEqual('', dco.unconsumed_tail) + def test_clear_unconsumed_tail(self): + # Issue #12050: calling decompress() without providing max_length + # should clear the unconsumed_tail attribute. + cdata = "x\x9cKLJ\x06\x00\x02M\x01" # "abc" + dco = zlib.decompressobj() + ddata = dco.decompress(cdata, 1) + ddata += dco.decompress(dco.unconsumed_tail) + self.assertEqual(dco.unconsumed_tail, "") + def test_flushes(self): # Test flush() with the various options, using all the # different levels in order to provide more variations. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,9 @@ Library ------- +- Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail + attribute when called without a max_length argument. + - Issue #12062: In the `io` module, fix a flushing bug when doing a certain type of I/O sequence on a file opened in read+write mode (namely: reading, seeking a bit forward, writing, then seeking before the previous write but diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -535,17 +535,22 @@ Py_END_ALLOW_THREADS } - /* Not all of the compressed data could be accommodated in the output buffer - of specified size. Return the unconsumed tail in an attribute.*/ if(max_length) { + /* Not all of the compressed data could be accommodated in a buffer of + the specified size. Return the unconsumed tail in an attribute. */ Py_DECREF(self->unconsumed_tail); self->unconsumed_tail = PyString_FromStringAndSize((char *)self->zst.next_in, self->zst.avail_in); - if(!self->unconsumed_tail) { - Py_DECREF(RetVal); - RetVal = NULL; - goto error; - } + } + else if (PyString_GET_SIZE(self->unconsumed_tail) > 0) { + /* All of the compressed data was consumed. Clear unconsumed_tail. */ + Py_DECREF(self->unconsumed_tail); + self->unconsumed_tail = PyString_FromStringAndSize("", 0); + } + if(!self->unconsumed_tail) { + Py_DECREF(RetVal); + RetVal = NULL; + goto error; } /* The end of the compressed data has been reached, so set the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 22:34:48 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 14 May 2011 22:34:48 +0200 Subject: [Python-checkins] cpython (3.1): Issue #8650: Backport 64-bit safety fixes for compress() and decompress(). Message-ID: http://hg.python.org/cpython/rev/850624632e9a changeset: 70103:850624632e9a branch: 3.1 parent: 70099:6a45567c7245 user: Nadeem Vawda date: Sat May 14 22:26:55 2011 +0200 summary: Issue #8650: Backport 64-bit safety fixes for compress() and decompress(). files: Lib/test/test_zlib.py | 11 +++++++++++ Modules/zlibmodule.c | 31 +++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -186,6 +186,17 @@ 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) + self.assertRaises(OverflowError, zlib.decompress, data) + finally: + data = None + class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): # Test compression object diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -116,13 +116,20 @@ { PyObject *ReturnVal = NULL; Py_buffer pinput; - Byte *input, *output; - int length, level=Z_DEFAULT_COMPRESSION, err; + Byte *input, *output = NULL; + 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; + + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error; + } input = pinput.buf; length = pinput.len; @@ -130,10 +137,9 @@ output = (Byte*)malloc(zst.avail_out); if (output == NULL) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); - return NULL; + goto error; } /* Past the point of no return. From here on out, we need to make sure @@ -196,10 +202,11 @@ static PyObject * PyZlib_decompress(PyObject *self, PyObject *args) { - PyObject *result_str; + PyObject *result_str = NULL; 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,6 +214,12 @@ if (!PyArg_ParseTuple(args, "y*|in:decompress", &pinput, &wsize, &r_strlen)) return NULL; + + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error; + } input = pinput.buf; length = pinput.len; @@ -216,10 +229,8 @@ zst.avail_in = length; zst.avail_out = r_strlen; - if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) + goto error; zst.zalloc = (alloc_func)NULL; zst.zfree = (free_func)Z_NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 22:34:49 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 14 May 2011 22:34:49 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Null merge (#8650): zlib.compress() and .decompress() are already 64-bit safe. Message-ID: http://hg.python.org/cpython/rev/99a3ce22c1ff changeset: 70104:99a3ce22c1ff branch: 3.2 parent: 70100:49c998a88777 parent: 70103:850624632e9a user: Nadeem Vawda date: Sat May 14 22:32:19 2011 +0200 summary: Null merge (#8650): zlib.compress() and .decompress() are already 64-bit safe. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 22:34:50 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 14 May 2011 22:34:50 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Null merge (#8650): zlib.compress() and .decompress() are already 64-bit safe. Message-ID: http://hg.python.org/cpython/rev/dea5fcdc9ecd changeset: 70105:dea5fcdc9ecd parent: 70101:088e5d705171 parent: 70104:99a3ce22c1ff user: Nadeem Vawda date: Sat May 14 22:33:07 2011 +0200 summary: Null merge (#8650): zlib.compress() and .decompress() are already 64-bit safe. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 22:59:10 2011 From: python-checkins at python.org (lukasz.langa) Date: Sat, 14 May 2011 22:59:10 +0200 Subject: [Python-checkins] cpython (3.1): pprint usage example rethought. Message-ID: http://hg.python.org/cpython/rev/ab16d8d4f75d changeset: 70106:ab16d8d4f75d branch: 3.1 parent: 70103:850624632e9a user: ?ukasz Langa date: Sat May 14 22:43:44 2011 +0200 summary: pprint usage example rethought. files: Doc/library/pprint.rst | 126 ++++++++++++++++++++++------ 1 files changed, 98 insertions(+), 28 deletions(-) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -188,36 +188,105 @@ .. _pprint-example: -pprint Example --------------- +Example +------- -This example demonstrates several uses of the :func:`pprint` function and its parameters. +To demonstrate several uses of the :func:`pprint` function and its parameters, +let's fetch information about a package from PyPI:: + >>> import json >>> import pprint - >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', - ... ('parrot', ('fresh fruit',)))))))) - >>> stuff = ['a' * 10, tup, ['a' * 30, 'b' * 30], ['c' * 20, 'd' * 20]] - >>> pprint.pprint(stuff) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, depth=3) - ['aaaaaaaaaa', - ('spam', ('eggs', (...))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, width=60) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', - ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] + >>> from urllib.request import urlopen + >>> with urlopen('http://pypi.python.org/pypi/configparser/json') as url: + ... http_info = url.info() + ... raw_data = url.read().decode(http_info.get_content_charset()) + >>> package_data = json.loads(raw_data) + >>> result = {'headers': http_info.items(), 'body': package_data} +In its basic form, :func:`pprint` shows the whole object:: + + >>> pprint.pprint(result) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': ['Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules'], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{'comment_text': '', + 'downloads': 47, + 'filename': 'configparser-3.2.0r3.tar.gz', + 'has_sig': False, + 'md5_digest': '8500fd87c61ac0de328fc996fce69b96', + 'packagetype': 'sdist', + 'python_version': 'source', + 'size': 32281, + 'upload_time': '2011-05-10T16:28:50', + 'url': 'http://pypi.python.org/packages/source/c/configparser/configparser-3.2.0r3.tar.gz'}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +The result can be limited to a certain *depth* (ellipsis is used for deeper +contents):: + + >>> pprint.pprint(result, depth=3) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': [...], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{...}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +Additionally, maximum *width* can be suggested. If a long object cannot be +split, the specified width will be exceeded:: + + >>> pprint.pprint(result['headers'], width=30) + [('Date', + 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', + 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', + 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', + 'chunked'), + ('Content-Type', + 'application/json; charset="UTF-8"')] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 22:59:10 2011 From: python-checkins at python.org (lukasz.langa) Date: Sat, 14 May 2011 22:59:10 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merged rethought pprint usage example from 3.1. Message-ID: http://hg.python.org/cpython/rev/e8038d1d5af3 changeset: 70107:e8038d1d5af3 branch: 3.2 parent: 70104:99a3ce22c1ff parent: 70106:ab16d8d4f75d user: ?ukasz Langa date: Sat May 14 22:49:10 2011 +0200 summary: Merged rethought pprint usage example from 3.1. files: Doc/library/pprint.rst | 127 ++++++++++++++++++++++------ 1 files changed, 98 insertions(+), 29 deletions(-) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -189,37 +189,105 @@ .. _pprint-example: -pprint Example --------------- +Example +------- -This example demonstrates several uses of the :func:`pprint` function and its -parameters. +To demonstrate several uses of the :func:`pprint` function and its parameters, +let's fetch information about a package from PyPI:: + >>> import json >>> import pprint - >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', - ... ('parrot', ('fresh fruit',)))))))) - >>> stuff = ['a' * 10, tup, ['a' * 30, 'b' * 30], ['c' * 20, 'd' * 20]] - >>> pprint.pprint(stuff) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, depth=3) - ['aaaaaaaaaa', - ('spam', ('eggs', (...))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, width=60) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', - ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] + >>> from urllib.request import urlopen + >>> with urlopen('http://pypi.python.org/pypi/configparser/json') as url: + ... http_info = url.info() + ... raw_data = url.read().decode(http_info.get_content_charset()) + >>> package_data = json.loads(raw_data) + >>> result = {'headers': http_info.items(), 'body': package_data} +In its basic form, :func:`pprint` shows the whole object:: + + >>> pprint.pprint(result) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': ['Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules'], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{'comment_text': '', + 'downloads': 47, + 'filename': 'configparser-3.2.0r3.tar.gz', + 'has_sig': False, + 'md5_digest': '8500fd87c61ac0de328fc996fce69b96', + 'packagetype': 'sdist', + 'python_version': 'source', + 'size': 32281, + 'upload_time': '2011-05-10T16:28:50', + 'url': 'http://pypi.python.org/packages/source/c/configparser/configparser-3.2.0r3.tar.gz'}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +The result can be limited to a certain *depth* (ellipsis is used for deeper +contents):: + + >>> pprint.pprint(result, depth=3) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': [...], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{...}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +Additionally, maximum *width* can be suggested. If a long object cannot be +split, the specified width will be exceeded:: + + >>> pprint.pprint(result['headers'], width=30) + [('Date', + 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', + 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', + 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', + 'chunked'), + ('Content-Type', + 'application/json; charset="UTF-8"')] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 22:59:12 2011 From: python-checkins at python.org (lukasz.langa) Date: Sat, 14 May 2011 22:59:12 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merged rethought pprint example from 3.2. Message-ID: http://hg.python.org/cpython/rev/1893294872cd changeset: 70108:1893294872cd parent: 70105:dea5fcdc9ecd parent: 70107:e8038d1d5af3 user: ?ukasz Langa date: Sat May 14 22:58:17 2011 +0200 summary: Merged rethought pprint example from 3.2. files: Doc/library/pprint.rst | 127 ++++++++++++++++++++++------ 1 files changed, 98 insertions(+), 29 deletions(-) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -189,37 +189,105 @@ .. _pprint-example: -pprint Example --------------- +Example +------- -This example demonstrates several uses of the :func:`pprint` function and its -parameters. +To demonstrate several uses of the :func:`pprint` function and its parameters, +let's fetch information about a package from PyPI:: + >>> import json >>> import pprint - >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', - ... ('parrot', ('fresh fruit',)))))))) - >>> stuff = ['a' * 10, tup, ['a' * 30, 'b' * 30], ['c' * 20, 'd' * 20]] - >>> pprint.pprint(stuff) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, depth=3) - ['aaaaaaaaaa', - ('spam', ('eggs', (...))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, width=60) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', - ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] + >>> from urllib.request import urlopen + >>> with urlopen('http://pypi.python.org/pypi/configparser/json') as url: + ... http_info = url.info() + ... raw_data = url.read().decode(http_info.get_content_charset()) + >>> package_data = json.loads(raw_data) + >>> result = {'headers': http_info.items(), 'body': package_data} +In its basic form, :func:`pprint` shows the whole object:: + + >>> pprint.pprint(result) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': ['Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules'], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{'comment_text': '', + 'downloads': 47, + 'filename': 'configparser-3.2.0r3.tar.gz', + 'has_sig': False, + 'md5_digest': '8500fd87c61ac0de328fc996fce69b96', + 'packagetype': 'sdist', + 'python_version': 'source', + 'size': 32281, + 'upload_time': '2011-05-10T16:28:50', + 'url': 'http://pypi.python.org/packages/source/c/configparser/configparser-3.2.0r3.tar.gz'}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +The result can be limited to a certain *depth* (ellipsis is used for deeper +contents):: + + >>> pprint.pprint(result, depth=3) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': [...], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{...}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +Additionally, maximum *width* can be suggested. If a long object cannot be +split, the specified width will be exceeded:: + + >>> pprint.pprint(result['headers'], width=30) + [('Date', + 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', + 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', + 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', + 'chunked'), + ('Content-Type', + 'application/json; charset="UTF-8"')] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 23:19:16 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 14 May 2011 23:19:16 +0200 Subject: [Python-checkins] cpython (3.2): Fix memory leaks in zlib.compress() and .decompress(). Message-ID: http://hg.python.org/cpython/rev/612781911887 changeset: 70109:612781911887 branch: 3.2 parent: 70107:e8038d1d5af3 user: Nadeem Vawda date: Sat May 14 23:07:36 2011 +0200 summary: Fix memory leaks in zlib.compress() and .decompress(). Also, make sure that test_zlib tests decompress() for overly-large inputs. files: Lib/test/test_zlib.py | 1 + Modules/zlibmodule.c | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -193,6 +193,7 @@ data = b'x' * size try: self.assertRaises(OverflowError, zlib.compress, data, 1) + self.assertRaises(OverflowError, zlib.decompress, data) finally: data = None diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -116,7 +116,7 @@ { PyObject *ReturnVal = NULL; Py_buffer pinput; - Byte *input, *output; + Byte *input, *output = NULL; unsigned int length; int level=Z_DEFAULT_COMPRESSION, err; z_stream zst; @@ -127,20 +127,19 @@ if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } + input = pinput.buf; length = pinput.len; - input = pinput.buf; zst.avail_out = length + length/1000 + 12 + 1; output = (Byte*)malloc(zst.avail_out); if (output == NULL) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); - return NULL; + goto error; } /* Past the point of no return. From here on out, we need to make sure @@ -203,7 +202,7 @@ static PyObject * PyZlib_decompress(PyObject *self, PyObject *args) { - PyObject *result_str; + PyObject *result_str = NULL; Py_buffer pinput; Byte *input; unsigned int length; @@ -218,11 +217,11 @@ if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } + input = pinput.buf; length = pinput.len; - input = pinput.buf; if (r_strlen <= 0) r_strlen = 1; @@ -230,10 +229,8 @@ zst.avail_in = length; zst.avail_out = r_strlen; - if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) + goto error; zst.zalloc = (alloc_func)NULL; zst.zfree = (free_func)Z_NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 14 23:19:17 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sat, 14 May 2011 23:19:17 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge fix for memory leaks in zlib.compress() and .decompress(). Message-ID: http://hg.python.org/cpython/rev/9090970d5e17 changeset: 70110:9090970d5e17 parent: 70108:1893294872cd parent: 70109:612781911887 user: Nadeem Vawda date: Sat May 14 23:18:07 2011 +0200 summary: Merge fix for memory leaks in zlib.compress() and .decompress(). Also, make sure that test_zlib tests decompress() for overly-large inputs. files: Lib/test/test_zlib.py | 1 + Modules/zlibmodule.c | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -193,6 +193,7 @@ data = b'x' * size try: self.assertRaises(OverflowError, zlib.compress, data, 1) + self.assertRaises(OverflowError, zlib.decompress, data) finally: data = None diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -116,7 +116,7 @@ { PyObject *ReturnVal = NULL; Py_buffer pinput; - Byte *input, *output; + Byte *input, *output = NULL; unsigned int length; int level=Z_DEFAULT_COMPRESSION, err; z_stream zst; @@ -127,20 +127,19 @@ if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } + input = pinput.buf; length = pinput.len; - input = pinput.buf; zst.avail_out = length + length/1000 + 12 + 1; output = (Byte*)malloc(zst.avail_out); if (output == NULL) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); - return NULL; + goto error; } /* Past the point of no return. From here on out, we need to make sure @@ -203,7 +202,7 @@ static PyObject * PyZlib_decompress(PyObject *self, PyObject *args) { - PyObject *result_str; + PyObject *result_str = NULL; Py_buffer pinput; Byte *input; unsigned int length; @@ -218,11 +217,11 @@ if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } + input = pinput.buf; length = pinput.len; - input = pinput.buf; if (r_strlen <= 0) r_strlen = 1; @@ -230,10 +229,8 @@ zst.avail_in = length; zst.avail_out = r_strlen; - if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) + goto error; zst.zalloc = (alloc_func)NULL; zst.zfree = (free_func)Z_NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:07:11 2011 From: python-checkins at python.org (kurt.kaiser) Date: Sun, 15 May 2011 00:07:11 +0200 Subject: [Python-checkins] cpython (3.1): Issue #6378: Further adjust idle.bat to start associated Python Message-ID: http://hg.python.org/cpython/rev/536ec6206584 changeset: 70111:536ec6206584 branch: 3.1 parent: 70103:850624632e9a user: Kurt B. Kaiser date: Sat May 14 17:20:09 2011 -0400 summary: Issue #6378: Further adjust idle.bat to start associated Python files: Lib/idlelib/NEWS.txt | 4 +++- Lib/idlelib/idle.bat | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,8 @@ *Release date: XX-XXX-11* +- Issue #6378: Further adjust idle.bat to start associated Python + - Issue #11896: Save on Close failed despite selecting "Yes" in dialog. - Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. @@ -63,7 +65,7 @@ extract port from command line when warnings are present. - Tk 8.5 Text widget requires 'wordprocessor' tabstyle attr to handle - mixed space/tab properly. Issue 5120, patch by Guilherme Polo. + mixed space/tab properly. Issue 5129, patch by Guilherme Polo. - Issue #3549: On MacOS the preferences menu was not present diff --git a/Lib/idlelib/idle.bat b/Lib/idlelib/idle.bat --- a/Lib/idlelib/idle.bat +++ b/Lib/idlelib/idle.bat @@ -1,4 +1,4 @@ @echo off rem Start IDLE using the appropriate Python interpreter set CURRDIR=%~dp0 -start "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 +start "IDLE" "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:07:12 2011 From: python-checkins at python.org (kurt.kaiser) Date: Sun, 15 May 2011 00:07:12 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge from 3.1 Message-ID: http://hg.python.org/cpython/rev/cd55c6960d86 changeset: 70112:cd55c6960d86 branch: 3.2 parent: 70104:99a3ce22c1ff parent: 70111:536ec6206584 user: Kurt B. Kaiser date: Sat May 14 17:22:14 2011 -0400 summary: Merge from 3.1 Issue #6378: Further adjust idle.bat to start associated Python files: Lib/idlelib/NEWS.txt | 4 +++- Lib/idlelib/idle.bat | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,8 @@ *Release date: 15-May-11* +- Issue #6378: Further adjust idle.bat to start associated Python + - Issue #11896: Save on Close failed despite selecting "Yes" in dialog. - Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. @@ -63,7 +65,7 @@ extract port from command line when warnings are present. - Tk 8.5 Text widget requires 'wordprocessor' tabstyle attr to handle - mixed space/tab properly. Issue 5120, patch by Guilherme Polo. + mixed space/tab properly. Issue 5129, patch by Guilherme Polo. - Issue #3549: On MacOS the preferences menu was not present diff --git a/Lib/idlelib/idle.bat b/Lib/idlelib/idle.bat --- a/Lib/idlelib/idle.bat +++ b/Lib/idlelib/idle.bat @@ -1,4 +1,4 @@ @echo off rem Start IDLE using the appropriate Python interpreter set CURRDIR=%~dp0 -start "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 +start "IDLE" "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:07:12 2011 From: python-checkins at python.org (kurt.kaiser) Date: Sun, 15 May 2011 00:07:12 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.1): Merge heads Message-ID: http://hg.python.org/cpython/rev/288c26e36d02 changeset: 70113:288c26e36d02 branch: 3.1 parent: 70111:536ec6206584 parent: 70106:ab16d8d4f75d user: Kurt B. Kaiser date: Sat May 14 17:30:58 2011 -0400 summary: Merge heads files: Doc/library/pprint.rst | 126 ++++++++++++++++++++++------ 1 files changed, 98 insertions(+), 28 deletions(-) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -188,36 +188,105 @@ .. _pprint-example: -pprint Example --------------- +Example +------- -This example demonstrates several uses of the :func:`pprint` function and its parameters. +To demonstrate several uses of the :func:`pprint` function and its parameters, +let's fetch information about a package from PyPI:: + >>> import json >>> import pprint - >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', - ... ('parrot', ('fresh fruit',)))))))) - >>> stuff = ['a' * 10, tup, ['a' * 30, 'b' * 30], ['c' * 20, 'd' * 20]] - >>> pprint.pprint(stuff) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, depth=3) - ['aaaaaaaaaa', - ('spam', ('eggs', (...))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, width=60) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', - ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] + >>> from urllib.request import urlopen + >>> with urlopen('http://pypi.python.org/pypi/configparser/json') as url: + ... http_info = url.info() + ... raw_data = url.read().decode(http_info.get_content_charset()) + >>> package_data = json.loads(raw_data) + >>> result = {'headers': http_info.items(), 'body': package_data} +In its basic form, :func:`pprint` shows the whole object:: + + >>> pprint.pprint(result) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': ['Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules'], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{'comment_text': '', + 'downloads': 47, + 'filename': 'configparser-3.2.0r3.tar.gz', + 'has_sig': False, + 'md5_digest': '8500fd87c61ac0de328fc996fce69b96', + 'packagetype': 'sdist', + 'python_version': 'source', + 'size': 32281, + 'upload_time': '2011-05-10T16:28:50', + 'url': 'http://pypi.python.org/packages/source/c/configparser/configparser-3.2.0r3.tar.gz'}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +The result can be limited to a certain *depth* (ellipsis is used for deeper +contents):: + + >>> pprint.pprint(result, depth=3) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': [...], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{...}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +Additionally, maximum *width* can be suggested. If a long object cannot be +split, the specified width will be exceeded:: + + >>> pprint.pprint(result['headers'], width=30) + [('Date', + 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', + 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', + 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', + 'chunked'), + ('Content-Type', + 'application/json; charset="UTF-8"')] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:07:13 2011 From: python-checkins at python.org (kurt.kaiser) Date: Sun, 15 May 2011 00:07:13 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): Merge heads Message-ID: http://hg.python.org/cpython/rev/c940b17a7020 changeset: 70114:c940b17a7020 branch: 3.2 parent: 70112:cd55c6960d86 parent: 70109:612781911887 user: Kurt B. Kaiser date: Sat May 14 17:31:54 2011 -0400 summary: Merge heads files: Doc/library/pprint.rst | 127 ++++++++++++++++++++++------ Lib/test/test_zlib.py | 1 + Modules/zlibmodule.c | 25 ++--- 3 files changed, 110 insertions(+), 43 deletions(-) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -189,37 +189,105 @@ .. _pprint-example: -pprint Example --------------- +Example +------- -This example demonstrates several uses of the :func:`pprint` function and its -parameters. +To demonstrate several uses of the :func:`pprint` function and its parameters, +let's fetch information about a package from PyPI:: + >>> import json >>> import pprint - >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', - ... ('parrot', ('fresh fruit',)))))))) - >>> stuff = ['a' * 10, tup, ['a' * 30, 'b' * 30], ['c' * 20, 'd' * 20]] - >>> pprint.pprint(stuff) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, depth=3) - ['aaaaaaaaaa', - ('spam', ('eggs', (...))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, width=60) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', - ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] + >>> from urllib.request import urlopen + >>> with urlopen('http://pypi.python.org/pypi/configparser/json') as url: + ... http_info = url.info() + ... raw_data = url.read().decode(http_info.get_content_charset()) + >>> package_data = json.loads(raw_data) + >>> result = {'headers': http_info.items(), 'body': package_data} +In its basic form, :func:`pprint` shows the whole object:: + + >>> pprint.pprint(result) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': ['Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules'], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{'comment_text': '', + 'downloads': 47, + 'filename': 'configparser-3.2.0r3.tar.gz', + 'has_sig': False, + 'md5_digest': '8500fd87c61ac0de328fc996fce69b96', + 'packagetype': 'sdist', + 'python_version': 'source', + 'size': 32281, + 'upload_time': '2011-05-10T16:28:50', + 'url': 'http://pypi.python.org/packages/source/c/configparser/configparser-3.2.0r3.tar.gz'}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +The result can be limited to a certain *depth* (ellipsis is used for deeper +contents):: + + >>> pprint.pprint(result, depth=3) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': [...], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{...}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +Additionally, maximum *width* can be suggested. If a long object cannot be +split, the specified width will be exceeded:: + + >>> pprint.pprint(result['headers'], width=30) + [('Date', + 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', + 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', + 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', + 'chunked'), + ('Content-Type', + 'application/json; charset="UTF-8"')] diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -193,6 +193,7 @@ data = b'x' * size try: self.assertRaises(OverflowError, zlib.compress, data, 1) + self.assertRaises(OverflowError, zlib.decompress, data) finally: data = None diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -116,7 +116,7 @@ { PyObject *ReturnVal = NULL; Py_buffer pinput; - Byte *input, *output; + Byte *input, *output = NULL; unsigned int length; int level=Z_DEFAULT_COMPRESSION, err; z_stream zst; @@ -127,20 +127,19 @@ if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } + input = pinput.buf; length = pinput.len; - input = pinput.buf; zst.avail_out = length + length/1000 + 12 + 1; output = (Byte*)malloc(zst.avail_out); if (output == NULL) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); - return NULL; + goto error; } /* Past the point of no return. From here on out, we need to make sure @@ -203,7 +202,7 @@ static PyObject * PyZlib_decompress(PyObject *self, PyObject *args) { - PyObject *result_str; + PyObject *result_str = NULL; Py_buffer pinput; Byte *input; unsigned int length; @@ -218,11 +217,11 @@ if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } + input = pinput.buf; length = pinput.len; - input = pinput.buf; if (r_strlen <= 0) r_strlen = 1; @@ -230,10 +229,8 @@ zst.avail_in = length; zst.avail_out = r_strlen; - if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) + goto error; zst.zalloc = (alloc_func)NULL; zst.zfree = (free_func)Z_NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:07:14 2011 From: python-checkins at python.org (kurt.kaiser) Date: Sun, 15 May 2011 00:07:14 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/ec3e73a25d84 changeset: 70115:ec3e73a25d84 parent: 70110:9090970d5e17 parent: 70114:c940b17a7020 user: Kurt B. Kaiser date: Sat May 14 17:46:44 2011 -0400 summary: Merge from 3.2 Issue #6378: Further adjust idle.bat to start associated Python files: Lib/idlelib/NEWS.txt | 4 +++- Lib/idlelib/idle.bat | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,8 @@ *Release date: 15-May-11* +- Issue #6378: Further adjust idle.bat to start associated Python + - Issue #11896: Save on Close failed despite selecting "Yes" in dialog. - Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. @@ -63,7 +65,7 @@ extract port from command line when warnings are present. - Tk 8.5 Text widget requires 'wordprocessor' tabstyle attr to handle - mixed space/tab properly. Issue 5120, patch by Guilherme Polo. + mixed space/tab properly. Issue 5129, patch by Guilherme Polo. - Issue #3549: On MacOS the preferences menu was not present diff --git a/Lib/idlelib/idle.bat b/Lib/idlelib/idle.bat --- a/Lib/idlelib/idle.bat +++ b/Lib/idlelib/idle.bat @@ -1,4 +1,4 @@ @echo off rem Start IDLE using the appropriate Python interpreter set CURRDIR=%~dp0 -start "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 +start "IDLE" "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:07:15 2011 From: python-checkins at python.org (kurt.kaiser) Date: Sun, 15 May 2011 00:07:15 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge heads (!) Message-ID: http://hg.python.org/cpython/rev/10d1030a60c2 changeset: 70116:10d1030a60c2 branch: 3.2 parent: 70114:c940b17a7020 parent: 70113:288c26e36d02 user: Kurt B. Kaiser date: Sat May 14 17:50:02 2011 -0400 summary: Merge heads (!) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:07:16 2011 From: python-checkins at python.org (kurt.kaiser) Date: Sun, 15 May 2011 00:07:16 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge heads(!) Message-ID: http://hg.python.org/cpython/rev/7fb34d30bd59 changeset: 70117:7fb34d30bd59 parent: 70115:ec3e73a25d84 parent: 70116:10d1030a60c2 user: Kurt B. Kaiser date: Sat May 14 17:51:10 2011 -0400 summary: Merge heads(!) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:24:54 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sun, 15 May 2011 00:24:54 +0200 Subject: [Python-checkins] cpython (3.1): Issue #8650: Make zlib.[de]compressobj().[de]compress() 64-bit clean. Message-ID: http://hg.python.org/cpython/rev/0b5211d19a14 changeset: 70118:0b5211d19a14 branch: 3.1 parent: 70113:288c26e36d02 user: Nadeem Vawda date: Sun May 15 00:19:50 2011 +0200 summary: Issue #8650: Make zlib.[de]compressobj().[de]compress() 64-bit clean. Raise an OverflowError if the input data is too large, instead of silently truncating the input and returning an incorrect result. files: Lib/test/test_zlib.py | 11 +++++++++ Misc/NEWS | 5 ++++ Modules/zlibmodule.c | 37 +++++++++++++++++++----------- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -523,6 +523,17 @@ decompress = lambda s: d.decompress(s) + d.flush() self.check_big_decompress_buffer(size, 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) + self.assertRaises(OverflowError, zlib.decompress, data) + finally: + data = None + def genblock(seed, length, step=1024, generator=random): """length-byte stream of random data from a seed (in step-byte blocks).""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,11 @@ Library ------- +- Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and + their incremental counterparts now raise OverflowError if given an input + larger than 4GB, instead of silently truncating the input and returning + an incorrect result. + - Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -420,22 +420,26 @@ static PyObject * PyZlib_objcompress(compobject *self, PyObject *args) { - int err, inplen; + int err; + unsigned int inplen; Py_ssize_t length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; if (!PyArg_ParseTuple(args, "y*:compress", &pinput)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -484,6 +488,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } @@ -502,9 +507,10 @@ static PyObject * PyZlib_objdecompress(compobject *self, PyObject *args) { - int err, inplen, max_length = 0; + int err, max_length = 0; + unsigned int inplen; Py_ssize_t old_length, length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; @@ -512,22 +518,24 @@ if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput, &max_length)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; if (max_length < 0) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_ValueError, "max_length must be greater than zero"); - return NULL; + goto error_outer; } /* limit amount of data allocated to max_length */ if (max_length && length > max_length) length = max_length; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -621,6 +629,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:24:55 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sun, 15 May 2011 00:24:55 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: #8650: Make zlib.[de]compressobj().[de]compress() 64-bit clean. Message-ID: http://hg.python.org/cpython/rev/3ff862d05d18 changeset: 70119:3ff862d05d18 branch: 3.2 parent: 70116:10d1030a60c2 parent: 70118:0b5211d19a14 user: Nadeem Vawda date: Sun May 15 00:20:52 2011 +0200 summary: Merge: #8650: Make zlib.[de]compressobj().[de]compress() 64-bit clean. Raise an OverflowError if the input data is too large, instead of silently truncating the input and returning an incorrect result. files: Lib/test/test_zlib.py | 11 +++++++++ Misc/NEWS | 5 ++++ Modules/zlibmodule.c | 37 +++++++++++++++++++----------- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -523,6 +523,17 @@ decompress = lambda s: d.decompress(s) + d.flush() self.check_big_decompress_buffer(size, 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) + self.assertRaises(OverflowError, zlib.decompress, data) + finally: + data = None + def genblock(seed, length, step=1024, generator=random): """length-byte stream of random data from a seed (in step-byte blocks).""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,11 @@ Library ------- +- Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and + their incremental counterparts now raise OverflowError if given an input + larger than 4GB, instead of silently truncating the input and returning + an incorrect result. + - Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -420,22 +420,26 @@ static PyObject * PyZlib_objcompress(compobject *self, PyObject *args) { - int err, inplen; + int err; + unsigned int inplen; Py_ssize_t length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; if (!PyArg_ParseTuple(args, "y*:compress", &pinput)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -484,6 +488,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } @@ -502,9 +507,10 @@ static PyObject * PyZlib_objdecompress(compobject *self, PyObject *args) { - int err, inplen, max_length = 0; + int err, max_length = 0; + unsigned int inplen; Py_ssize_t old_length, length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; @@ -512,22 +518,24 @@ if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput, &max_length)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; if (max_length < 0) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_ValueError, "max_length must be greater than zero"); - return NULL; + goto error_outer; } /* limit amount of data allocated to max_length */ if (max_length && length > max_length) length = max_length; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -621,6 +629,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:24:56 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sun, 15 May 2011 00:24:56 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: #8650: Make zlib.[de]compressobj().[de]compress() 64-bit clean. Message-ID: http://hg.python.org/cpython/rev/f86a22b6ab58 changeset: 70120:f86a22b6ab58 parent: 70117:7fb34d30bd59 parent: 70119:3ff862d05d18 user: Nadeem Vawda date: Sun May 15 00:23:40 2011 +0200 summary: Merge: #8650: Make zlib.[de]compressobj().[de]compress() 64-bit clean. Raise an OverflowError if the input data is too large, instead of silently truncating the input and returning an incorrect result. files: Lib/test/test_zlib.py | 11 +++++++++ Misc/NEWS | 5 ++++ Modules/zlibmodule.c | 37 +++++++++++++++++++----------- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -523,6 +523,17 @@ decompress = lambda s: d.decompress(s) + d.flush() self.check_big_decompress_buffer(size, 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) + self.assertRaises(OverflowError, zlib.decompress, data) + finally: + data = None + def genblock(seed, length, step=1024, generator=random): """length-byte stream of random data from a seed (in step-byte blocks).""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -147,6 +147,11 @@ Library ------- +- Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and + their incremental counterparts now raise OverflowError if given an input + larger than 4GB, instead of silently truncating the input and returning + an incorrect result. + - Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -420,22 +420,26 @@ static PyObject * PyZlib_objcompress(compobject *self, PyObject *args) { - int err, inplen; + int err; + unsigned int inplen; Py_ssize_t length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; if (!PyArg_ParseTuple(args, "y*:compress", &pinput)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -484,6 +488,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } @@ -502,9 +507,10 @@ static PyObject * PyZlib_objdecompress(compobject *self, PyObject *args) { - int err, inplen, max_length = 0; + int err, max_length = 0; + unsigned int inplen; Py_ssize_t old_length, length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; @@ -512,22 +518,24 @@ if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput, &max_length)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; if (max_length < 0) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_ValueError, "max_length must be greater than zero"); - return NULL; + goto error_outer; } /* limit amount of data allocated to max_length */ if (max_length && length > max_length) length = max_length; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -621,6 +629,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:36:20 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 00:36:20 +0200 Subject: [Python-checkins] cpython (2.7): Fixes Issue #12059: Properly handle missing hash functions even when Message-ID: http://hg.python.org/cpython/rev/572fbd9ca28f changeset: 70121:572fbd9ca28f branch: 2.7 parent: 70102:24543f7a87ce user: Gregory P. Smith date: Sat May 14 15:07:53 2011 -0700 summary: Fixes Issue #12059: Properly handle missing hash functions even when the expected builtin modules are not present. This includes a unittest for __get_builtin_constructor() in the face of such an error. files: Lib/hashlib.py | 43 ++++++++++++++------------- Lib/test/test_hashlib.py | 18 +++++++++++ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -64,26 +64,29 @@ def __get_builtin_constructor(name): - if name in ('SHA1', 'sha1'): - import _sha - return _sha.new - elif name in ('MD5', 'md5'): - import _md5 - return _md5.new - elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): - import _sha256 - bs = name[3:] - if bs == '256': - return _sha256.sha256 - elif bs == '224': - return _sha256.sha224 - elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): - import _sha512 - bs = name[3:] - if bs == '512': - return _sha512.sha512 - elif bs == '384': - return _sha512.sha384 + try: + if name in ('SHA1', 'sha1'): + import _sha + return _sha.new + elif name in ('MD5', 'md5'): + import _md5 + return _md5.new + elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): + import _sha256 + bs = name[3:] + if bs == '256': + return _sha256.sha256 + elif bs == '224': + return _sha256.sha224 + elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): + import _sha512 + bs = name[3:] + if bs == '512': + return _sha512.sha512 + elif bs == '384': + return _sha512.sha384 + except ImportError: + pass # no extension module, this hash is unsupported. raise ValueError('unsupported hash type %s' % name) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -115,6 +115,24 @@ else: self.assertTrue(0 == "hashlib didn't reject bogus hash name") + def test_get_builtin_constructor(self): + get_builtin_constructor = hashlib.__dict__[ + '__get_builtin_constructor'] + self.assertRaises(ValueError, get_builtin_constructor, 'test') + try: + import _md5 + except ImportError: + pass + # This forces an ImportError for "import _md5" statements + sys.modules['_md5'] = None + try: + self.assertRaises(ValueError, get_builtin_constructor, 'md5') + finally: + if '_md5' in locals(): + sys.modules['_md5'] = _md5 + else: + del sys.modules['_md5'] + def test_hexdigest(self): for name in self.supported_hash_names: h = hashlib.new(name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:36:21 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 00:36:21 +0200 Subject: [Python-checkins] cpython (3.2): Fixes Issue #12059: Properly handle missing hash functions even when Message-ID: http://hg.python.org/cpython/rev/ad9249f35914 changeset: 70122:ad9249f35914 branch: 3.2 parent: 70078:b340d1577dc5 user: Gregory P. Smith date: Sat May 14 15:15:49 2011 -0700 summary: Fixes Issue #12059: Properly handle missing hash functions even when the expected builtin modules are not present. This includes a unittest for __get_builtin_constructor() in the face of such an error. files: Lib/hashlib.py | 43 ++++++++++++++------------- Lib/test/test_hashlib.py | 18 +++++++++++ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -64,26 +64,29 @@ def __get_builtin_constructor(name): - if name in ('SHA1', 'sha1'): - import _sha1 - return _sha1.sha1 - elif name in ('MD5', 'md5'): - import _md5 - return _md5.md5 - elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): - import _sha256 - bs = name[3:] - if bs == '256': - return _sha256.sha256 - elif bs == '224': - return _sha256.sha224 - elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): - import _sha512 - bs = name[3:] - if bs == '512': - return _sha512.sha512 - elif bs == '384': - return _sha512.sha384 + try: + if name in ('SHA1', 'sha1'): + import _sha1 + return _sha1.sha1 + elif name in ('MD5', 'md5'): + import _md5 + return _md5.md5 + elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): + import _sha256 + bs = name[3:] + if bs == '256': + return _sha256.sha256 + elif bs == '224': + return _sha256.sha224 + elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): + import _sha512 + bs = name[3:] + if bs == '512': + return _sha512.sha512 + elif bs == '384': + return _sha512.sha384 + except ImportError: + pass # no extension module, this hash is unsupported. raise ValueError('unsupported hash type %s' % name) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -118,6 +118,24 @@ else: self.assertTrue(0 == "hashlib didn't reject bogus hash name") + def test_get_builtin_constructor(self): + get_builtin_constructor = hashlib.__dict__[ + '__get_builtin_constructor'] + self.assertRaises(ValueError, get_builtin_constructor, 'test') + try: + import _md5 + except ImportError: + pass + # This forces an ImportError for "import _md5" statements + sys.modules['_md5'] = None + try: + self.assertRaises(ValueError, get_builtin_constructor, 'md5') + finally: + if '_md5' in locals(): + sys.modules['_md5'] = _md5 + else: + del sys.modules['_md5'] + def test_hexdigest(self): for name in self.supported_hash_names: h = hashlib.new(name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:36:22 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 00:36:22 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): merge heads. Message-ID: http://hg.python.org/cpython/rev/5066cda37414 changeset: 70123:5066cda37414 branch: 3.2 parent: 70122:ad9249f35914 parent: 70116:10d1030a60c2 user: Gregory P. Smith date: Sat May 14 15:26:35 2011 -0700 summary: merge heads. files: Doc/howto/sockets.rst | 33 +- Doc/library/pprint.rst | 127 +++++++-- Lib/idlelib/NEWS.txt | 4 +- Lib/idlelib/idle.bat | 2 +- Lib/json/decoder.py | 4 +- Lib/test/json_tests/__init__.py | 46 +++- Lib/test/json_tests/test_decode.py | 57 +-- Lib/test/json_tests/test_default.py | 13 +- Lib/test/json_tests/test_dump.py | 17 +- Lib/test/json_tests/test_encode_basestring_ascii.py | 30 +- Lib/test/json_tests/test_fail.py | 18 +- Lib/test/json_tests/test_float.py | 17 +- Lib/test/json_tests/test_indent.py | 28 +- Lib/test/json_tests/test_pass1.py | 17 +- Lib/test/json_tests/test_pass2.py | 16 +- Lib/test/json_tests/test_pass3.py | 16 +- Lib/test/json_tests/test_recursion.py | 60 ++-- Lib/test/json_tests/test_scanstring.py | 29 +- Lib/test/json_tests/test_separators.py | 18 +- Lib/test/json_tests/test_speedups.py | 29 +- Lib/test/json_tests/test_unicode.py | 52 ++- Lib/test/support.py | 38 +- Lib/test/test_zlib.py | 10 + Misc/NEWS | 5 + Modules/zlibmodule.c | 44 +- 25 files changed, 425 insertions(+), 305 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -43,10 +43,10 @@ History ------- -Of the various forms of IPC (*Inter Process Communication*), sockets are by far -the most popular. On any given platform, there are likely to be other forms of -IPC that are faster, but for cross-platform communication, sockets are about the -only game in town. +Of the various forms of :abbr:`IPC (Inter Process Communication)`, +sockets are by far the most popular. On any given platform, there are +likely to be other forms of IPC that are faster, but for +cross-platform communication, sockets are about the only game in town. They were invented in Berkeley as part of the BSD flavor of Unix. They spread like wildfire with the Internet. With good reason --- the combination of sockets @@ -66,13 +66,14 @@ # - the normal http port s.connect(("www.mcmillan-inc.com", 80)) -When the ``connect`` completes, the socket ``s`` can now be used to send in a -request for the text of this page. The same socket will read the reply, and then -be destroyed. That's right - destroyed. Client sockets are normally only used -for one exchange (or a small set of sequential exchanges). +When the ``connect`` completes, the socket ``s`` can be used to send +in a request for the text of the page. The same socket will read the +reply, and then be destroyed. That's right, destroyed. Client sockets +are normally only used for one exchange (or a small set of sequential +exchanges). What happens in the web server is a bit more complex. First, the web server -creates a "server socket". :: +creates a "server socket":: #create an INET, STREAMing socket serversocket = socket.socket( @@ -96,7 +97,7 @@ queue up as many as 5 connect requests (the normal max) before refusing outside connections. If the rest of the code is written properly, that should be plenty. -OK, now we have a "server" socket, listening on port 80. Now we enter the +Now that we have a "server" socket, listening on port 80, we can enter the mainloop of the web server:: while True: @@ -145,7 +146,7 @@ Now there are two sets of verbs to use for communication. You can use ``send`` and ``recv``, or you can transform your client socket into a file-like beast and -use ``read`` and ``write``. The latter is the way Java presents their sockets. +use ``read`` and ``write``. The latter is the way Java presents its sockets. I'm not going to talk about it here, except to warn you that you need to use ``flush`` on sockets. These are buffered "files", and a common mistake is to ``write`` something, and then ``read`` for a reply. Without a ``flush`` in @@ -166,11 +167,11 @@ about that some on the next page. A protocol like HTTP uses a socket for only one transfer. The client sends a -request, the reads a reply. That's it. The socket is discarded. This means that +request, then reads a reply. That's it. The socket is discarded. This means that a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize -that *there is no "EOT" (End of Transfer) on a socket.* I repeat: if a socket +that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* I repeat: if a socket ``send`` or ``recv`` returns after handling 0 bytes, the connection has been broken. If the connection has *not* been broken, you may wait on a ``recv`` forever, because the socket will *not* tell you that there's nothing more to @@ -336,7 +337,7 @@ In C, coding ``select`` is fairly complex. In Python, it's a piece of cake, but it's close enough to the C version that if you understand ``select`` in Python, -you'll have little trouble with it in C. :: +you'll have little trouble with it in C:: ready_to_read, ready_to_write, in_error = \ select.select( @@ -353,9 +354,9 @@ thing to do - give it a nice long timeout (say a minute) unless you have good reason to do otherwise. -In return, you will get three lists. They have the sockets that are actually +In return, you will get three lists. They contain the sockets that are actually readable, writable and in error. Each of these lists is a subset (possibly -empty) of the corresponding list you passed in. And if you put a socket in more +empty) of the corresponding list you passed in. If you put a socket in more than one input list, it will only be (at most) in one output list. If a socket is in the output readable list, you can be diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -189,37 +189,105 @@ .. _pprint-example: -pprint Example --------------- +Example +------- -This example demonstrates several uses of the :func:`pprint` function and its -parameters. +To demonstrate several uses of the :func:`pprint` function and its parameters, +let's fetch information about a package from PyPI:: + >>> import json >>> import pprint - >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', - ... ('parrot', ('fresh fruit',)))))))) - >>> stuff = ['a' * 10, tup, ['a' * 30, 'b' * 30], ['c' * 20, 'd' * 20]] - >>> pprint.pprint(stuff) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, depth=3) - ['aaaaaaaaaa', - ('spam', ('eggs', (...))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, width=60) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', - ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] + >>> from urllib.request import urlopen + >>> with urlopen('http://pypi.python.org/pypi/configparser/json') as url: + ... http_info = url.info() + ... raw_data = url.read().decode(http_info.get_content_charset()) + >>> package_data = json.loads(raw_data) + >>> result = {'headers': http_info.items(), 'body': package_data} +In its basic form, :func:`pprint` shows the whole object:: + + >>> pprint.pprint(result) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': ['Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules'], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{'comment_text': '', + 'downloads': 47, + 'filename': 'configparser-3.2.0r3.tar.gz', + 'has_sig': False, + 'md5_digest': '8500fd87c61ac0de328fc996fce69b96', + 'packagetype': 'sdist', + 'python_version': 'source', + 'size': 32281, + 'upload_time': '2011-05-10T16:28:50', + 'url': 'http://pypi.python.org/packages/source/c/configparser/configparser-3.2.0r3.tar.gz'}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +The result can be limited to a certain *depth* (ellipsis is used for deeper +contents):: + + >>> pprint.pprint(result, depth=3) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': [...], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{...}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +Additionally, maximum *width* can be suggested. If a long object cannot be +split, the specified width will be exceeded:: + + >>> pprint.pprint(result['headers'], width=30) + [('Date', + 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', + 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', + 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', + 'chunked'), + ('Content-Type', + 'application/json; charset="UTF-8"')] diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,8 @@ *Release date: 15-May-11* +- Issue #6378: Further adjust idle.bat to start associated Python + - Issue #11896: Save on Close failed despite selecting "Yes" in dialog. - Issue #1028: Ctrl-space binding to show completions was causing IDLE to exit. @@ -63,7 +65,7 @@ extract port from command line when warnings are present. - Tk 8.5 Text widget requires 'wordprocessor' tabstyle attr to handle - mixed space/tab properly. Issue 5120, patch by Guilherme Polo. + mixed space/tab properly. Issue 5129, patch by Guilherme Polo. - Issue #3549: On MacOS the preferences menu was not present diff --git a/Lib/idlelib/idle.bat b/Lib/idlelib/idle.bat --- a/Lib/idlelib/idle.bat +++ b/Lib/idlelib/idle.bat @@ -1,4 +1,4 @@ @echo off rem Start IDLE using the appropriate Python interpreter set CURRDIR=%~dp0 -start "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 +start "IDLE" "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -5,7 +5,7 @@ import sys import struct -from json.scanner import make_scanner +from json import scanner try: from _json import scanstring as c_scanstring except ImportError: @@ -340,7 +340,7 @@ self.parse_array = JSONArray self.parse_string = scanstring self.memo = {} - self.scan_once = make_scanner(self) + self.scan_once = scanner.make_scanner(self) def decode(self, s, _w=WHITESPACE.match): diff --git a/Lib/test/json_tests/__init__.py b/Lib/test/json_tests/__init__.py --- a/Lib/test/json_tests/__init__.py +++ b/Lib/test/json_tests/__init__.py @@ -1,7 +1,46 @@ import os import sys +import json +import doctest import unittest -import doctest + +from test import support + +# import json with and without accelerations +cjson = support.import_fresh_module('json', fresh=['_json']) +pyjson = support.import_fresh_module('json', blocked=['_json']) + +# create two base classes that will be used by the other tests +class PyTest(unittest.TestCase): + json = pyjson + loads = staticmethod(pyjson.loads) + dumps = staticmethod(pyjson.dumps) + + at unittest.skipUnless(cjson, 'requires _json') +class CTest(unittest.TestCase): + if cjson is not None: + json = cjson + loads = staticmethod(cjson.loads) + dumps = staticmethod(cjson.dumps) + +# test PyTest and CTest checking if the functions come from the right module +class TestPyTest(PyTest): + def test_pyjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, + 'json.scanner') + self.assertEqual(self.json.decoder.scanstring.__module__, + 'json.decoder') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + 'json.encoder') + +class TestCTest(CTest): + def test_cjson(self): + self.assertEqual(self.json.scanner.make_scanner.__module__, '_json') + self.assertEqual(self.json.decoder.scanstring.__module__, '_json') + self.assertEqual(self.json.encoder.c_make_encoder.__module__, '_json') + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + '_json') + here = os.path.dirname(__file__) @@ -17,12 +56,11 @@ return suite def additional_tests(): - import json - import json.encoder - import json.decoder suite = unittest.TestSuite() for mod in (json, json.encoder, json.decoder): suite.addTest(doctest.DocTestSuite(mod)) + suite.addTest(TestPyTest('test_pyjson')) + suite.addTest(TestCTest('test_cjson')) return suite def main(): diff --git a/Lib/test/json_tests/test_decode.py b/Lib/test/json_tests/test_decode.py --- a/Lib/test/json_tests/test_decode.py +++ b/Lib/test/json_tests/test_decode.py @@ -1,55 +1,38 @@ import decimal -from unittest import TestCase from io import StringIO -from contextlib import contextmanager +from collections import OrderedDict +from test.json_tests import PyTest, CTest -import json -import json.decoder -import json.scanner -from collections import OrderedDict - - at contextmanager -def use_python_scanner(): - py_scanner = json.scanner.py_make_scanner - old_scanner = json.decoder.make_scanner - json.decoder.make_scanner = py_scanner - try: - yield - finally: - json.decoder.make_scanner = old_scanner - - -class TestDecode(TestCase): +class TestDecode: def test_decimal(self): - rval = json.loads('1.1', parse_float=decimal.Decimal) + rval = self.loads('1.1', parse_float=decimal.Decimal) self.assertTrue(isinstance(rval, decimal.Decimal)) self.assertEqual(rval, decimal.Decimal('1.1')) def test_float(self): - rval = json.loads('1', parse_int=float) + rval = self.loads('1', parse_int=float) self.assertTrue(isinstance(rval, float)) self.assertEqual(rval, 1.0) def test_empty_objects(self): - self.assertEqual(json.loads('{}'), {}) - self.assertEqual(json.loads('[]'), []) - self.assertEqual(json.loads('""'), "") + self.assertEqual(self.loads('{}'), {}) + self.assertEqual(self.loads('[]'), []) + self.assertEqual(self.loads('""'), "") def test_object_pairs_hook(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) - self.assertEqual(json.load(StringIO(s), - object_pairs_hook=lambda x: x), p) - od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p) + self.assertEqual(self.json.load(StringIO(s), + object_pairs_hook=lambda x: x), p) + od = self.loads(s, object_pairs_hook = OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, - object_pairs_hook = OrderedDict, + self.assertEqual(self.loads(s, object_pairs_hook = OrderedDict, object_hook = lambda x: None), OrderedDict(p)) @@ -57,7 +40,7 @@ # Several optimizations were made that skip over calls to # the whitespace regex, so this test is designed to try and # exercise the uncommon cases. The array cases are already covered. - rval = json.loads('{ "key" : "value" , "k":"v" }') + rval = self.loads('{ "key" : "value" , "k":"v" }') self.assertEqual(rval, {"key":"value", "k":"v"}) def check_keys_reuse(self, source, loads): @@ -68,7 +51,9 @@ def test_keys_reuse(self): s = '[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]' - self.check_keys_reuse(s, json.loads) - # Disabled: the pure Python version of json simply doesn't work - with use_python_scanner(): - self.check_keys_reuse(s, json.decoder.JSONDecoder().decode) + self.check_keys_reuse(s, self.loads) + self.check_keys_reuse(s, self.json.decoder.JSONDecoder().decode) + + +class TestPyDecode(TestDecode, PyTest): pass +class TestCDecode(TestDecode, CTest): pass diff --git a/Lib/test/json_tests/test_default.py b/Lib/test/json_tests/test_default.py --- a/Lib/test/json_tests/test_default.py +++ b/Lib/test/json_tests/test_default.py @@ -1,9 +1,12 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json -class TestDefault(TestCase): +class TestDefault: def test_default(self): self.assertEqual( - json.dumps(type, default=repr), - json.dumps(repr(type))) + self.dumps(type, default=repr), + self.dumps(repr(type))) + + +class TestPyDefault(TestDefault, PyTest): pass +class TestCDefault(TestDefault, CTest): pass diff --git a/Lib/test/json_tests/test_dump.py b/Lib/test/json_tests/test_dump.py --- a/Lib/test/json_tests/test_dump.py +++ b/Lib/test/json_tests/test_dump.py @@ -1,21 +1,24 @@ -from unittest import TestCase from io import StringIO +from test.json_tests import PyTest, CTest -import json -class TestDump(TestCase): +class TestDump: def test_dump(self): sio = StringIO() - json.dump({}, sio) + self.json.dump({}, sio) self.assertEqual(sio.getvalue(), '{}') def test_dumps(self): - self.assertEqual(json.dumps({}), '{}') + self.assertEqual(self.dumps({}), '{}') def test_encode_truefalse(self): - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {True: False, False: True}, sort_keys=True), '{"false": true, "true": false}') - self.assertEqual(json.dumps( + self.assertEqual(self.dumps( {2: 3.0, 4.0: 5, False: 1, 6: True}, sort_keys=True), '{"false": 1, "2": 3.0, "4.0": 5, "6": true}') + + +class TestPyDump(TestDump, PyTest): pass +class TestCDump(TestDump, CTest): pass diff --git a/Lib/test/json_tests/test_encode_basestring_ascii.py b/Lib/test/json_tests/test_encode_basestring_ascii.py --- a/Lib/test/json_tests/test_encode_basestring_ascii.py +++ b/Lib/test/json_tests/test_encode_basestring_ascii.py @@ -1,8 +1,6 @@ -from unittest import TestCase +from collections import OrderedDict +from test.json_tests import PyTest, CTest -import json.encoder -from json import dumps -from collections import OrderedDict CASES = [ ('/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'), @@ -21,19 +19,11 @@ ('\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), ] -class TestEncodeBaseStringAscii(TestCase): - def test_py_encode_basestring_ascii(self): - self._test_encode_basestring_ascii(json.encoder.py_encode_basestring_ascii) - - def test_c_encode_basestring_ascii(self): - if not json.encoder.c_encode_basestring_ascii: - return - self._test_encode_basestring_ascii(json.encoder.c_encode_basestring_ascii) - - def _test_encode_basestring_ascii(self, encode_basestring_ascii): - fname = encode_basestring_ascii.__name__ +class TestEncodeBasestringAscii: + def test_encode_basestring_ascii(self): + fname = self.json.encoder.encode_basestring_ascii.__name__ for input_string, expect in CASES: - result = encode_basestring_ascii(input_string) + result = self.json.encoder.encode_basestring_ascii(input_string) self.assertEqual(result, expect, '{0!r} != {1!r} for {2}({3!r})'.format( result, expect, fname, input_string)) @@ -41,10 +31,14 @@ def test_ordered_dict(self): # See issue 6105 items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(OrderedDict(items)) + s = self.dumps(OrderedDict(items)) self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}') def test_sorted_dict(self): items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(dict(items), sort_keys=True) + s = self.dumps(dict(items), sort_keys=True) self.assertEqual(s, '{"five": 5, "four": 4, "one": 1, "three": 3, "two": 2}') + + +class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass +class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): pass diff --git a/Lib/test/json_tests/test_fail.py b/Lib/test/json_tests/test_fail.py --- a/Lib/test/json_tests/test_fail.py +++ b/Lib/test/json_tests/test_fail.py @@ -1,6 +1,4 @@ -from unittest import TestCase - -import json +from test.json_tests import PyTest, CTest # Fri Dec 30 18:57:26 2005 JSONDOCS = [ @@ -61,15 +59,15 @@ 18: "spec doesn't specify any nesting limitations", } -class TestFail(TestCase): +class TestFail: def test_failures(self): for idx, doc in enumerate(JSONDOCS): idx = idx + 1 if idx in SKIPS: - json.loads(doc) + self.loads(doc) continue try: - json.loads(doc) + self.loads(doc) except ValueError: pass else: @@ -79,7 +77,11 @@ data = {'a' : 1, (1, 2) : 2} #This is for c encoder - self.assertRaises(TypeError, json.dumps, data) + self.assertRaises(TypeError, self.dumps, data) #This is for python encoder - self.assertRaises(TypeError, json.dumps, data, indent=True) + self.assertRaises(TypeError, self.dumps, data, indent=True) + + +class TestPyFail(TestFail, PyTest): pass +class TestCFail(TestFail, CTest): pass diff --git a/Lib/test/json_tests/test_float.py b/Lib/test/json_tests/test_float.py --- a/Lib/test/json_tests/test_float.py +++ b/Lib/test/json_tests/test_float.py @@ -1,15 +1,18 @@ import math -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json -class TestFloat(TestCase): +class TestFloat: def test_floats(self): for num in [1617161771.7650001, math.pi, math.pi**100, math.pi**-100, 3.1]: - self.assertEqual(float(json.dumps(num)), num) - self.assertEqual(json.loads(json.dumps(num)), num) + self.assertEqual(float(self.dumps(num)), num) + self.assertEqual(self.loads(self.dumps(num)), num) def test_ints(self): for num in [1, 1<<32, 1<<64]: - self.assertEqual(json.dumps(num), str(num)) - self.assertEqual(int(json.dumps(num)), num) + self.assertEqual(self.dumps(num), str(num)) + self.assertEqual(int(self.dumps(num)), num) + + +class TestPyFloat(TestFloat, PyTest): pass +class TestCFloat(TestFloat, CTest): pass diff --git a/Lib/test/json_tests/test_indent.py b/Lib/test/json_tests/test_indent.py --- a/Lib/test/json_tests/test_indent.py +++ b/Lib/test/json_tests/test_indent.py @@ -1,10 +1,9 @@ -from unittest import TestCase - -import json import textwrap from io import StringIO +from test.json_tests import PyTest, CTest -class TestIndent(TestCase): + +class TestIndent: def test_indent(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -30,14 +29,13 @@ \t} ]""") + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) + d3 = self.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) - d3 = json.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) - - h1 = json.loads(d1) - h2 = json.loads(d2) - h3 = json.loads(d3) + h1 = self.loads(d1) + h2 = self.loads(d2) + h3 = self.loads(d3) self.assertEqual(h1, h) self.assertEqual(h2, h) @@ -48,14 +46,18 @@ def test_indent0(self): h = {3: 1} def check(indent, expected): - d1 = json.dumps(h, indent=indent) + d1 = self.dumps(h, indent=indent) self.assertEqual(d1, expected) sio = StringIO() - json.dump(h, sio, indent=indent) + self.json.dump(h, sio, indent=indent) self.assertEqual(sio.getvalue(), expected) # indent=0 should emit newlines check(0, '{\n"3": 1\n}') # indent=None is more compact check(None, '{"3": 1}') + + +class TestPyIndent(TestIndent, PyTest): pass +class TestCIndent(TestIndent, CTest): pass diff --git a/Lib/test/json_tests/test_pass1.py b/Lib/test/json_tests/test_pass1.py --- a/Lib/test/json_tests/test_pass1.py +++ b/Lib/test/json_tests/test_pass1.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass1.json JSON = r''' @@ -62,15 +61,19 @@ ,"rosebud"] ''' -class TestPass1(TestCase): +class TestPass1: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) try: - json.dumps(res, allow_nan=False) + self.dumps(res, allow_nan=False) except ValueError: pass else: self.fail("23456789012E666 should be out of range") + + +class TestPyPass1(TestPass1, PyTest): pass +class TestCPass1(TestPass1, CTest): pass diff --git a/Lib/test/json_tests/test_pass2.py b/Lib/test/json_tests/test_pass2.py --- a/Lib/test/json_tests/test_pass2.py +++ b/Lib/test/json_tests/test_pass2.py @@ -1,14 +1,18 @@ -from unittest import TestCase -import json +from test.json_tests import PyTest, CTest + # from http://json.org/JSON_checker/test/pass2.json JSON = r''' [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] ''' -class TestPass2(TestCase): +class TestPass2: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass2(TestPass2, PyTest): pass +class TestCPass2(TestPass2, CTest): pass diff --git a/Lib/test/json_tests/test_pass3.py b/Lib/test/json_tests/test_pass3.py --- a/Lib/test/json_tests/test_pass3.py +++ b/Lib/test/json_tests/test_pass3.py @@ -1,6 +1,5 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json # from http://json.org/JSON_checker/test/pass3.json JSON = r''' @@ -12,9 +11,14 @@ } ''' -class TestPass3(TestCase): + +class TestPass3: def test_parse(self): # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) + res = self.loads(JSON) + out = self.dumps(res) + self.assertEqual(res, self.loads(out)) + + +class TestPyPass3(TestPass3, PyTest): pass +class TestCPass3(TestPass3, CTest): pass diff --git a/Lib/test/json_tests/test_recursion.py b/Lib/test/json_tests/test_recursion.py --- a/Lib/test/json_tests/test_recursion.py +++ b/Lib/test/json_tests/test_recursion.py @@ -1,33 +1,16 @@ -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json class JSONTestObject: pass -class RecursiveJSONEncoder(json.JSONEncoder): - recurse = False - def default(self, o): - if o is JSONTestObject: - if self.recurse: - return [JSONTestObject] - else: - return 'JSONTestObject' - return json.JSONEncoder.default(o) - -class EndlessJSONEncoder(json.JSONEncoder): - def default(self, o): - """If check_circular is False, this will keep adding another list.""" - return [o] - - -class TestRecursion(TestCase): +class TestRecursion: def test_listrecursion(self): x = [] x.append(x) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -36,7 +19,7 @@ y = [x] x.append(y) try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -44,13 +27,13 @@ y = [] x = [y, y] # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_dictrecursion(self): x = {} x["test"] = x try: - json.dumps(x) + self.dumps(x) except ValueError: pass else: @@ -58,9 +41,19 @@ x = {} y = {"a": x, "b": x} # ensure that the marker is cleared - json.dumps(x) + self.dumps(x) def test_defaultrecursion(self): + class RecursiveJSONEncoder(self.json.JSONEncoder): + recurse = False + def default(self, o): + if o is JSONTestObject: + if self.recurse: + return [JSONTestObject] + else: + return 'JSONTestObject' + return pyjson.JSONEncoder.default(o) + enc = RecursiveJSONEncoder() self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"') enc.recurse = True @@ -76,11 +69,11 @@ # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '1' + '}' * 100000) + self.loads('{"a":' * 100000 + '1' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('{"a":' * 100000 + '[1]' + '}' * 100000) + self.loads('{"a":' * 100000 + '[1]' + '}' * 100000) with self.assertRaises(RuntimeError): - json.loads('[' * 100000 + '1' + ']' * 100000) + self.loads('[' * 100000 + '1' + ']' * 100000) def test_highly_nested_objects_encoding(self): # See #12051 @@ -88,11 +81,20 @@ for x in range(100000): l, d = [l], {'k':d} with self.assertRaises(RuntimeError): - json.dumps(l) + self.dumps(l) with self.assertRaises(RuntimeError): - json.dumps(d) + self.dumps(d) def test_endless_recursion(self): # See #12051 + class EndlessJSONEncoder(self.json.JSONEncoder): + def default(self, o): + """If check_circular is False, this will keep adding another list.""" + return [o] + with self.assertRaises(RuntimeError): EndlessJSONEncoder(check_circular=False).encode(5j) + + +class TestPyRecursion(TestRecursion, PyTest): pass +class TestCRecursion(TestRecursion, CTest): pass diff --git a/Lib/test/json_tests/test_scanstring.py b/Lib/test/json_tests/test_scanstring.py --- a/Lib/test/json_tests/test_scanstring.py +++ b/Lib/test/json_tests/test_scanstring.py @@ -1,24 +1,10 @@ import sys -from unittest import TestCase, skipUnless +from test.json_tests import PyTest, CTest -import json -import json.decoder -try: - import _json -except ImportError: - _json = None - -class TestScanString(TestCase): - def test_py_scanstring(self): - self._test_scanstring(json.decoder.py_scanstring) - - @skipUnless(_json, 'test requires the _json module') - def test_c_scanstring(self): - if json.decoder.c_scanstring is not None: - self._test_scanstring(json.decoder.c_scanstring) - - def _test_scanstring(self, scanstring): +class TestScanstring: + def test_scanstring(self): + scanstring = self.json.decoder.scanstring self.assertEqual( scanstring('"z\\ud834\\udd20x"', 1, True), ('z\U0001d120x', 16)) @@ -109,4 +95,9 @@ ('Bad value', 12)) def test_overflow(self): - self.assertRaises(OverflowError, json.decoder.scanstring, b"xxx", sys.maxsize+1) + with self.assertRaises(OverflowError): + self.json.decoder.scanstring(b"xxx", sys.maxsize+1) + + +class TestPyScanstring(TestScanstring, PyTest): pass +class TestCScanstring(TestScanstring, CTest): pass diff --git a/Lib/test/json_tests/test_separators.py b/Lib/test/json_tests/test_separators.py --- a/Lib/test/json_tests/test_separators.py +++ b/Lib/test/json_tests/test_separators.py @@ -1,10 +1,8 @@ import textwrap -from unittest import TestCase +from test.json_tests import PyTest, CTest -import json - -class TestSeparators(TestCase): +class TestSeparators: def test_separators(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] @@ -31,12 +29,16 @@ ]""") - d1 = json.dumps(h) - d2 = json.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) + d1 = self.dumps(h) + d2 = self.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) - h1 = json.loads(d1) - h2 = json.loads(d2) + h1 = self.loads(d1) + h2 = self.loads(d2) self.assertEqual(h1, h) self.assertEqual(h2, h) self.assertEqual(d2, expect) + + +class TestPySeparators(TestSeparators, PyTest): pass +class TestCSeparators(TestSeparators, CTest): pass diff --git a/Lib/test/json_tests/test_speedups.py b/Lib/test/json_tests/test_speedups.py --- a/Lib/test/json_tests/test_speedups.py +++ b/Lib/test/json_tests/test_speedups.py @@ -1,29 +1,24 @@ -from unittest import TestCase, skipUnless +from test.json_tests import CTest -from json import decoder, encoder, scanner -try: - import _json -except ImportError: - _json = None - - at skipUnless(_json, 'test requires the _json module') -class TestSpeedups(TestCase): +class TestSpeedups(CTest): def test_scanstring(self): - self.assertEqual(decoder.scanstring.__module__, "_json") - self.assertIs(decoder.scanstring, decoder.c_scanstring) + self.assertEqual(self.json.decoder.scanstring.__module__, "_json") + self.assertIs(self.json.decoder.scanstring, self.json.decoder.c_scanstring) def test_encode_basestring_ascii(self): - self.assertEqual(encoder.encode_basestring_ascii.__module__, "_json") - self.assertIs(encoder.encode_basestring_ascii, - encoder.c_encode_basestring_ascii) + self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__, + "_json") + self.assertIs(self.json.encoder.encode_basestring_ascii, + self.json.encoder.c_encode_basestring_ascii) -class TestDecode(TestCase): + +class TestDecode(CTest): def test_make_scanner(self): - self.assertRaises(AttributeError, scanner.c_make_scanner, 1) + self.assertRaises(AttributeError, self.json.scanner.c_make_scanner, 1) def test_make_encoder(self): - self.assertRaises(TypeError, encoder.c_make_encoder, + self.assertRaises(TypeError, self.json.encoder.c_make_encoder, (True, False), b"\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75", None) diff --git a/Lib/test/json_tests/test_unicode.py b/Lib/test/json_tests/test_unicode.py --- a/Lib/test/json_tests/test_unicode.py +++ b/Lib/test/json_tests/test_unicode.py @@ -1,73 +1,75 @@ -from unittest import TestCase +from collections import OrderedDict +from test.json_tests import PyTest, CTest -import json -from collections import OrderedDict -class TestUnicode(TestCase): +class TestUnicode: # test_encoding1 and test_encoding2 from 2.x are irrelevant (only str # is supported as input, not bytes). def test_encoding3(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u) + j = self.dumps(u) self.assertEqual(j, '"\\u03b1\\u03a9"') def test_encoding4(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u]) + j = self.dumps([u]) self.assertEqual(j, '["\\u03b1\\u03a9"]') def test_encoding5(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u, ensure_ascii=False) + j = self.dumps(u, ensure_ascii=False) self.assertEqual(j, '"{0}"'.format(u)) def test_encoding6(self): u = '\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u], ensure_ascii=False) + j = self.dumps([u], ensure_ascii=False) self.assertEqual(j, '["{0}"]'.format(u)) def test_big_unicode_encode(self): u = '\U0001d120' - self.assertEqual(json.dumps(u), '"\\ud834\\udd20"') - self.assertEqual(json.dumps(u, ensure_ascii=False), '"\U0001d120"') + self.assertEqual(self.dumps(u), '"\\ud834\\udd20"') + self.assertEqual(self.dumps(u, ensure_ascii=False), '"\U0001d120"') def test_big_unicode_decode(self): u = 'z\U0001d120x' - self.assertEqual(json.loads('"' + u + '"'), u) - self.assertEqual(json.loads('"z\\ud834\\udd20x"'), u) + self.assertEqual(self.loads('"' + u + '"'), u) + self.assertEqual(self.loads('"z\\ud834\\udd20x"'), u) def test_unicode_decode(self): for i in range(0, 0xd7ff): u = chr(i) s = '"\\u{0:04x}"'.format(i) - self.assertEqual(json.loads(s), u) + self.assertEqual(self.loads(s), u) def test_unicode_preservation(self): - self.assertEqual(type(json.loads('""')), str) - self.assertEqual(type(json.loads('"a"')), str) - self.assertEqual(type(json.loads('["a"]')[0]), str) + self.assertEqual(type(self.loads('""')), str) + self.assertEqual(type(self.loads('"a"')), str) + self.assertEqual(type(self.loads('["a"]')[0]), str) def test_bytes_encode(self): - self.assertRaises(TypeError, json.dumps, b"hi") - self.assertRaises(TypeError, json.dumps, [b"hi"]) + self.assertRaises(TypeError, self.dumps, b"hi") + self.assertRaises(TypeError, self.dumps, [b"hi"]) def test_bytes_decode(self): - self.assertRaises(TypeError, json.loads, b'"hi"') - self.assertRaises(TypeError, json.loads, b'["hi"]') + self.assertRaises(TypeError, self.loads, b'"hi"') + self.assertRaises(TypeError, self.loads, b'["hi"]') def test_object_pairs_hook_with_unicode(self): s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook = lambda x: x), p) - od = json.loads(s, object_pairs_hook = OrderedDict) + self.assertEqual(self.loads(s), eval(s)) + self.assertEqual(self.loads(s, object_pairs_hook = lambda x: x), p) + od = self.loads(s, object_pairs_hook = OrderedDict) self.assertEqual(od, OrderedDict(p)) self.assertEqual(type(od), OrderedDict) # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, - object_pairs_hook = OrderedDict, + self.assertEqual(self.loads(s, object_pairs_hook = OrderedDict, object_hook = lambda x: None), OrderedDict(p)) + + +class TestPyUnicode(TestUnicode, PyTest): pass +class TestCUnicode(TestUnicode, CTest): pass diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -37,6 +37,7 @@ "findfile", "sortdict", "check_syntax_error", "open_urlresource", "check_warnings", "CleanImport", "EnvironmentVarGuard", "TransientResource", "captured_output", "captured_stdout", + "captured_stdin", "captured_stderr", "time_out", "socket_peer_reset", "ioerror_peer_reset", "run_with_locale", 'temp_umask', "transient_internet", "set_memlimit", "bigmemtest", "bigaddrspacetest", "BasicTestRunner", @@ -92,19 +93,15 @@ def _save_and_remove_module(name, orig_modules): """Helper function to save and remove a module from sys.modules - Return True if the module was in sys.modules, False otherwise. Raise ImportError if the module can't be imported.""" - saved = True - try: - orig_modules[name] = sys.modules[name] - except KeyError: - # try to import the module and raise an error if it can't be imported + # try to import the module and raise an error if it can't be imported + if name not in sys.modules: __import__(name) - saved = False - else: del sys.modules[name] - return saved - + for modname in list(sys.modules): + if modname == name or modname.startswith(name + '.'): + orig_modules[modname] = sys.modules[modname] + del sys.modules[modname] def _save_and_block_module(name, orig_modules): """Helper function to save and block a module in sys.modules @@ -132,8 +129,8 @@ If deprecated is True, any module or package deprecation messages will be suppressed.""" - # NOTE: test_heapq and test_warnings include extra sanity checks to make - # sure that this utility function is working as expected + # NOTE: test_heapq, test_json and test_warnings include extra sanity checks + # to make sure that this utility function is working as expected with _ignore_deprecated_imports(deprecated): # Keep track of modules saved for later restoration as well # as those which just need a blocking entry removed @@ -895,14 +892,8 @@ @contextlib.contextmanager def captured_output(stream_name): - """Run the 'with' statement body using a StringIO object in place of a - specific attribute on the sys module. - Example use (with 'stream_name=stdout'):: - - with captured_stdout() as s: - print("hello") - assert s.getvalue() == "hello" - """ + """Return a context manager used by captured_stdout/stdin/stderr + that temporarily replaces the sys stream *stream_name* with a StringIO.""" import io orig_stdout = getattr(sys, stream_name) setattr(sys, stream_name, io.StringIO()) @@ -912,6 +903,12 @@ setattr(sys, stream_name, orig_stdout) def captured_stdout(): + """Capture the output of sys.stdout: + + with captured_stdout() as s: + print("hello") + self.assertEqual(s.getvalue(), "hello") + """ return captured_output("stdout") def captured_stderr(): @@ -920,6 +917,7 @@ def captured_stdin(): return captured_output("stdin") + def gc_collect(): """Force as many objects as possible to be collected. diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -193,6 +193,7 @@ data = b'x' * size try: self.assertRaises(OverflowError, zlib.compress, data, 1) + self.assertRaises(OverflowError, zlib.decompress, data) finally: data = None @@ -360,6 +361,15 @@ self.assertRaises(ValueError, dco.decompress, b"", -1) self.assertEqual(b'', dco.unconsumed_tail) + def test_clear_unconsumed_tail(self): + # Issue #12050: calling decompress() without providing max_length + # should clear the unconsumed_tail attribute. + cdata = b"x\x9cKLJ\x06\x00\x02M\x01" # "abc" + dco = zlib.decompressobj() + ddata = dco.decompress(cdata, 1) + ddata += dco.decompress(dco.unconsumed_tail) + self.assertEqual(dco.unconsumed_tail, b"") + def test_flushes(self): # Test flush() with the various options, using all the # different levels in order to provide more variations. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,9 @@ Library ------- +- Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail + attribute when called without a max_length argument. + - Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence on a file opened in read+write mode (namely: reading, seeking a bit forward, writing, then seeking before the previous write but still within buffered @@ -379,6 +382,8 @@ Tests ----- +- Issue #5723: Improve json tests to be executed with and without accelerations. + - Issue #11873: Change regex in test_compileall to fix occasional failures when when the randomly generated temporary path happened to match the regex. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -116,7 +116,7 @@ { PyObject *ReturnVal = NULL; Py_buffer pinput; - Byte *input, *output; + Byte *input, *output = NULL; unsigned int length; int level=Z_DEFAULT_COMPRESSION, err; z_stream zst; @@ -127,20 +127,19 @@ if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } + input = pinput.buf; length = pinput.len; - input = pinput.buf; zst.avail_out = length + length/1000 + 12 + 1; output = (Byte*)malloc(zst.avail_out); if (output == NULL) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); - return NULL; + goto error; } /* Past the point of no return. From here on out, we need to make sure @@ -203,7 +202,7 @@ static PyObject * PyZlib_decompress(PyObject *self, PyObject *args) { - PyObject *result_str; + PyObject *result_str = NULL; Py_buffer pinput; Byte *input; unsigned int length; @@ -218,11 +217,11 @@ if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } + input = pinput.buf; length = pinput.len; - input = pinput.buf; if (r_strlen <= 0) r_strlen = 1; @@ -230,10 +229,8 @@ zst.avail_in = length; zst.avail_out = r_strlen; - if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) + goto error; zst.zalloc = (alloc_func)NULL; zst.zfree = (free_func)Z_NULL; @@ -574,17 +571,22 @@ Py_END_ALLOW_THREADS } - /* Not all of the compressed data could be accommodated in the output buffer - of specified size. Return the unconsumed tail in an attribute.*/ if(max_length) { + /* Not all of the compressed data could be accommodated in a buffer of + the specified size. Return the unconsumed tail in an attribute. */ Py_DECREF(self->unconsumed_tail); self->unconsumed_tail = PyBytes_FromStringAndSize((char *)self->zst.next_in, self->zst.avail_in); - if(!self->unconsumed_tail) { - Py_DECREF(RetVal); - RetVal = NULL; - goto error; - } + } + else if (PyBytes_GET_SIZE(self->unconsumed_tail) > 0) { + /* All of the compressed data was consumed. Clear unconsumed_tail. */ + Py_DECREF(self->unconsumed_tail); + self->unconsumed_tail = PyBytes_FromStringAndSize("", 0); + } + if (self->unconsumed_tail == NULL) { + Py_DECREF(RetVal); + RetVal = NULL; + goto error; } /* The end of the compressed data has been reached, so set the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:36:23 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 00:36:23 +0200 Subject: [Python-checkins] cpython: Fixes Issue #12059: Properly handle missing hash functions even when Message-ID: http://hg.python.org/cpython/rev/298888fd46b0 changeset: 70124:298888fd46b0 parent: 70117:7fb34d30bd59 user: Gregory P. Smith date: Sat May 14 15:15:49 2011 -0700 summary: Fixes Issue #12059: Properly handle missing hash functions even when the expected builtin modules are not present. This includes a unittest for __get_builtin_constructor() in the face of such an error. files: Lib/hashlib.py | 43 ++++++++++++++------------- Lib/test/test_hashlib.py | 18 +++++++++++ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -64,26 +64,29 @@ def __get_builtin_constructor(name): - if name in ('SHA1', 'sha1'): - import _sha1 - return _sha1.sha1 - elif name in ('MD5', 'md5'): - import _md5 - return _md5.md5 - elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): - import _sha256 - bs = name[3:] - if bs == '256': - return _sha256.sha256 - elif bs == '224': - return _sha256.sha224 - elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): - import _sha512 - bs = name[3:] - if bs == '512': - return _sha512.sha512 - elif bs == '384': - return _sha512.sha384 + try: + if name in ('SHA1', 'sha1'): + import _sha1 + return _sha1.sha1 + elif name in ('MD5', 'md5'): + import _md5 + return _md5.md5 + elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): + import _sha256 + bs = name[3:] + if bs == '256': + return _sha256.sha256 + elif bs == '224': + return _sha256.sha224 + elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): + import _sha512 + bs = name[3:] + if bs == '512': + return _sha512.sha512 + elif bs == '384': + return _sha512.sha384 + except ImportError: + pass # no extension module, this hash is unsupported. raise ValueError('unsupported hash type %s' % name) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -118,6 +118,24 @@ else: self.assertTrue(0 == "hashlib didn't reject bogus hash name") + def test_get_builtin_constructor(self): + get_builtin_constructor = hashlib.__dict__[ + '__get_builtin_constructor'] + self.assertRaises(ValueError, get_builtin_constructor, 'test') + try: + import _md5 + except ImportError: + pass + # This forces an ImportError for "import _md5" statements + sys.modules['_md5'] = None + try: + self.assertRaises(ValueError, get_builtin_constructor, 'md5') + finally: + if '_md5' in locals(): + sys.modules['_md5'] = _md5 + else: + del sys.modules['_md5'] + def test_hexdigest(self): for name in self.supported_hash_names: h = hashlib.new(name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:36:24 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 00:36:24 +0200 Subject: [Python-checkins] cpython (merge default -> default): merge heads Message-ID: http://hg.python.org/cpython/rev/599487064aa0 changeset: 70125:599487064aa0 parent: 70124:298888fd46b0 parent: 70120:f86a22b6ab58 user: Gregory P. Smith date: Sat May 14 15:32:19 2011 -0700 summary: merge heads files: Lib/test/test_zlib.py | 11 +++++++++ Misc/NEWS | 5 ++++ Modules/zlibmodule.c | 37 +++++++++++++++++++----------- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -523,6 +523,17 @@ decompress = lambda s: d.decompress(s) + d.flush() self.check_big_decompress_buffer(size, 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) + self.assertRaises(OverflowError, zlib.decompress, data) + finally: + data = None + def genblock(seed, length, step=1024, generator=random): """length-byte stream of random data from a seed (in step-byte blocks).""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -147,6 +147,11 @@ Library ------- +- Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and + their incremental counterparts now raise OverflowError if given an input + larger than 4GB, instead of silently truncating the input and returning + an incorrect result. + - Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -420,22 +420,26 @@ static PyObject * PyZlib_objcompress(compobject *self, PyObject *args) { - int err, inplen; + int err; + unsigned int inplen; Py_ssize_t length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; if (!PyArg_ParseTuple(args, "y*:compress", &pinput)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -484,6 +488,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } @@ -502,9 +507,10 @@ static PyObject * PyZlib_objdecompress(compobject *self, PyObject *args) { - int err, inplen, max_length = 0; + int err, max_length = 0; + unsigned int inplen; Py_ssize_t old_length, length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; @@ -512,22 +518,24 @@ if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput, &max_length)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; if (max_length < 0) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_ValueError, "max_length must be greater than zero"); - return NULL; + goto error_outer; } /* limit amount of data allocated to max_length */ if (max_length && length > max_length) length = max_length; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -621,6 +629,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:36:24 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 00:36:24 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): merge heads Message-ID: http://hg.python.org/cpython/rev/428e9eed5cda changeset: 70126:428e9eed5cda branch: 3.2 parent: 70123:5066cda37414 parent: 70119:3ff862d05d18 user: Gregory P. Smith date: Sat May 14 15:33:43 2011 -0700 summary: merge heads files: Lib/test/test_zlib.py | 11 +++++++++ Misc/NEWS | 5 ++++ Modules/zlibmodule.c | 37 +++++++++++++++++++----------- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -523,6 +523,17 @@ decompress = lambda s: d.decompress(s) + d.flush() self.check_big_decompress_buffer(size, 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) + self.assertRaises(OverflowError, zlib.decompress, data) + finally: + data = None + def genblock(seed, length, step=1024, generator=random): """length-byte stream of random data from a seed (in step-byte blocks).""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,11 @@ Library ------- +- Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and + their incremental counterparts now raise OverflowError if given an input + larger than 4GB, instead of silently truncating the input and returning + an incorrect result. + - Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -420,22 +420,26 @@ static PyObject * PyZlib_objcompress(compobject *self, PyObject *args) { - int err, inplen; + int err; + unsigned int inplen; Py_ssize_t length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; if (!PyArg_ParseTuple(args, "y*:compress", &pinput)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -484,6 +488,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } @@ -502,9 +507,10 @@ static PyObject * PyZlib_objdecompress(compobject *self, PyObject *args) { - int err, inplen, max_length = 0; + int err, max_length = 0; + unsigned int inplen; Py_ssize_t old_length, length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; Py_buffer pinput; Byte *input; unsigned long start_total_out; @@ -512,22 +518,24 @@ if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput, &max_length)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } input = pinput.buf; inplen = pinput.len; if (max_length < 0) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_ValueError, "max_length must be greater than zero"); - return NULL; + goto error_outer; } /* limit amount of data allocated to max_length */ if (max_length && length > max_length) length = max_length; - if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; ENTER_ZLIB(self); @@ -621,6 +629,7 @@ error: LEAVE_ZLIB(self); + error_outer: PyBuffer_Release(&pinput); return RetVal; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:36:25 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 00:36:25 +0200 Subject: [Python-checkins] cpython (3.2): fix whitespace Message-ID: http://hg.python.org/cpython/rev/c238bddf3596 changeset: 70127:c238bddf3596 branch: 3.2 user: Gregory P. Smith date: Sat May 14 15:35:19 2011 -0700 summary: fix whitespace files: Lib/hashlib.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -86,7 +86,7 @@ elif bs == '384': return _sha512.sha384 except ImportError: - pass # no extension module, this hash is unsupported. + pass # no extension module, this hash is unsupported. raise ValueError('unsupported hash type %s' % name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:36:25 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 00:36:25 +0200 Subject: [Python-checkins] cpython: fix whitespace Message-ID: http://hg.python.org/cpython/rev/a968ed87ff75 changeset: 70128:a968ed87ff75 parent: 70125:599487064aa0 user: Gregory P. Smith date: Sat May 14 15:35:56 2011 -0700 summary: fix whitespace files: Lib/hashlib.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -86,7 +86,7 @@ elif bs == '384': return _sha512.sha384 except ImportError: - pass # no extension module, this hash is unsupported. + pass # no extension module, this hash is unsupported. raise ValueError('unsupported hash type %s' % name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:50:19 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sun, 15 May 2011 00:50:19 +0200 Subject: [Python-checkins] cpython (3.1): Fix copy-paste mistake in new zlib test. Message-ID: http://hg.python.org/cpython/rev/8db300ceceb7 changeset: 70129:8db300ceceb7 branch: 3.1 parent: 70118:0b5211d19a14 user: Nadeem Vawda date: Sun May 15 00:48:24 2011 +0200 summary: Fix copy-paste mistake in new zlib test. files: Lib/test/test_zlib.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -528,9 +528,11 @@ if size < _4G + 100: self.skipTest("not enough free memory, need at least 4 GB") data = b'x' * size + c = zlib.compressobj(1) + d = zlib.decompressobj() try: - self.assertRaises(OverflowError, zlib.compress, data, 1) - self.assertRaises(OverflowError, zlib.decompress, data) + self.assertRaises(OverflowError, c.compress, data) + self.assertRaises(OverflowError, d.decompress, data) finally: data = None -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:50:20 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sun, 15 May 2011 00:50:20 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge: Fix copy-paste mistake in new zlib test. Message-ID: http://hg.python.org/cpython/rev/a3b76b14864a changeset: 70130:a3b76b14864a branch: 3.2 parent: 70127:c238bddf3596 parent: 70129:8db300ceceb7 user: Nadeem Vawda date: Sun May 15 00:48:57 2011 +0200 summary: Merge: Fix copy-paste mistake in new zlib test. files: Lib/test/test_zlib.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -528,9 +528,11 @@ if size < _4G + 100: self.skipTest("not enough free memory, need at least 4 GB") data = b'x' * size + c = zlib.compressobj(1) + d = zlib.decompressobj() try: - self.assertRaises(OverflowError, zlib.compress, data, 1) - self.assertRaises(OverflowError, zlib.decompress, data) + self.assertRaises(OverflowError, c.compress, data) + self.assertRaises(OverflowError, d.decompress, data) finally: data = None -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 00:50:22 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sun, 15 May 2011 00:50:22 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge: Fix copy-paste mistake in new zlib test. Message-ID: http://hg.python.org/cpython/rev/0bdf5c7e60e8 changeset: 70131:0bdf5c7e60e8 parent: 70128:a968ed87ff75 parent: 70130:a3b76b14864a user: Nadeem Vawda date: Sun May 15 00:49:20 2011 +0200 summary: Merge: Fix copy-paste mistake in new zlib test. files: Lib/test/test_zlib.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -528,9 +528,11 @@ if size < _4G + 100: self.skipTest("not enough free memory, need at least 4 GB") data = b'x' * size + c = zlib.compressobj(1) + d = zlib.decompressobj() try: - self.assertRaises(OverflowError, zlib.compress, data, 1) - self.assertRaises(OverflowError, zlib.decompress, data) + self.assertRaises(OverflowError, c.compress, data) + self.assertRaises(OverflowError, d.decompress, data) finally: data = None -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun May 15 05:00:12 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 15 May 2011 05:00:12 +0200 Subject: [Python-checkins] Daily reference leaks (0bdf5c7e60e8): sum=0 Message-ID: results for 0bdf5c7e60e8 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogL9u1Mm', '-x'] From python-checkins at python.org Sun May 15 08:51:40 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 15 May 2011 08:51:40 +0200 Subject: [Python-checkins] cpython (3.1): Closes #6498: fix several misspellings of "SystemExit" as "SystemError". Message-ID: http://hg.python.org/cpython/rev/0311f62714f7 changeset: 70132:0311f62714f7 branch: 3.1 parent: 70129:8db300ceceb7 user: Georg Brandl date: Sun May 15 08:49:12 2011 +0200 summary: Closes #6498: fix several misspellings of "SystemExit" as "SystemError". files: Doc/c-api/veryhigh.rst | 11 ++++++----- Python/pythonrun.c | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -34,11 +34,12 @@ according to the user's locale). It is important to note that the argument list may be modified (but the contents of the strings pointed to by the argument list are not). The return value will be - the integer passed to the :func:`sys.exit` function, ``1`` if the - interpreter exits due to an exception, or ``2`` if the parameter - list does not represent a valid Python command line. + ```0``` if the interpreter exits normally (ie, without an + exception), ``1`` if the interpreter exits due to an exception, or + ``2`` if the parameter list does not represent a valid Python + command line. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``1``, but exit the process, as long as ``Py_InspectFlag`` is not set. @@ -84,7 +85,7 @@ there was an error, there is no way to get the exception information. For the meaning of *flags*, see below. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``-1``, but exit the process, as long as ``Py_InspectFlag`` is not set. diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -82,7 +82,7 @@ int Py_DebugFlag; /* Needed by parser.c */ int Py_VerboseFlag; /* Needed by import.c */ int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ -int Py_InspectFlag; /* Needed to determine whether to exit at SystemError */ +int Py_InspectFlag; /* Needed to determine whether to exit at SystemExit */ int Py_NoSiteFlag; /* Suppress 'import site' */ int Py_BytesWarningFlag; /* Warn on str(bytes) and str(buffer) */ int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.py[co]) */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 08:51:41 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 15 May 2011 08:51:41 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Merge #6498 fix from 3.1. Message-ID: http://hg.python.org/cpython/rev/7089afd69a1a changeset: 70133:7089afd69a1a branch: 3.2 parent: 70130:a3b76b14864a parent: 70132:0311f62714f7 user: Georg Brandl date: Sun May 15 08:49:29 2011 +0200 summary: Merge #6498 fix from 3.1. files: Doc/c-api/veryhigh.rst | 11 ++++++----- Python/pythonrun.c | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -34,11 +34,12 @@ according to the user's locale). It is important to note that the argument list may be modified (but the contents of the strings pointed to by the argument list are not). The return value will be - the integer passed to the :func:`sys.exit` function, ``1`` if the - interpreter exits due to an exception, or ``2`` if the parameter - list does not represent a valid Python command line. + ```0``` if the interpreter exits normally (ie, without an + exception), ``1`` if the interpreter exits due to an exception, or + ``2`` if the parameter list does not represent a valid Python + command line. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``1``, but exit the process, as long as ``Py_InspectFlag`` is not set. @@ -85,7 +86,7 @@ there was an error, there is no way to get the exception information. For the meaning of *flags*, see below. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``-1``, but exit the process, as long as ``Py_InspectFlag`` is not set. diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -80,7 +80,7 @@ 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_InspectFlag; /* Needed to determine whether to exit at SystemExit */ int Py_NoSiteFlag; /* Suppress 'import site' */ int Py_BytesWarningFlag; /* Warn on str(bytes) and str(buffer) */ int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.py[co]) */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 08:51:42 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 15 May 2011 08:51:42 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #6498 fix from 3.2. Message-ID: http://hg.python.org/cpython/rev/94e3c44b0662 changeset: 70134:94e3c44b0662 parent: 70131:0bdf5c7e60e8 parent: 70133:7089afd69a1a user: Georg Brandl date: Sun May 15 08:49:38 2011 +0200 summary: Merge #6498 fix from 3.2. files: Doc/c-api/veryhigh.rst | 11 ++++++----- Python/pythonrun.c | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -34,11 +34,12 @@ according to the user's locale). It is important to note that the argument list may be modified (but the contents of the strings pointed to by the argument list are not). The return value will be - the integer passed to the :func:`sys.exit` function, ``1`` if the - interpreter exits due to an exception, or ``2`` if the parameter - list does not represent a valid Python command line. + ```0``` if the interpreter exits normally (ie, without an + exception), ``1`` if the interpreter exits due to an exception, or + ``2`` if the parameter list does not represent a valid Python + command line. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``1``, but exit the process, as long as ``Py_InspectFlag`` is not set. @@ -85,7 +86,7 @@ there was an error, there is no way to get the exception information. For the meaning of *flags*, see below. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``-1``, but exit the process, as long as ``Py_InspectFlag`` is not set. diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -83,7 +83,7 @@ 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_InspectFlag; /* Needed to determine whether to exit at SystemExit */ int Py_NoSiteFlag; /* Suppress 'import site' */ int Py_BytesWarningFlag; /* Warn on str(bytes) and str(buffer) */ int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.py[co]) */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 08:51:42 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 15 May 2011 08:51:42 +0200 Subject: [Python-checkins] cpython (2.7): Port #6498 fix: fix several misspellings of "SystemExit" as "SystemError". Message-ID: http://hg.python.org/cpython/rev/97a75fccd7c8 changeset: 70135:97a75fccd7c8 branch: 2.7 parent: 70121:572fbd9ca28f user: Georg Brandl date: Sun May 15 08:50:32 2011 +0200 summary: Port #6498 fix: fix several misspellings of "SystemExit" as "SystemError". files: Doc/c-api/veryhigh.rst | 10 +++++----- Python/pythonrun.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -32,11 +32,11 @@ prepared exactly as those which are passed to a C program's :cfunc:`main` function. It is important to note that the argument list may be modified (but the contents of the strings pointed to by the argument list are not). The return - value will be the integer passed to the :func:`sys.exit` function, ``1`` if the - interpreter exits due to an exception, or ``2`` if the parameter list does not - represent a valid Python command line. + value will be ```0``` if the interpreter exits normally (ie, without an + exception), ``1`` if the interpreter exits due to an exception, or ``2`` + if the parameter list does not represent a valid Python command line. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``1``, but exit the process, as long as ``Py_InspectFlag`` is not set. @@ -82,7 +82,7 @@ there was an error, there is no way to get the exception information. For the meaning of *flags*, see below. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``-1``, but exit the process, as long as ``Py_InspectFlag`` is not set. diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -76,7 +76,7 @@ int Py_DebugFlag; /* Needed by parser.c */ int Py_VerboseFlag; /* Needed by import.c */ int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ -int Py_InspectFlag; /* Needed to determine whether to exit at SystemError */ +int Py_InspectFlag; /* Needed to determine whether to exit at SystemExit */ int Py_NoSiteFlag; /* Suppress 'import site' */ int Py_BytesWarningFlag; /* Warn on str(bytes) and str(buffer) */ int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.py[co]) */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 09:27:03 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 09:27:03 +0200 Subject: [Python-checkins] cpython: Issue #1746656: Add if_nameindex, if_nametoindex, if_indextoname Message-ID: http://hg.python.org/cpython/rev/c2515cb23d9b changeset: 70136:c2515cb23d9b parent: 70134:94e3c44b0662 user: Gregory P. Smith date: Sun May 15 00:26:45 2011 -0700 summary: Issue #1746656: Add if_nameindex, if_nametoindex, if_indextoname methods to the socket module. files: Doc/library/socket.rst | 33 + Lib/test/test_socket.py | 10 + Misc/NEWS | 3 + Modules/socketmodule.c | 110 +++++ configure | 523 ++++++++++++++------------- configure.in | 1 + pyconfig.h.in | 3 + 7 files changed, 432 insertions(+), 251 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -536,6 +536,39 @@ .. versionadded:: 3.3 +.. function:: if_nameindex() + + Returns a list of network interface information + (index, name as a byte string) tuples. + :exc:`socket.error` if the system call fails for any reason. + + Availability: Unix. + + .. versionadded:: 3.3 + + +.. function:: if_nametoindex(if_name) + + Returns a network interface index number corresponding to an + interface name byte string. + :exc:`socket.error` if no interface with the given name exists. + + Availability: Unix. + + .. versionadded:: 3.3 + + +.. function:: if_indextoname(if_index) + + Returns a network interface name byte string corresponding to a + interface index. + :exc:`socket.error` if no interface with the given index exists. + + Availability: Unix. + + .. versionadded:: 3.3 + + .. data:: SocketType This is a Python type object that represents the socket object type. It is the diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -372,6 +372,16 @@ finally: socket.sethostname(oldhn) + @unittest.skipUnless(hasattr(socket, 'if_nameindex'), + 'socket.if_nameindex() not available.') + def testInterfaceNameIndex(self): + interfaces = socket.if_nameindex() + for index, name in interfaces: + # interface indices are non-zero integers + self.assertGreater(index, 0) + self.assertEqual(index, socket.if_nametoindex(name)) + self.assertEqual(name, socket.if_indextoname(index)) + def testRefCountGetNameInfo(self): # Testing reference count for getnameinfo if hasattr(sys, "getrefcount"): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Added the if_nameindex, if_indextoname, if_nametoindex methods to + the socket module as requested in issue #1746656. + - Issue #12044: Fixed subprocess.Popen when used as a context manager to wait for the process to end when exiting the context to avoid unintentionally leaving zombie processes around. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -42,6 +42,9 @@ - socket.inet_ntoa(packed IP) -> IP address string - socket.getdefaulttimeout() -> None | float - socket.setdefaulttimeout(None | float) +- socket.if_nameindex() -> list of tuples (if_index, if_name) +- socket.if_nametoindex(name) -> corresponding interface index +- socket.if_indextoname(index) -> corresponding interface name - an Internet socket address is a pair (hostname, port) where hostname can be anything recognized by gethostbyname() (including the dd.dd.dd.dd notation) and port is in host byte order @@ -133,6 +136,9 @@ setsockopt(level, optname, value) -- set socket options\n\ settimeout(None | float) -- set or clear the timeout\n\ shutdown(how) -- shut down traffic in one or both directions\n\ +if_nameindex() -- return all network interface indices and names\n\ +if_nametoindex(name) -- returns the corresponding interface index\n\ +if_indextoname(index) -- returns the corresponding interface name\n\ \n\ [*] not available on all platforms!"); @@ -4267,6 +4273,102 @@ When the socket module is first imported, the default is None."); +#ifdef HAVE_IF_NAMEINDEX +/* Python API for getting interface indices and names */ + +static PyObject * +socket_if_nameindex(PyObject *self, PyObject *arg) +{ + int i = 0; + PyObject *list; + struct if_nameindex *ni = if_nameindex(); + + if (ni == NULL) { + PyErr_SetString(socket_error, "if_nameindex() returned NULL."); + return NULL; + } + + list = PyList_New(0); + if (list == NULL) { + if_freenameindex(ni); + return NULL; + } + + while (ni[i].if_index != 0 && i < INT_MAX) { + PyObject *ni_tuple = Py_BuildValue( + "Iy", ni[i].if_index, ni[i].if_name); + + if (ni_tuple == NULL || PyList_Append(list, ni_tuple) == -1) { + Py_XDECREF(ni_tuple); + goto error; + } + Py_DECREF(ni_tuple); + + ++i; + } + + if_freenameindex(ni); + return list; + +error: + Py_DECREF(list); + if_freenameindex(ni); + return NULL; +} + +PyDoc_STRVAR(if_nameindex_doc, +"if_nameindex()\n\ +\n\ +Returns a list of network interface information (index, name) tuples."); + + +PyObject* +socket_if_nametoindex(PyObject *self, PyObject *arg) +{ + char* ifname = PyBytes_AsString(arg); + unsigned long index; + + if (ifname == NULL) + return NULL; + + index = if_nametoindex(ifname); + if (index == 0) { + PyErr_SetString(socket_error, "no interface with this name"); + return NULL; + } + + return PyLong_FromUnsignedLong(index); +} + +PyDoc_STRVAR(if_nametoindex_doc, +"if_nametoindex(if_name)\n\ +\n\ +Returns the interface index corresponding to the interface name if_name."); + + +PyObject* +socket_if_indextoname(PyObject *self, PyObject *arg) +{ + unsigned long index = PyLong_AsUnsignedLongMask(arg); + char name[IF_NAMESIZE + 1]; /* or use IFNAMSIZ ?*/ + char *ret = if_indextoname(index, &name[0]); + + if (ret == NULL) { + PyErr_SetString(socket_error, "no interface with this index"); + return NULL; + } + + return PyBytes_FromString(name); +} + +PyDoc_STRVAR(if_indextoname_doc, +"if_indextoname(if_index)\n\ +\n\ +Returns the interface name corresponding to the interface index if_index."); + +#endif /* HAVE_IF_NAMEINDEX */ + + /* List of functions exported by this module. */ static PyMethodDef socket_methods[] = { @@ -4322,6 +4424,14 @@ METH_NOARGS, getdefaulttimeout_doc}, {"setdefaulttimeout", socket_setdefaulttimeout, METH_O, setdefaulttimeout_doc}, +#ifdef HAVE_IF_NAMEINDEX + {"if_nameindex", socket_if_nameindex, + METH_NOARGS, if_nameindex_doc}, + {"if_nametoindex", socket_if_nametoindex, + METH_O, if_nametoindex_doc}, + {"if_indextoname", socket_if_indextoname, + METH_O, if_indextoname_doc}, +#endif {NULL, NULL} /* Sentinel */ }; diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,14 +1,14 @@ #! /bin/sh # From configure.in Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.65 for python 3.3. +# Generated by GNU Autoconf 2.67 for python 3.3. # # Report bugs to . # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS 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=$?; 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 + 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 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&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, Linux) returns a bogus exit status, +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` @@ -832,8 +832,9 @@ fi case $ac_option in - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *) ac_optarg=yes ;; + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. @@ -878,7 +879,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 @@ -904,7 +905,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 @@ -1108,7 +1109,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 @@ -1124,7 +1125,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 @@ -1154,8 +1155,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" ;; *=*) @@ -1163,7 +1164,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 ;; @@ -1181,13 +1182,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 @@ -1210,7 +1211,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' @@ -1224,8 +1225,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 @@ -1240,9 +1241,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. @@ -1281,11 +1282,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 @@ -1325,7 +1326,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 @@ -1510,9 +1511,9 @@ if $ac_init_version; then cat <<\_ACEOF python configure 3.3 -generated by GNU Autoconf 2.65 - -Copyright (C) 2009 Free Software Foundation, Inc. +generated by GNU Autoconf 2.67 + +Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1628,7 +1629,7 @@ mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } >/dev/null && { + test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : @@ -1652,10 +1653,10 @@ ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -1691,7 +1692,7 @@ else ac_header_preproc=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } @@ -1714,17 +1715,15 @@ $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;} -( cat <<\_ASBOX -## -------------------------------------- ## +( $as_echo "## -------------------------------------- ## ## 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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -1788,7 +1787,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -1819,7 +1818,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1873,7 +1872,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1903,8 +1902,7 @@ esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - eval as_val=\$$3 - if test "x$as_val" = x""no; then : + if eval test \"x\$"$3"\" = x"no"; then : else break @@ -1927,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1978,8 +1976,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - eval as_val=\$$3 - if test "x$as_val" = x""no; then : + if eval test \"x\$"$3"\" = x"no"; then : else break @@ -2179,7 +2176,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 { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2247,7 +2244,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 { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$4+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2295,15 +2292,18 @@ } # ac_fn_c_check_member -# ac_fn_c_check_decl LINENO SYMBOL VAR -# ------------------------------------ -# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. +# 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 () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $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_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_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2312,8 +2312,12 @@ int main () { -#ifndef $2 - (void) $2; +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif #endif ; @@ -2338,7 +2342,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by python $as_me 3.3, which was -generated by GNU Autoconf 2.65. Invocation command line was +generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ @@ -2448,11 +2452,9 @@ { echo - cat <<\_ASBOX -## ---------------- ## + $as_echo "## ---------------- ## ## Cache variables. ## -## ---------------- ## -_ASBOX +## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( @@ -2486,11 +2488,9 @@ ) echo - cat <<\_ASBOX -## ----------------- ## + $as_echo "## ----------------- ## ## Output variables. ## -## ----------------- ## -_ASBOX +## ----------------- ##" echo for ac_var in $ac_subst_vars do @@ -2503,11 +2503,9 @@ echo if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------------- ## + $as_echo "## ------------------- ## ## File substitutions. ## -## ------------------- ## -_ASBOX +## ------------------- ##" echo for ac_var in $ac_subst_files do @@ -2521,11 +2519,9 @@ fi if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## + $as_echo "## ----------- ## ## confdefs.h. ## -## ----------- ## -_ASBOX +## ----------- ##" echo cat confdefs.h echo @@ -2580,7 +2576,12 @@ ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - ac_site_file1=$CONFIG_SITE + # 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 elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site @@ -2595,7 +2596,11 @@ { $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" + . "$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 ; } fi done @@ -2671,7 +2676,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. ## @@ -2772,7 +2777,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 @@ -3164,7 +3169,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 @@ -3474,8 +3479,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 @@ -3589,9 +3594,8 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "C compiler cannot create executables -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "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; } @@ -3633,8 +3637,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 @@ -3691,9 +3695,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 @@ -3744,8 +3748,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 @@ -4228,7 +4232,7 @@ # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -4244,11 +4248,11 @@ ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi @@ -4287,7 +4291,7 @@ # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -4303,18 +4307,18 @@ ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i 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 @@ -4375,7 +4379,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 @@ -4441,7 +4445,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 @@ -4573,8 +4577,7 @@ 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 " -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -5198,16 +5201,22 @@ esac ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - 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 + 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 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, @@ -5545,7 +5554,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 @@ -6033,8 +6042,7 @@ 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" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -6048,7 +6056,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 { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$as_ac_Header+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6075,8 +6083,7 @@ eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF @@ -6573,9 +6580,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (int) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (int) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_int=0 fi @@ -6607,9 +6613,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (long) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_long=0 fi @@ -6641,9 +6646,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (void *) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (void *) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_void_p=0 fi @@ -6675,9 +6679,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (short) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (short) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_short=0 fi @@ -6709,9 +6712,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (float) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (float) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_float=0 fi @@ -6743,9 +6745,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (double) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (double) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_double=0 fi @@ -6777,9 +6778,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (fpos_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (fpos_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_fpos_t=0 fi @@ -6811,9 +6811,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (size_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (size_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_size_t=0 fi @@ -6845,9 +6844,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (pid_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (pid_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_pid_t=0 fi @@ -6906,9 +6904,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (long long) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long long) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_long_long=0 fi @@ -6968,9 +6965,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (long double) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long double) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_long_double=0 fi @@ -7031,9 +7027,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (_Bool) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (_Bool) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof__Bool=0 fi @@ -7080,9 +7075,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (uintptr_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (uintptr_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_uintptr_t=0 fi @@ -7122,9 +7116,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (off_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (off_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_off_t=0 fi @@ -7185,9 +7178,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (time_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (time_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_time_t=0 fi @@ -7258,9 +7250,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (pthread_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (pthread_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_pthread_t=0 fi @@ -7347,7 +7338,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 @@ -7359,7 +7350,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 @@ -7385,7 +7376,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 @@ -8225,12 +8216,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 @@ -9203,7 +9194,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 @@ -9286,6 +9277,7 @@ futimens futimes \ gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ + if_nameindex \ initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \ posix_fallocate posix_fadvise pread \ @@ -9301,8 +9293,7 @@ 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -10325,8 +10316,7 @@ 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -10335,25 +10325,44 @@ done -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 +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 - *" $ac_func.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" + *" dup2.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS dup2.$ac_objext" ;; esac fi -done + +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 + +else + case " $LIBOBJS " in + *" strdup.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strdup.$ac_objext" + ;; +esac + +fi for ac_func in getpgrp @@ -11566,7 +11575,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 @@ -11590,7 +11599,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 @@ -11840,8 +11849,7 @@ 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -11853,8 +11861,7 @@ 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -12117,7 +12124,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; } @@ -12168,9 +12175,8 @@ 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_set_status 77 -as_fn_error "cannot compute sizeof (wchar_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (wchar_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_wchar_t=0 fi @@ -12539,8 +12545,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 @@ -12801,7 +12807,7 @@ have_readline=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext if test $have_readline = yes then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12975,7 +12981,7 @@ have_readline=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext if test $have_readline = yes then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13905,6 +13911,7 @@ 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$//' @@ -14067,19 +14074,19 @@ (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS 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=$?; 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 + 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 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -14275,7 +14282,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 @@ -14329,7 +14336,7 @@ # values after options handling. ac_log=" This file was extended by python $as_me 3.3, which was -generated by GNU Autoconf 2.65. Invocation command line was +generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -14391,10 +14398,10 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ python config.status 3.3 -configured by $0, generated by GNU Autoconf 2.65, +configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" -Copyright (C) 2009 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -14410,11 +14417,16 @@ 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 @@ -14436,6 +14448,7 @@ $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;; @@ -14448,7 +14461,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 ;; @@ -14457,7 +14470,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" @@ -14516,7 +14529,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 @@ -14553,7 +14566,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. @@ -14570,7 +14583,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 @@ -14584,18 +14597,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 @@ -14684,20 +14697,28 @@ else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ - || as_fn_error "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and + || 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 # 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[ ]*=/{ -s/:*\$(srcdir):*/:/ -s/:*\${srcdir}:*/:/ -s/:*@srcdir@:*/:/ -s/^\([^=]*=[ ]*\):*/\1/ + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// s/^[^=]*=[ ]*$// }' fi @@ -14725,7 +14746,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 @@ -14810,7 +14831,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" @@ -14823,7 +14844,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 @@ -14851,7 +14872,7 @@ [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "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'" @@ -14878,7 +14899,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 @@ -15009,22 +15030,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) # @@ -15035,19 +15056,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 ;; @@ -15067,7 +15088,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. @@ -15088,7 +15109,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 $? + $ac_cs_success || as_fn_exit 1 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 diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -2512,6 +2512,7 @@ futimens futimes \ gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ + if_nameindex \ initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \ posix_fallocate posix_fadvise pread \ diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -389,6 +389,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_IEEEFP_H +/* Define to 1 if you have the `if_nameindex' function. */ +#undef HAVE_IF_NAMEINDEX + /* Define if you have the 'inet_aton' function. */ #undef HAVE_INET_ATON -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 10:27:58 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 15 May 2011 10:27:58 +0200 Subject: [Python-checkins] cpython (3.1): Issue #12060: Use sig_atomic_t type and volatile keyword in the signal module. Message-ID: http://hg.python.org/cpython/rev/945ca78c38b1 changeset: 70137:945ca78c38b1 branch: 3.1 parent: 70132:0311f62714f7 user: Victor Stinner date: Sun May 15 10:21:59 2011 +0200 summary: Issue #12060: Use sig_atomic_t type and volatile keyword in the signal module. Patch written by Charles-Fran?ois Natali. files: Misc/NEWS | 3 +++ Modules/signalmodule.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12060: Use sig_atomic_t type and volatile keyword in the signal + module. Patch written by Charles-Fran?ois Natali. + - Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, clear the end-of-file indicator after CTRL+d. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -78,12 +78,12 @@ static pid_t main_pid; #endif -static struct { - int tripped; +static volatile struct { + sig_atomic_t tripped; PyObject *func; } Handlers[NSIG]; -static sig_atomic_t wakeup_fd = -1; +static volatile sig_atomic_t wakeup_fd = -1; /* Speed up sigcheck() when none tripped */ static volatile sig_atomic_t is_tripped = 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 10:27:59 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 15 May 2011 10:27:59 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (Merge 3.1) Issue #12060: Use sig_atomic_t type and volatile keyword in the Message-ID: http://hg.python.org/cpython/rev/b74999f561ca changeset: 70138:b74999f561ca branch: 3.2 parent: 70133:7089afd69a1a parent: 70137:945ca78c38b1 user: Victor Stinner date: Sun May 15 10:27:09 2011 +0200 summary: (Merge 3.1) Issue #12060: Use sig_atomic_t type and volatile keyword in the signal module. Patch written by Charles-Fran?ois Natali. files: Misc/NEWS | 3 +++ Modules/signalmodule.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12060: Use sig_atomic_t type and volatile keyword in the signal + module. Patch written by Charles-Fran?ois Natali. + - Issue #12044: Fixed subprocess.Popen when used as a context manager to wait for the process to end when exiting the context to avoid unintentionally leaving zombie processes around. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -80,12 +80,12 @@ static pid_t main_pid; #endif -static struct { - int tripped; +static volatile struct { + sig_atomic_t tripped; PyObject *func; } Handlers[NSIG]; -static sig_atomic_t wakeup_fd = -1; +static volatile sig_atomic_t wakeup_fd = -1; /* Speed up sigcheck() when none tripped */ static volatile sig_atomic_t is_tripped = 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 10:28:00 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 15 May 2011 10:28:00 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #12060: Use sig_atomic_t type and volatile keyword in the Message-ID: http://hg.python.org/cpython/rev/1aa48391da30 changeset: 70139:1aa48391da30 parent: 70136:c2515cb23d9b parent: 70138:b74999f561ca user: Victor Stinner date: Sun May 15 10:27:49 2011 +0200 summary: (Merge 3.2) Issue #12060: Use sig_atomic_t type and volatile keyword in the signal module. Patch written by Charles-Fran?ois Natali. files: Misc/NEWS | 3 +++ Modules/signalmodule.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12060: Use sig_atomic_t type and volatile keyword in the signal + module. Patch written by Charles-Fran?ois Natali. + - Added the if_nameindex, if_indextoname, if_nametoindex methods to the socket module as requested in issue #1746656. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -88,12 +88,12 @@ static pid_t main_pid; #endif -static struct { - int tripped; +static volatile struct { + sig_atomic_t tripped; PyObject *func; } Handlers[NSIG]; -static sig_atomic_t wakeup_fd = -1; +static volatile sig_atomic_t wakeup_fd = -1; /* Speed up sigcheck() when none tripped */ static volatile sig_atomic_t is_tripped = 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 10:43:03 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 15 May 2011 10:43:03 +0200 Subject: [Python-checkins] cpython (3.2): Fix-up NEWS: entries made after 3.2.1b1 go into the 3.2.1c1 section. Message-ID: http://hg.python.org/cpython/rev/b57537094ddc changeset: 70140:b57537094ddc branch: 3.2 parent: 70130:a3b76b14864a user: Georg Brandl date: Sun May 15 09:49:19 2011 +0200 summary: Fix-up NEWS: entries made after 3.2.1b1 go into the 3.2.1c1 section. files: Misc/NEWS | 111 ++++++++++++++++++++++++----------------- 1 files changed, 66 insertions(+), 45 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,10 +2,10 @@ Python News +++++++++++ -What's New in Python 3.2.1 beta 1? -================================== - -*Release date: 08-May-2011* +What's New in Python 3.2.1 release candidate 1? +=============================================== + +*Release date: XX-XXX-2011* Core and Builtins ----------------- @@ -17,6 +17,68 @@ - Issue #1195: Fix input() if it is interrupted by CTRL+d and then CTRL+c, clear the end-of-file indicator after CTRL+d. +Library +------- + +- Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. + +- Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and + their incremental counterparts now raise OverflowError if given an input + larger than 4GB, instead of silently truncating the input and returning + an incorrect result. + +- Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail + attribute when called without a max_length argument. + +- Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence + on a file opened in read+write mode (namely: reading, seeking a bit forward, + writing, then seeking before the previous write but still within buffered + data, and writing again). + +- Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. + With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused + IDLE to exit. Converted to valid Unicode null in PythonCmd(). + +- Issue #11169: compileall module uses repr() to format filenames and paths to + escape surrogate characters and show spaces. + +- Issue #10419, #6011: build_scripts command of distutils handles correctly + non-ASCII path (path to the Python executable). Open and write the script in + binary mode, but ensure that the shebang is decodable from UTF-8 and from the + encoding of the script. + +- Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in + order to accept exactly one connection. Patch by Daniel Evers. + +- Issue #11164: Stop trying to use _xmlplus in the xml module. + +Build +----- + +- Issue #11347: Use --no-as-needed when linking libpython3.so. + +Tools/Demos +----------- + +- Issue #11996: libpython (gdb), replace "py-bt" command by "py-bt-full" and + add a smarter "py-bt" command printing a classic Python traceback. + +Tests +----- + +- Issue #5723: Improve json tests to be executed with and without accelerations. + +- Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. + + +What's New in Python 3.2.1 beta 1? +================================== + +*Release date: 08-May-2011* + +Core and Builtins +----------------- + - Issue #1856: Avoid crashes and lockups when daemon threads run while the interpreter is shutting down; instead, these threads are now killed when they try to take the GIL. @@ -90,36 +152,6 @@ Library ------- -- Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and - their incremental counterparts now raise OverflowError if given an input - larger than 4GB, instead of silently truncating the input and returning - an incorrect result. - -- Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail - attribute when called without a max_length argument. - -- Issue #12062: Fix a flushing bug when doing a certain type of I/O sequence - on a file opened in read+write mode (namely: reading, seeking a bit forward, - writing, then seeking before the previous write but still within buffered - data, and writing again). - -- Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. - With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused - IDLE to exit. Converted to valid Unicode null in PythonCmd(). - -- Issue #11169: compileall module uses repr() to format filenames and paths to - escape surrogate characters and show spaces. - -- Issue #10419, #6011: build_scripts command of distutils handles correctly - non-ASCII path (path to the Python executable). Open and write the script in - binary mode, but ensure that the shebang is decodable from UTF-8 and from the - encoding of the script. - -- Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in - order to accept exactly one connection. Patch by Daniel Evers. - -- Issue #11164: Stop trying to use _xmlplus in the xml module. - - Issue #11927: SMTP_SSL now uses port 465 by default as documented. Patch by Kasun Herath. @@ -351,8 +383,6 @@ Build ----- -- Issue #11347: Use --no-as-needed when linking libpython3.so. - - Issue #11411: Fix 'make DESTDIR=' with a relative destination. - Issue #11268: Prevent Mac OS X Installer failure if Documentation package had @@ -367,9 +397,6 @@ Tools/Demos ----------- -- Issue #11996: libpython (gdb), replace "py-bt" command by "py-bt-full" and - add a smarter "py-bt" command printing a classic Python traceback. - - Issue #11179: Make ccbench work under Python 3.1 and 2.7 again. Extension Modules @@ -387,8 +414,6 @@ Tests ----- -- Issue #5723: Improve json tests to be executed with and without accelerations. - - Issue #11873: Change regex in test_compileall to fix occasional failures when when the randomly generated temporary path happened to match the regex. @@ -660,8 +685,6 @@ Library ------- -- Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. - - Issue #10916: mmap should not segfault when a file is mapped using 0 as length and a non-zero offset, and an attempt to read past the end of file is made (IndexError is raised instead). Patch by Ross Lagerwall. @@ -877,8 +900,6 @@ Tests ----- -- Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. - - Fix test_startfile to wait for child process to terminate before finishing. - Issue #10822: Fix test_posix:test_getgroups failure under Solaris. Patch -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 10:43:04 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 15 May 2011 10:43:04 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> 3.2): Branch merge. Message-ID: http://hg.python.org/cpython/rev/bad5c22ff1a4 changeset: 70141:bad5c22ff1a4 branch: 3.2 parent: 70140:b57537094ddc parent: 70138:b74999f561ca user: Georg Brandl date: Sun May 15 10:42:56 2011 +0200 summary: Branch merge. files: Doc/c-api/veryhigh.rst | 11 ++++++----- Misc/NEWS | 3 +++ Modules/signalmodule.c | 6 +++--- Python/pythonrun.c | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -34,11 +34,12 @@ according to the user's locale). It is important to note that the argument list may be modified (but the contents of the strings pointed to by the argument list are not). The return value will be - the integer passed to the :func:`sys.exit` function, ``1`` if the - interpreter exits due to an exception, or ``2`` if the parameter - list does not represent a valid Python command line. + ```0``` if the interpreter exits normally (ie, without an + exception), ``1`` if the interpreter exits due to an exception, or + ``2`` if the parameter list does not represent a valid Python + command line. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``1``, but exit the process, as long as ``Py_InspectFlag`` is not set. @@ -85,7 +86,7 @@ there was an error, there is no way to get the exception information. For the meaning of *flags*, see below. - Note that if an otherwise unhandled :exc:`SystemError` is raised, this + Note that if an otherwise unhandled :exc:`SystemExit` is raised, this function will not return ``-1``, but exit the process, as long as ``Py_InspectFlag`` is not set. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12060: Use sig_atomic_t type and volatile keyword in the signal + module. Patch written by Charles-Fran?ois Natali. + - Issue #12044: Fixed subprocess.Popen when used as a context manager to wait for the process to end when exiting the context to avoid unintentionally leaving zombie processes around. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -80,12 +80,12 @@ static pid_t main_pid; #endif -static struct { - int tripped; +static volatile struct { + sig_atomic_t tripped; PyObject *func; } Handlers[NSIG]; -static sig_atomic_t wakeup_fd = -1; +static volatile sig_atomic_t wakeup_fd = -1; /* Speed up sigcheck() when none tripped */ static volatile sig_atomic_t is_tripped = 0; diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -80,7 +80,7 @@ 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_InspectFlag; /* Needed to determine whether to exit at SystemExit */ int Py_NoSiteFlag; /* Suppress 'import site' */ int Py_BytesWarningFlag; /* Warn on str(bytes) and str(buffer) */ int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.py[co]) */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 13:28:06 2011 From: python-checkins at python.org (nadeem.vawda) Date: Sun, 15 May 2011 13:28:06 +0200 Subject: [Python-checkins] cpython: Fix _socket compilation failures on non-Linux buildbots (cf. issue #1746656). Message-ID: http://hg.python.org/cpython/rev/434dfe42fde1 changeset: 70142:434dfe42fde1 parent: 70139:1aa48391da30 user: Nadeem Vawda date: Sun May 15 13:16:22 2011 +0200 summary: Fix _socket compilation failures on non-Linux buildbots (cf. issue #1746656). files: Modules/socketmodule.h | 5 ++++- configure | 2 +- configure.in | 2 +- pyconfig.h.in | 3 +++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -59,9 +59,12 @@ #include #endif +#ifdef HAVE_NET_IF_H +# include +#endif + #ifdef HAVE_NETPACKET_PACKET_H # include -# include # include #endif diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6037,7 +6037,7 @@ sys/param.h sys/poll.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ sys/stat.h sys/termio.h sys/time.h \ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ -libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ +libutil.h sys/resource.h net/if.h netpacket/packet.h sysexits.h bluetooth.h \ bluetooth/bluetooth.h linux/tipc.h spawn.h util.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -1293,7 +1293,7 @@ sys/param.h sys/poll.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ sys/stat.h sys/termio.h sys/time.h \ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ -libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ +libutil.h sys/resource.h net/if.h netpacket/packet.h sysexits.h bluetooth.h \ bluetooth/bluetooth.h linux/tipc.h spawn.h util.h) AC_HEADER_DIRENT AC_HEADER_MAJOR diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -539,6 +539,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NETPACKET_PACKET_H +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_H + /* Define to 1 if you have the `nice' function. */ #undef HAVE_NICE -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 17:14:10 2011 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 15 May 2011 17:14:10 +0200 Subject: [Python-checkins] cpython (2.7): Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in Message-ID: http://hg.python.org/cpython/rev/9874f213edb2 changeset: 70143:9874f213edb2 branch: 2.7 parent: 70135:97a75fccd7c8 user: Ronald Oussoren date: Sun May 15 16:44:27 2011 +0200 summary: Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in shell. Without this patch python will fail to start properly when the environment variable MACOSX_DEPLOYMENT_TARGET is set on MacOSX and has a value that is not compatible with the value during Python's build. This is caused by code in sysconfig that was only meant to be used in disutils. files: Lib/distutils/sysconfig.py | 2 +- Lib/distutils/tests/test_build_ext.py | 56 ++++++++++++++- Lib/distutils/util.py | 4 +- Lib/sysconfig.py | 19 +---- Lib/test/test_sysconfig.py | 50 ++++++++++++- 5 files changed, 105 insertions(+), 26 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -389,7 +389,7 @@ cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') if cur_target == '': cur_target = cfg_target - os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) + os.environ['MACOSX_DEPLOYMENT_TARGET'] = cfg_target elif map(int, cfg_target.split('.')) > map(int, cur_target.split('.')): my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" during configure' % (cur_target, cfg_target)) diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -3,12 +3,13 @@ import tempfile import shutil from StringIO import StringIO +import textwrap from distutils.core import Extension, Distribution from distutils.command.build_ext import build_ext from distutils import sysconfig from distutils.tests import support -from distutils.errors import DistutilsSetupError +from distutils.errors import DistutilsSetupError, CompileError import unittest from test import test_support @@ -430,6 +431,59 @@ wanted = os.path.join(cmd.build_lib, 'UpdateManager', 'fdsend' + ext) self.assertEqual(ext_path, wanted) + @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX') + def test_deployment_target(self): + self._try_compile_deployment_target() + + orig_environ = os.environ + os.environ = orig_environ.copy() + self.addCleanup(setattr, os, 'environ', orig_environ) + + os.environ['MACOSX_DEPLOYMENT_TARGET']='10.1' + self._try_compile_deployment_target() + + + def _try_compile_deployment_target(self): + deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c') + + with open(deptarget_c, 'w') as fp: + fp.write(textwrap.dedent('''\ + #include + + int dummy; + + #if TARGET != MAC_OS_X_VERSION_MIN_REQUIRED + #error "Unexpected target" + #endif + + ''')) + + target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') + target = tuple(map(int, target.split('.'))) + target = '%02d%01d0' % target + + deptarget_ext = Extension( + 'deptarget', + [deptarget_c], + extra_compile_args=['-DTARGET=%s'%(target,)], + ) + dist = Distribution({ + 'name': 'deptarget', + 'ext_modules': [deptarget_ext] + }) + dist.package_dir = self.tmp_dir + cmd = build_ext(dist) + cmd.build_lib = self.tmp_dir + cmd.build_temp = self.tmp_dir + + try: + old_stdout = sys.stdout + cmd.ensure_finalized() + cmd.run() + + except CompileError: + self.fail("Wrong deployment target during compilation") + def test_suite(): return unittest.makeSuite(BuildExtTestCase) diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -97,9 +97,7 @@ from distutils.sysconfig import get_config_vars cfgvars = get_config_vars() - macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET') - if not macver: - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') + macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') if 1: # Always calculate the release of the running machine, diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -297,21 +297,6 @@ msg = msg + " (%s)" % e.strerror raise IOError(msg) - # On MacOSX we need to check the setting of the environment variable - # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so - # it needs to be compatible. - # If it isn't set we set it to the configure-time value - if sys.platform == 'darwin' and 'MACOSX_DEPLOYMENT_TARGET' in vars: - cfg_target = vars['MACOSX_DEPLOYMENT_TARGET'] - cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') - if cur_target == '': - cur_target = cfg_target - os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) - elif map(int, cfg_target.split('.')) > map(int, cur_target.split('.')): - msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" ' - 'during configure' % (cur_target, cfg_target)) - raise IOError(msg) - # On AIX, there are wrong paths to the linker scripts in the Makefile # -- these paths are relative to the Python source, but when installed # the scripts are in another directory. @@ -616,9 +601,7 @@ # machine is going to compile and link as if it were # MACOSX_DEPLOYMENT_TARGET. cfgvars = get_config_vars() - macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET') - if not macver: - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') + macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') if 1: # Always calculate the release of the running machine, diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -141,7 +141,7 @@ ('Darwin Kernel Version 8.11.1: ' 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'PowerPC')) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' '-fwrapv -O3 -Wall -Wstrict-prototypes') @@ -161,7 +161,6 @@ 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' '-fwrapv -O3 -Wall -Wstrict-prototypes') @@ -176,7 +175,7 @@ sys.maxint = maxint # macbook with fat binaries (fat, universal or fat64) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.4' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -265,6 +264,51 @@ user_path = get_path(name, 'posix_user') self.assertEqual(user_path, global_path.replace(base, user)) + @unittest.skipUnless(sys.platform == "darwin", "test only relevant on MacOSX") + def test_platform_in_subprocess(self): + my_platform = sysconfig.get_platform() + + # Test without MACOSX_DEPLOYMENT_TARGET in the environment + + env = os.environ.copy() + if 'MACOSX_DEPLOYMENT_TARGET' in env: + del env['MACOSX_DEPLOYMENT_TARGET'] + + with open('/dev/null', 'w') as devnull_fp: + p = subprocess.Popen([ + sys.executable, '-c', + 'import sysconfig; print(sysconfig.get_platform())', + ], + stdout=subprocess.PIPE, + stderr=devnull_fp, + env=env) + test_platform = p.communicate()[0].strip() + test_platform = test_platform.decode('utf-8') + status = p.wait() + + self.assertEqual(status, 0) + self.assertEqual(my_platform, test_platform) + + + # Test with MACOSX_DEPLOYMENT_TARGET in the environment, and + # using a value that is unlikely to be the default one. + env = os.environ.copy() + env['MACOSX_DEPLOYMENT_TARGET'] = '10.1' + + p = subprocess.Popen([ + sys.executable, '-c', + 'import sysconfig; print(sysconfig.get_platform())', + ], + stdout=subprocess.PIPE, + stderr=open('/dev/null'), + env=env) + test_platform = p.communicate()[0].strip() + test_platform = test_platform.decode('utf-8') + status = p.wait() + + self.assertEqual(status, 0) + self.assertEqual(my_platform, test_platform) + def test_main(): run_unittest(TestSysConfig) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 17:14:11 2011 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 15 May 2011 17:14:11 +0200 Subject: [Python-checkins] cpython (3.2): Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in Message-ID: http://hg.python.org/cpython/rev/5b108229a978 changeset: 70144:5b108229a978 branch: 3.2 parent: 70141:bad5c22ff1a4 user: Ronald Oussoren date: Sun May 15 16:46:11 2011 +0200 summary: Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in shell. Without this patch python will fail to start properly when the environment variable MACOSX_DEPLOYMENT_TARGET is set on MacOSX and has a value that is not compatible with the value during Python's build. This is caused by code in sysconfig that was only meant to be used in disutils. files: Lib/distutils/sysconfig.py | 2 +- Lib/distutils/tests/test_build_ext.py | 62 +++++++++++++++ Lib/distutils/tests/test_util.py | 9 +- Lib/distutils/util.py | 4 +- Lib/sysconfig.py | 20 +---- Lib/test/test_sysconfig.py | 56 ++++++++++++- 6 files changed, 126 insertions(+), 27 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -428,7 +428,7 @@ cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') if cur_target == '': cur_target = cfg_target - os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) + os.environ['MACOSX_DEPLOYMENT_TARGET'] = cfg_target elif [int(x) for x in cfg_target.split('.')] > [int(x) for x in cur_target.split('.')]: my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" during configure' % (cur_target, cfg_target)) diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -2,6 +2,7 @@ import os import shutil from io import StringIO +import textwrap from distutils.core import Distribution from distutils.command.build_ext import build_ext @@ -419,6 +420,67 @@ wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext) self.assertEqual(wanted, path) + + @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX') + def test_deployment_target(self): + self._try_compile_deployment_target() + + orig_environ = os.environ + os.environ = orig_environ.copy() + self.addCleanup(setattr, os, 'environ', orig_environ) + + os.environ['MACOSX_DEPLOYMENT_TARGET']='10.1' + self._try_compile_deployment_target() + + + def _try_compile_deployment_target(self): + deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c') + + with open(deptarget_c, 'w') as fp: + fp.write(textwrap.dedent('''\ + #include + + int dummy; + + #if TARGET != MAC_OS_X_VERSION_MIN_REQUIRED + #error "Unexpected target" + #endif + + ''')) + + target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') + target = tuple(map(int, target.split('.'))) + target = '%02d%01d0' % target + + deptarget_ext = Extension( + 'deptarget', + [deptarget_c], + extra_compile_args=['-DTARGET=%s'%(target,)], + ) + dist = Distribution({ + 'name': 'deptarget', + 'ext_modules': [deptarget_ext] + }) + dist.package_dir = self.tmp_dir + cmd = build_ext(dist) + cmd.build_lib = self.tmp_dir + cmd.build_temp = self.tmp_dir + + try: + old_stdout = sys.stdout + if not support.verbose: + # silence compiler output + sys.stdout = StringIO() + try: + cmd.ensure_finalized() + cmd.run() + finally: + sys.stdout = old_stdout + + except CompileError: + self.fail("Wrong deployment target during compilation") + + def test_suite(): src = _get_source_filename() if not os.path.exists(src): diff --git a/Lib/distutils/tests/test_util.py b/Lib/distutils/tests/test_util.py --- a/Lib/distutils/tests/test_util.py +++ b/Lib/distutils/tests/test_util.py @@ -92,7 +92,7 @@ ('Darwin Kernel Version 8.11.1: ' 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' '-fwrapv -O3 -Wall -Wstrict-prototypes') @@ -105,7 +105,7 @@ sys.maxsize = cursize # macbook with fat binaries (fat, universal or fat64) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.4' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -113,6 +113,10 @@ self.assertEqual(get_platform(), 'macosx-10.4-fat') + os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.1' + self.assertEqual(get_platform(), 'macosx-10.4-fat') + + get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -147,6 +151,7 @@ self.assertEqual(get_platform(), 'macosx-10.4-%s'%(arch,)) + # linux debian sarge os.name = 'posix' sys.version = ('2.3.5 (#1, Jul 4 2007, 17:28:59) ' diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -96,9 +96,7 @@ from distutils.sysconfig import get_config_vars cfgvars = get_config_vars() - macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET') - if not macver: - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') + macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') if 1: # Always calculate the release of the running machine, diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -345,21 +345,6 @@ if hasattr(e, "strerror"): msg = msg + " (%s)" % e.strerror raise IOError(msg) - # On MacOSX we need to check the setting of the environment variable - # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so - # it needs to be compatible. - # If it isn't set we set it to the configure-time value - if sys.platform == 'darwin' and 'MACOSX_DEPLOYMENT_TARGET' in vars: - cfg_target = vars['MACOSX_DEPLOYMENT_TARGET'] - cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') - if cur_target == '': - cur_target = cfg_target - os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) - elif (list(map(int, cfg_target.split('.'))) > - list(map(int, cur_target.split('.')))): - msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" ' - 'during configure' % (cur_target, cfg_target)) - raise IOError(msg) # On AIX, there are wrong paths to the linker scripts in the Makefile # -- these paths are relative to the Python source, but when installed # the scripts are in another directory. @@ -670,10 +655,9 @@ # to. This makes the compatibility story a bit more sane because the # machine is going to compile and link as if it were # MACOSX_DEPLOYMENT_TARGET. + # cfgvars = get_config_vars() - macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET') - if not macver: - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') + macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') if 1: # Always calculate the release of the running machine, diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -142,7 +142,9 @@ ('Darwin Kernel Version 8.11.1: ' 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'PowerPC')) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' + + + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' '-fwrapv -O3 -Wall -Wstrict-prototypes') @@ -162,7 +164,7 @@ 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' '-fwrapv -O3 -Wall -Wstrict-prototypes') @@ -176,7 +178,7 @@ sys.maxsize = maxint # macbook with fat binaries (fat, universal or fat64) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.4' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -291,6 +293,54 @@ self.assertIn(ldflags, ldshared) + @unittest.skipUnless(sys.platform == "darwin", "test only relevant on MacOSX") + def test_platform_in_subprocess(self): + my_platform = sysconfig.get_platform() + + # Test without MACOSX_DEPLOYMENT_TARGET in the environment + + env = os.environ.copy() + if 'MACOSX_DEPLOYMENT_TARGET' in env: + del env['MACOSX_DEPLOYMENT_TARGET'] + + with open('/dev/null', 'w') as devnull_fp: + p = subprocess.Popen([ + sys.executable, '-c', + 'import sysconfig; print(sysconfig.get_platform())', + ], + stdout=subprocess.PIPE, + stderr=devnull_fp, + env=env) + test_platform = p.communicate()[0].strip() + test_platform = test_platform.decode('utf-8') + status = p.wait() + + self.assertEqual(status, 0) + self.assertEqual(my_platform, test_platform) + + + # Test with MACOSX_DEPLOYMENT_TARGET in the environment, and + # using a value that is unlikely to be the default one. + env = os.environ.copy() + env['MACOSX_DEPLOYMENT_TARGET'] = '10.1' + + p = subprocess.Popen([ + sys.executable, '-c', + 'import sysconfig; print(sysconfig.get_platform())', + ], + stdout=subprocess.PIPE, + stderr=open('/dev/null'), + env=env) + test_platform = p.communicate()[0].strip() + test_platform = test_platform.decode('utf-8') + status = p.wait() + + self.assertEqual(status, 0) + self.assertEqual(my_platform, test_platform) + + + + def test_main(): run_unittest(TestSysConfig) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 17:14:12 2011 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 15 May 2011 17:14:12 +0200 Subject: [Python-checkins] cpython (2.7): NEWS entry for fix of issue #9516 Message-ID: http://hg.python.org/cpython/rev/978016199be8 changeset: 70145:978016199be8 branch: 2.7 parent: 70143:9874f213edb2 user: Ronald Oussoren date: Sun May 15 16:51:10 2011 +0200 summary: NEWS entry for fix of issue #9516 files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,9 @@ Library ------- +- Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is + set in shell. + - Issue #12050: zlib.decompressobj().decompress() now clears the unconsumed_tail attribute when called without a max_length argument. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 17:14:13 2011 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 15 May 2011 17:14:13 +0200 Subject: [Python-checkins] cpython (3.2): NEWS entry for fix of issue #9516 Message-ID: http://hg.python.org/cpython/rev/25040a6a68e9 changeset: 70146:25040a6a68e9 branch: 3.2 parent: 70144:5b108229a978 user: Ronald Oussoren date: Sun May 15 16:50:28 2011 +0200 summary: NEWS entry for fix of issue #9516 files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ Library ------- +- Issue #9516: Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET + is set in shell. + - Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. - Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 17:14:13 2011 From: python-checkins at python.org (ronald.oussoren) Date: Sun, 15 May 2011 17:14:13 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (merge from 3.2) Issue #9516: avoid errors in sysconfig when Message-ID: http://hg.python.org/cpython/rev/412d5f2c995f changeset: 70147:412d5f2c995f parent: 70142:434dfe42fde1 parent: 70146:25040a6a68e9 user: Ronald Oussoren date: Sun May 15 17:13:47 2011 +0200 summary: (merge from 3.2) Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in shell. Without this patch python will fail to start properly when the environment variable MACOSX_DEPLOYMENT_TARGET is set on MacOSX and has a value that is not compatible with the value during Python's build. This is caused by code in sysconfig that was only meant to be used in disutils. files: Lib/distutils/sysconfig.py | 2 +- Lib/distutils/tests/test_build_ext.py | 62 +++++++++++++++ Lib/distutils/tests/test_util.py | 9 +- Lib/distutils/util.py | 4 +- Lib/sysconfig.py | 20 +---- Lib/test/test_sysconfig.py | 56 ++++++++++++- Misc/NEWS | 3 + 7 files changed, 129 insertions(+), 27 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -428,7 +428,7 @@ cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') if cur_target == '': cur_target = cfg_target - os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) + os.environ['MACOSX_DEPLOYMENT_TARGET'] = cfg_target elif [int(x) for x in cfg_target.split('.')] > [int(x) for x in cur_target.split('.')]: my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" during configure' % (cur_target, cfg_target)) diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -2,6 +2,7 @@ import os import shutil from io import StringIO +import textwrap from distutils.core import Distribution from distutils.command.build_ext import build_ext @@ -419,6 +420,67 @@ wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext) self.assertEqual(wanted, path) + + @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX') + def test_deployment_target(self): + self._try_compile_deployment_target() + + orig_environ = os.environ + os.environ = orig_environ.copy() + self.addCleanup(setattr, os, 'environ', orig_environ) + + os.environ['MACOSX_DEPLOYMENT_TARGET']='10.1' + self._try_compile_deployment_target() + + + def _try_compile_deployment_target(self): + deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c') + + with open(deptarget_c, 'w') as fp: + fp.write(textwrap.dedent('''\ + #include + + int dummy; + + #if TARGET != MAC_OS_X_VERSION_MIN_REQUIRED + #error "Unexpected target" + #endif + + ''')) + + target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') + target = tuple(map(int, target.split('.'))) + target = '%02d%01d0' % target + + deptarget_ext = Extension( + 'deptarget', + [deptarget_c], + extra_compile_args=['-DTARGET=%s'%(target,)], + ) + dist = Distribution({ + 'name': 'deptarget', + 'ext_modules': [deptarget_ext] + }) + dist.package_dir = self.tmp_dir + cmd = build_ext(dist) + cmd.build_lib = self.tmp_dir + cmd.build_temp = self.tmp_dir + + try: + old_stdout = sys.stdout + if not support.verbose: + # silence compiler output + sys.stdout = StringIO() + try: + cmd.ensure_finalized() + cmd.run() + finally: + sys.stdout = old_stdout + + except CompileError: + self.fail("Wrong deployment target during compilation") + + def test_suite(): src = _get_source_filename() if not os.path.exists(src): diff --git a/Lib/distutils/tests/test_util.py b/Lib/distutils/tests/test_util.py --- a/Lib/distutils/tests/test_util.py +++ b/Lib/distutils/tests/test_util.py @@ -92,7 +92,7 @@ ('Darwin Kernel Version 8.11.1: ' 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' '-fwrapv -O3 -Wall -Wstrict-prototypes') @@ -105,7 +105,7 @@ sys.maxsize = cursize # macbook with fat binaries (fat, universal or fat64) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.4' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -113,6 +113,10 @@ self.assertEqual(get_platform(), 'macosx-10.4-fat') + os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.1' + self.assertEqual(get_platform(), 'macosx-10.4-fat') + + get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -147,6 +151,7 @@ self.assertEqual(get_platform(), 'macosx-10.4-%s'%(arch,)) + # linux debian sarge os.name = 'posix' sys.version = ('2.3.5 (#1, Jul 4 2007, 17:28:59) ' diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -96,9 +96,7 @@ from distutils.sysconfig import get_config_vars cfgvars = get_config_vars() - macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET') - if not macver: - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') + macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') if 1: # Always calculate the release of the running machine, diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -345,21 +345,6 @@ if hasattr(e, "strerror"): msg = msg + " (%s)" % e.strerror raise IOError(msg) - # On MacOSX we need to check the setting of the environment variable - # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so - # it needs to be compatible. - # If it isn't set we set it to the configure-time value - if sys.platform == 'darwin' and 'MACOSX_DEPLOYMENT_TARGET' in vars: - cfg_target = vars['MACOSX_DEPLOYMENT_TARGET'] - cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') - if cur_target == '': - cur_target = cfg_target - os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) - elif (list(map(int, cfg_target.split('.'))) > - list(map(int, cur_target.split('.')))): - msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" ' - 'during configure' % (cur_target, cfg_target)) - raise IOError(msg) # On AIX, there are wrong paths to the linker scripts in the Makefile # -- these paths are relative to the Python source, but when installed # the scripts are in another directory. @@ -670,10 +655,9 @@ # to. This makes the compatibility story a bit more sane because the # machine is going to compile and link as if it were # MACOSX_DEPLOYMENT_TARGET. + # cfgvars = get_config_vars() - macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET') - if not macver: - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') + macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') if 1: # Always calculate the release of the running machine, diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -142,7 +142,9 @@ ('Darwin Kernel Version 8.11.1: ' 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'PowerPC')) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' + + + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' '-fwrapv -O3 -Wall -Wstrict-prototypes') @@ -162,7 +164,7 @@ 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' '-fwrapv -O3 -Wall -Wstrict-prototypes') @@ -176,7 +178,7 @@ sys.maxsize = maxint # macbook with fat binaries (fat, universal or fat64) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.4' + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -291,6 +293,54 @@ self.assertIn(ldflags, ldshared) + @unittest.skipUnless(sys.platform == "darwin", "test only relevant on MacOSX") + def test_platform_in_subprocess(self): + my_platform = sysconfig.get_platform() + + # Test without MACOSX_DEPLOYMENT_TARGET in the environment + + env = os.environ.copy() + if 'MACOSX_DEPLOYMENT_TARGET' in env: + del env['MACOSX_DEPLOYMENT_TARGET'] + + with open('/dev/null', 'w') as devnull_fp: + p = subprocess.Popen([ + sys.executable, '-c', + 'import sysconfig; print(sysconfig.get_platform())', + ], + stdout=subprocess.PIPE, + stderr=devnull_fp, + env=env) + test_platform = p.communicate()[0].strip() + test_platform = test_platform.decode('utf-8') + status = p.wait() + + self.assertEqual(status, 0) + self.assertEqual(my_platform, test_platform) + + + # Test with MACOSX_DEPLOYMENT_TARGET in the environment, and + # using a value that is unlikely to be the default one. + env = os.environ.copy() + env['MACOSX_DEPLOYMENT_TARGET'] = '10.1' + + p = subprocess.Popen([ + sys.executable, '-c', + 'import sysconfig; print(sysconfig.get_platform())', + ], + stdout=subprocess.PIPE, + stderr=open('/dev/null'), + env=env) + test_platform = p.communicate()[0].strip() + test_platform = test_platform.decode('utf-8') + status = p.wait() + + self.assertEqual(status, 0) + self.assertEqual(my_platform, test_platform) + + + + def test_main(): run_unittest(TestSysConfig) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -153,6 +153,9 @@ Library ------- +- Issue #9516: Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET + is set in shell. + - Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and their incremental counterparts now raise OverflowError if given an input larger than 4GB, instead of silently truncating the input and returning -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 19:02:39 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 15 May 2011 19:02:39 +0200 Subject: [Python-checkins] cpython (3.1): Issue #10756: atexit normalizes the exception before displaying it. Patch by Message-ID: http://hg.python.org/cpython/rev/461e37a60187 changeset: 70148:461e37a60187 branch: 3.1 parent: 70137:945ca78c38b1 user: Victor Stinner date: Sun May 15 18:57:44 2011 +0200 summary: Issue #10756: atexit normalizes the exception before displaying it. Patch by Andreas St?hrk. Backport a fix already applied to Python 3.2+ (4a82be47a948 + 5060a92a8597). files: Lib/test/test_atexit.py | 8 ++++++++ Misc/NEWS | 3 +++ Modules/atexitmodule.c | 1 + 3 files changed, 12 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_atexit.py b/Lib/test/test_atexit.py --- a/Lib/test/test_atexit.py +++ b/Lib/test/test_atexit.py @@ -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(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,6 +72,9 @@ Library ------- +- Issue #10756: atexit normalizes the exception before displaying it. Patch by + Andreas St?hrk. + - Issue #8650: Make zlib module 64-bit clean. compress(), decompress() and their incremental counterparts now raise OverflowError if given an input larger than 4GB, instead of silently truncating the input and returning diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c --- a/Modules/atexitmodule.c +++ b/Modules/atexitmodule.c @@ -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); } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 19:02:40 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 15 May 2011 19:02:40 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): Null merge 3.1 (fix already applied: 4a82be47a948+5060a92a8597). Message-ID: http://hg.python.org/cpython/rev/5a210973c310 changeset: 70149:5a210973c310 branch: 3.2 parent: 70146:25040a6a68e9 parent: 70148:461e37a60187 user: Victor Stinner date: Sun May 15 18:59:29 2011 +0200 summary: Null merge 3.1 (fix already applied: 4a82be47a948+5060a92a8597). files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 19:02:41 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 15 May 2011 19:02:41 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Null merge 3.2 (fix already applied: 4a82be47a948+5060a92a8597). Message-ID: http://hg.python.org/cpython/rev/c348e870d686 changeset: 70150:c348e870d686 parent: 70147:412d5f2c995f parent: 70149:5a210973c310 user: Victor Stinner date: Sun May 15 19:02:34 2011 +0200 summary: Null merge 3.2 (fix already applied: 4a82be47a948+5060a92a8597). files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 15 21:18:36 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 15 May 2011 21:18:36 +0200 Subject: [Python-checkins] cpython: issue #1746656: Fix for OS X. configure and #include changes so that the socket Message-ID: http://hg.python.org/cpython/rev/b6aafb20e5f5 changeset: 70151:b6aafb20e5f5 user: Gregory P. Smith date: Sun May 15 12:18:23 2011 -0700 summary: issue #1746656: Fix for OS X. configure and #include changes so that the socket module compiles again on OS X with its more annoying #include requirements. files: Modules/socketmodule.c | 8 ++++++++ configure | 30 +++++++++++++++++++++++++++++- configure.in | 19 ++++++++++++++++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -256,6 +256,14 @@ #include #endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NET_IF_H +#include +#endif + /* Generic socket object definitions and includes */ #define PySocket_BUILDING_SOCKET #include "socketmodule.h" diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6037,7 +6037,7 @@ sys/param.h sys/poll.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ sys/stat.h sys/termio.h sys/time.h \ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ -libutil.h sys/resource.h net/if.h netpacket/packet.h sysexits.h bluetooth.h \ +libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ bluetooth/bluetooth.h linux/tipc.h spawn.h util.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` @@ -6260,6 +6260,34 @@ fi +# On Darwin (OS X) net/if.h requires sys/socket.h to be imported first. +for ac_header in net/if.h +do : + ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +" +if test "x$ac_cv_header_net_if_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NET_IF_H 1 +_ACEOF + +fi + +done + + + # On Solaris, term.h requires curses.h for ac_header in term.h do : diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -1293,11 +1293,28 @@ sys/param.h sys/poll.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ sys/stat.h sys/termio.h sys/time.h \ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ -libutil.h sys/resource.h net/if.h netpacket/packet.h sysexits.h bluetooth.h \ +libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ bluetooth/bluetooth.h linux/tipc.h spawn.h util.h) AC_HEADER_DIRENT AC_HEADER_MAJOR +# On Darwin (OS X) net/if.h requires sys/socket.h to be imported first. +AC_CHECK_HEADERS([net/if.h], [], [], +[#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +]) + + # On Solaris, term.h requires curses.h AC_CHECK_HEADERS(term.h,,,[ #ifdef HAVE_CURSES_H -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon May 16 04:59:53 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 16 May 2011 04:59:53 +0200 Subject: [Python-checkins] Daily reference leaks (b6aafb20e5f5): sum=323 Message-ID: results for b6aafb20e5f5 on branch "default" -------------------------------------------- test_pydoc leaked [323, 0, 0] references, sum=323 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogmZbni5', '-x'] From ezio.melotti at gmail.com Mon May 16 05:14:25 2011 From: ezio.melotti at gmail.com (Ezio Melotti) Date: Mon, 16 May 2011 06:14:25 +0300 Subject: [Python-checkins] cpython: Issue #1746656: Add if_nameindex, if_nametoindex, if_indextoname In-Reply-To: References: Message-ID: <4DD09691.2000604@gmail.com> Hi, On 15/05/2011 10.27, gregory.p.smith wrote: > http://hg.python.org/cpython/rev/c2515cb23d9b > changeset: 70136:c2515cb23d9b > parent: 70134:94e3c44b0662 > user: Gregory P. Smith > date: Sun May 15 00:26:45 2011 -0700 > summary: > Issue #1746656: Add if_nameindex, if_nametoindex, if_indextoname > methods to the socket module. > > files: > Doc/library/socket.rst | 33 + > Lib/test/test_socket.py | 10 + > Misc/NEWS | 3 + > Modules/socketmodule.c | 110 +++++ > configure | 523 ++++++++++++++------------- > configure.in | 1 + > pyconfig.h.in | 3 + > 7 files changed, 432 insertions(+), 251 deletions(-) > > > diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst > --- a/Doc/library/socket.rst > +++ b/Doc/library/socket.rst > @@ -536,6 +536,39 @@ > .. versionadded:: 3.3 > > > +.. function:: if_nameindex() > + > + Returns a list of network interface information > + (index, name as a byte string) tuples. This should be 'Return' (ditto for the next two functions). I assume index is an int and 'as a byte string' refers only to the name, but saying something like "(index as an int, name as a byte string)" would make this clearer IMHO. > + :exc:`socket.error` if the system call fails for any reason. "Raise :exc:`socket.error` if ..." (ditto for the next two). The "for any reason" is probably unnecessary. > + > + Availability: Unix. > + > + .. versionadded:: 3.3 > + > + > +.. function:: if_nametoindex(if_name) > + > + Returns a network interface index number corresponding to an > + interface name byte string. I would say "an interface name as a byte string", otherwise this can be parsed as "the byte string of the interface name", "the name byte string of the interface" or even "the string of the interface name byte". On the other hand 'as a byte string' might also refer to the returned index so maybe something like this is better: "Return the network interface index number corresponding to the interface name *if_name*. *if_name* must be a byte string." > + :exc:`socket.error` if no interface with the given name exists. > + > + Availability: Unix. > + > + .. versionadded:: 3.3 > + > + > +.. function:: if_indextoname(if_index) > + > + Returns a network interface name byte string corresponding to a > + interface index. > + :exc:`socket.error` if no interface with the given index exists. > + > + Availability: Unix. > + > + .. versionadded:: 3.3 > + > + > .. data:: SocketType > > This is a Python type object that represents the socket object type. It is the > diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py > --- a/Lib/test/test_socket.py > +++ b/Lib/test/test_socket.py > @@ -372,6 +372,16 @@ > finally: > socket.sethostname(oldhn) > > + @unittest.skipUnless(hasattr(socket, 'if_nameindex'), > + 'socket.if_nameindex() not available.') > + def testInterfaceNameIndex(self): > + interfaces = socket.if_nameindex() > + for index, name in interfaces: > + # interface indices are non-zero integers > + self.assertGreater(index, 0) > + self.assertEqual(index, socket.if_nametoindex(name)) > + self.assertEqual(name, socket.if_indextoname(index)) > + A test for the error conditions should be added too. > def testRefCountGetNameInfo(self): > # Testing reference count for getnameinfo > if hasattr(sys, "getrefcount"): > diff --git a/Misc/NEWS b/Misc/NEWS > --- a/Misc/NEWS > +++ b/Misc/NEWS > @@ -10,6 +10,9 @@ > Core and Builtins > ----------------- > > +- Added the if_nameindex, if_indextoname, if_nametoindex methods to > + the socket module as requested in issue #1746656. > + This should be in the form "- Issue #NNNN: description". > - Issue #12044: Fixed subprocess.Popen when used as a context manager to > wait for the process to end when exiting the context to avoid unintentionally > leaving zombie processes around. > diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c > --- a/Modules/socketmodule.c > +++ b/Modules/socketmodule.c > @@ -42,6 +42,9 @@ > - socket.inet_ntoa(packed IP) -> IP address string > - socket.getdefaulttimeout() -> None | float > - socket.setdefaulttimeout(None | float) > +- socket.if_nameindex() -> list of tuples (if_index, if_name) > +- socket.if_nametoindex(name) -> corresponding interface index > +- socket.if_indextoname(index) -> corresponding interface name > - an Internet socket address is a pair (hostname, port) > where hostname can be anything recognized by gethostbyname() > (including the dd.dd.dd.dd notation) and port is in host byte order > @@ -133,6 +136,9 @@ > setsockopt(level, optname, value) -- set socket options\n\ > settimeout(None | float) -- set or clear the timeout\n\ > shutdown(how) -- shut down traffic in one or both directions\n\ > +if_nameindex() -- return all network interface indices and names\n\ > +if_nametoindex(name) -- returns the corresponding interface index\n\ > +if_indextoname(index) -- returns the corresponding interface name\n\ s/returns/return/g > \n\ > [*] not available on all platforms!"); > > @@ -4267,6 +4273,102 @@ > When the socket module is first imported, the default is None."); > > > +#ifdef HAVE_IF_NAMEINDEX > +/* Python API for getting interface indices and names */ > + > +static PyObject * > +socket_if_nameindex(PyObject *self, PyObject *arg) > +{ > + int i = 0; > + PyObject *list; > + struct if_nameindex *ni = if_nameindex(); > + > + if (ni == NULL) { > + PyErr_SetString(socket_error, "if_nameindex() returned NULL."); Wouldn't something like "An error occurred in if_nameindex()." be better? Returning NULL is just an implementation detail that people might not be aware of. > + return NULL; > + } > + > + list = PyList_New(0); > + if (list == NULL) { > + if_freenameindex(ni); > + return NULL; > + } > + > + while (ni[i].if_index != 0&& i< INT_MAX) { > + PyObject *ni_tuple = Py_BuildValue( > + "Iy", ni[i].if_index, ni[i].if_name); > + > + if (ni_tuple == NULL || PyList_Append(list, ni_tuple) == -1) { > + Py_XDECREF(ni_tuple); > + goto error; > + } > + Py_DECREF(ni_tuple); > + > + ++i; > + } > + > + if_freenameindex(ni); > + return list; > + > +error: > + Py_DECREF(list); > + if_freenameindex(ni); > + return NULL; > +} > + > +PyDoc_STRVAR(if_nameindex_doc, > +"if_nameindex()\n\ > +\n\ > +Returns a list of network interface information (index, name) tuples."); s/Returns/Return/ > + > + > +PyObject* > +socket_if_nametoindex(PyObject *self, PyObject *arg) > +{ > + char* ifname = PyBytes_AsString(arg); > + unsigned long index; > + > + if (ifname == NULL) > + return NULL; > + > + index = if_nametoindex(ifname); > + if (index == 0) { > + PyErr_SetString(socket_error, "no interface with this name"); > + return NULL; > + } > + > + return PyLong_FromUnsignedLong(index); > +} > + > +PyDoc_STRVAR(if_nametoindex_doc, > +"if_nametoindex(if_name)\n\ > +\n\ > +Returns the interface index corresponding to the interface name if_name."); Ditto. > + > + > +PyObject* > +socket_if_indextoname(PyObject *self, PyObject *arg) > +{ > + unsigned long index = PyLong_AsUnsignedLongMask(arg); > + char name[IF_NAMESIZE + 1]; /* or use IFNAMSIZ ?*/ > + char *ret = if_indextoname(index,&name[0]); > + > + if (ret == NULL) { > + PyErr_SetString(socket_error, "no interface with this index"); > + return NULL; > + } > + > + return PyBytes_FromString(name); > +} > + > +PyDoc_STRVAR(if_indextoname_doc, > +"if_indextoname(if_index)\n\ > +\n\ > +Returns the interface name corresponding to the interface index if_index."); Ditto. > + > +#endif /* HAVE_IF_NAMEINDEX */ > + > + > /* List of functions exported by this module. */ > > static PyMethodDef socket_methods[] = { > @@ -4322,6 +4424,14 @@ > METH_NOARGS, getdefaulttimeout_doc}, > {"setdefaulttimeout", socket_setdefaulttimeout, > METH_O, setdefaulttimeout_doc}, > +#ifdef HAVE_IF_NAMEINDEX > + {"if_nameindex", socket_if_nameindex, > + METH_NOARGS, if_nameindex_doc}, > + {"if_nametoindex", socket_if_nametoindex, > + METH_O, if_nametoindex_doc}, > + {"if_indextoname", socket_if_indextoname, > + METH_O, if_indextoname_doc}, > +#endif > {NULL, NULL} /* Sentinel */ > }; > > diff --git a/configure b/configure > --- a/configure > +++ b/configure > [...] Best Regards, Ezio Melotti From python-checkins at python.org Mon May 16 09:30:00 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 16 May 2011 09:30:00 +0200 Subject: [Python-checkins] peps: Note that the release dir must be group writable. Message-ID: http://hg.python.org/peps/rev/eadba8326d8b changeset: 3881:eadba8326d8b user: Georg Brandl date: Mon May 16 09:29:47 2011 +0200 summary: Note that the release dir must be group writable. files: pep-0101.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0101.txt b/pep-0101.txt --- a/pep-0101.txt +++ b/pep-0101.txt @@ -358,7 +358,8 @@ Python-3.2a1.msi, Python-3.2a1.tgz, Python-3.2a1.tar.bz2, etc. ___ On dinsdale, cd /data/ftp.python.org/pub/python/X.Y[.Z] - creating it if necessary. + creating it if necessary. Make sure it is owned by group 'webmaster' + and group-writable. ___ Move the previous release files to a directory called 'prev' creating the directory if necessary (make sure the directory has -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon May 16 16:35:45 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 16 May 2011 16:35:45 +0200 Subject: [Python-checkins] cpython (3.1): Issue #11614: import __hello__ prints "Hello World!". Patch written by Andreas Message-ID: http://hg.python.org/cpython/rev/44fd95cead7b changeset: 70152:44fd95cead7b branch: 3.1 parent: 70148:461e37a60187 user: Victor Stinner date: Mon May 16 16:29:35 2011 +0200 summary: Issue #11614: import __hello__ prints "Hello World!". Patch written by Andreas St?hrk. files: Lib/test/test_frozen.py | 52 ++++++++++++++++------------ Misc/NEWS | 3 + Python/frozen.c | 19 ++++++---- Tools/freeze/flag.py | 1 + 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_frozen.py b/Lib/test/test_frozen.py --- a/Lib/test/test_frozen.py +++ b/Lib/test/test_frozen.py @@ -6,31 +6,37 @@ class FrozenTests(unittest.TestCase): def test_frozen(self): - try: - import __hello__ - except ImportError as x: - self.fail("import __hello__ failed:" + str(x)) - self.assertEqual(__hello__.initialized, True) - self.assertEqual(len(dir(__hello__)), 6, dir(__hello__)) + with captured_stdout() as stdout: + try: + import __hello__ + except ImportError as x: + self.fail("import __hello__ failed:" + str(x)) + self.assertEqual(__hello__.initialized, True) + self.assertEqual(len(dir(__hello__)), 6, dir(__hello__)) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') - try: - import __phello__ - except ImportError as x: - self.fail("import __phello__ failed:" + str(x)) - self.assertEqual(__phello__.initialized, True) - if not "__phello__.spam" in sys.modules: - self.assertEqual(len(dir(__phello__)), 7, dir(__phello__)) - else: - self.assertEqual(len(dir(__phello__)), 8, dir(__phello__)) - self.assertEqual(__phello__.__path__, [__phello__.__name__]) + with captured_stdout() as stdout: + try: + import __phello__ + except ImportError as x: + self.fail("import __phello__ failed:" + str(x)) + self.assertEqual(__phello__.initialized, True) + if not "__phello__.spam" in sys.modules: + self.assertEqual(len(dir(__phello__)), 7, dir(__phello__)) + else: + self.assertEqual(len(dir(__phello__)), 8, dir(__phello__)) + self.assertEqual(__phello__.__path__, [__phello__.__name__]) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') - try: - import __phello__.spam - except ImportError as x: - self.fail("import __phello__.spam failed:" + str(x)) - self.assertEqual(__phello__.spam.initialized, True) - self.assertEqual(len(dir(__phello__.spam)), 6) - self.assertEqual(len(dir(__phello__)), 8) + with captured_stdout() as stdout: + try: + import __phello__.spam + except ImportError as x: + self.fail("import __phello__.spam failed:" + str(x)) + self.assertEqual(__phello__.spam.initialized, True) + self.assertEqual(len(dir(__phello__.spam)), 6) + self.assertEqual(len(dir(__phello__)), 8) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') try: import __phello__.foo diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -390,6 +390,9 @@ Tests ----- +- Issue #11614: import __hello__ prints "Hello World!". Patch written by + Andreas St?hrk. + - Issue #5723: Improve json tests to be executed with and without accelerations. - Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. diff --git a/Python/frozen.c b/Python/frozen.c --- a/Python/frozen.c +++ b/Python/frozen.c @@ -12,14 +12,17 @@ the appropriate bytes from M___main__.c. */ static unsigned char M___hello__[] = { - 99,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, - 0,64,0,0,0,115,10,0,0,0,100,1,0,90,1,0, - 100,0,0,83,40,2,0,0,0,78,84,40,2,0,0,0, - 117,4,0,0,0,84,114,117,101,117,11,0,0,0,105,110, - 105,116,105,97,108,105,122,101,100,40,0,0,0,0,40,0, - 0,0,0,40,0,0,0,0,117,7,0,0,0,102,108,97, - 103,46,112,121,117,8,0,0,0,60,109,111,100,117,108,101, - 62,1,0,0,0,115,0,0,0,0, + 99,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, + 0,64,0,0,0,115,20,0,0,0,100,2,0,90,1,0, + 101,2,0,100,0,0,131,1,0,1,100,1,0,83,40,3, + 0,0,0,117,12,0,0,0,72,101,108,108,111,32,119,111, + 114,108,100,33,78,84,40,3,0,0,0,117,4,0,0,0, + 84,114,117,101,117,11,0,0,0,105,110,105,116,105,97,108, + 105,122,101,100,117,5,0,0,0,112,114,105,110,116,40,0, + 0,0,0,40,0,0,0,0,40,0,0,0,0,117,7,0, + 0,0,102,108,97,103,46,112,121,117,8,0,0,0,60,109, + 111,100,117,108,101,62,1,0,0,0,115,2,0,0,0,6, + 1, }; #define SIZE (int)sizeof(M___hello__) diff --git a/Tools/freeze/flag.py b/Tools/freeze/flag.py --- a/Tools/freeze/flag.py +++ b/Tools/freeze/flag.py @@ -1,1 +1,2 @@ initialized = True +print("Hello world!") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 16 16:35:46 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 16 May 2011 16:35:46 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (Merge 3.1) Issue #11614: import __hello__ prints "Hello World!". Patch written Message-ID: http://hg.python.org/cpython/rev/2c5736e8a221 changeset: 70153:2c5736e8a221 branch: 3.2 parent: 70149:5a210973c310 parent: 70152:44fd95cead7b user: Victor Stinner date: Mon May 16 16:32:33 2011 +0200 summary: (Merge 3.1) Issue #11614: import __hello__ prints "Hello World!". Patch written by Andreas St?hrk. files: Lib/test/test_frozen.py | 52 ++++++++++++++++------------ Misc/NEWS | 5 ++- Python/frozen.c | 19 ++++++---- Tools/freeze/flag.py | 1 + 4 files changed, 45 insertions(+), 32 deletions(-) diff --git a/Lib/test/test_frozen.py b/Lib/test/test_frozen.py --- a/Lib/test/test_frozen.py +++ b/Lib/test/test_frozen.py @@ -6,31 +6,37 @@ class FrozenTests(unittest.TestCase): def test_frozen(self): - try: - import __hello__ - except ImportError as x: - self.fail("import __hello__ failed:" + str(x)) - self.assertEqual(__hello__.initialized, True) - self.assertEqual(len(dir(__hello__)), 7, dir(__hello__)) + with captured_stdout() as stdout: + try: + import __hello__ + except ImportError as x: + self.fail("import __hello__ failed:" + str(x)) + self.assertEqual(__hello__.initialized, True) + self.assertEqual(len(dir(__hello__)), 7, dir(__hello__)) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') - try: - import __phello__ - except ImportError as x: - self.fail("import __phello__ failed:" + str(x)) - self.assertEqual(__phello__.initialized, True) - if not "__phello__.spam" in sys.modules: - self.assertEqual(len(dir(__phello__)), 8, dir(__phello__)) - else: - self.assertEqual(len(dir(__phello__)), 9, dir(__phello__)) - self.assertEqual(__phello__.__path__, [__phello__.__name__]) + with captured_stdout() as stdout: + try: + import __phello__ + except ImportError as x: + self.fail("import __phello__ failed:" + str(x)) + self.assertEqual(__phello__.initialized, True) + if not "__phello__.spam" in sys.modules: + self.assertEqual(len(dir(__phello__)), 8, dir(__phello__)) + else: + self.assertEqual(len(dir(__phello__)), 9, dir(__phello__)) + self.assertEqual(__phello__.__path__, [__phello__.__name__]) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') - try: - import __phello__.spam - except ImportError as x: - self.fail("import __phello__.spam failed:" + str(x)) - self.assertEqual(__phello__.spam.initialized, True) - self.assertEqual(len(dir(__phello__.spam)), 7) - self.assertEqual(len(dir(__phello__)), 9) + with captured_stdout() as stdout: + try: + import __phello__.spam + except ImportError as x: + self.fail("import __phello__.spam failed:" + str(x)) + self.assertEqual(__phello__.spam.initialized, True) + self.assertEqual(len(dir(__phello__.spam)), 7) + self.assertEqual(len(dir(__phello__)), 9) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') try: import __phello__.foo diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,7 +23,7 @@ Library ------- -- Issue #9516: Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET +- Issue #9516: Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in shell. - Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional. @@ -72,6 +72,9 @@ Tests ----- +- Issue #11614: import __hello__ prints "Hello World!". Patch written by + Andreas St?hrk. + - Issue #5723: Improve json tests to be executed with and without accelerations. - Issue #11910: Fix test_heapq to skip the C tests when _heapq is missing. diff --git a/Python/frozen.c b/Python/frozen.c --- a/Python/frozen.c +++ b/Python/frozen.c @@ -12,14 +12,17 @@ the appropriate bytes from M___main__.c. */ static unsigned char M___hello__[] = { - 99,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, - 0,64,0,0,0,115,10,0,0,0,100,1,0,90,1,0, - 100,0,0,83,40,2,0,0,0,78,84,40,2,0,0,0, - 117,4,0,0,0,84,114,117,101,117,11,0,0,0,105,110, - 105,116,105,97,108,105,122,101,100,40,0,0,0,0,40,0, - 0,0,0,40,0,0,0,0,117,7,0,0,0,102,108,97, - 103,46,112,121,117,8,0,0,0,60,109,111,100,117,108,101, - 62,1,0,0,0,115,0,0,0,0, + 99,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, + 0,64,0,0,0,115,20,0,0,0,100,2,0,90,1,0, + 101,2,0,100,0,0,131,1,0,1,100,1,0,83,40,3, + 0,0,0,117,12,0,0,0,72,101,108,108,111,32,119,111, + 114,108,100,33,78,84,40,3,0,0,0,117,4,0,0,0, + 84,114,117,101,117,11,0,0,0,105,110,105,116,105,97,108, + 105,122,101,100,117,5,0,0,0,112,114,105,110,116,40,0, + 0,0,0,40,0,0,0,0,40,0,0,0,0,117,7,0, + 0,0,102,108,97,103,46,112,121,117,8,0,0,0,60,109, + 111,100,117,108,101,62,1,0,0,0,115,2,0,0,0,6, + 1, }; #define SIZE (int)sizeof(M___hello__) diff --git a/Tools/freeze/flag.py b/Tools/freeze/flag.py --- a/Tools/freeze/flag.py +++ b/Tools/freeze/flag.py @@ -1,1 +1,2 @@ initialized = True +print("Hello world!") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 16 16:35:47 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 16 May 2011 16:35:47 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #11614: import __hello__ prints "Hello World!". Patch written Message-ID: http://hg.python.org/cpython/rev/79c49d2fc768 changeset: 70154:79c49d2fc768 parent: 70151:b6aafb20e5f5 parent: 70153:2c5736e8a221 user: Victor Stinner date: Mon May 16 16:35:35 2011 +0200 summary: (Merge 3.2) Issue #11614: import __hello__ prints "Hello World!". Patch written by Andreas St?hrk. files: Lib/test/test_frozen.py | 52 ++++++++++++++++------------ Misc/NEWS | 3 + Python/frozen.c | 19 ++++++---- Tools/freeze/flag.py | 1 + 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_frozen.py b/Lib/test/test_frozen.py --- a/Lib/test/test_frozen.py +++ b/Lib/test/test_frozen.py @@ -6,31 +6,37 @@ class FrozenTests(unittest.TestCase): def test_frozen(self): - try: - import __hello__ - except ImportError as x: - self.fail("import __hello__ failed:" + str(x)) - self.assertEqual(__hello__.initialized, True) - self.assertEqual(len(dir(__hello__)), 7, dir(__hello__)) + with captured_stdout() as stdout: + try: + import __hello__ + except ImportError as x: + self.fail("import __hello__ failed:" + str(x)) + self.assertEqual(__hello__.initialized, True) + self.assertEqual(len(dir(__hello__)), 7, dir(__hello__)) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') - try: - import __phello__ - except ImportError as x: - self.fail("import __phello__ failed:" + str(x)) - self.assertEqual(__phello__.initialized, True) - if not "__phello__.spam" in sys.modules: - self.assertEqual(len(dir(__phello__)), 8, dir(__phello__)) - else: - self.assertEqual(len(dir(__phello__)), 9, dir(__phello__)) - self.assertEqual(__phello__.__path__, [__phello__.__name__]) + with captured_stdout() as stdout: + try: + import __phello__ + except ImportError as x: + self.fail("import __phello__ failed:" + str(x)) + self.assertEqual(__phello__.initialized, True) + if not "__phello__.spam" in sys.modules: + self.assertEqual(len(dir(__phello__)), 8, dir(__phello__)) + else: + self.assertEqual(len(dir(__phello__)), 9, dir(__phello__)) + self.assertEqual(__phello__.__path__, [__phello__.__name__]) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') - try: - import __phello__.spam - except ImportError as x: - self.fail("import __phello__.spam failed:" + str(x)) - self.assertEqual(__phello__.spam.initialized, True) - self.assertEqual(len(dir(__phello__.spam)), 7) - self.assertEqual(len(dir(__phello__)), 9) + with captured_stdout() as stdout: + try: + import __phello__.spam + except ImportError as x: + self.fail("import __phello__.spam failed:" + str(x)) + self.assertEqual(__phello__.spam.initialized, True) + self.assertEqual(len(dir(__phello__.spam)), 7) + self.assertEqual(len(dir(__phello__)), 9) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') try: import __phello__.foo diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -676,6 +676,9 @@ Tests ----- +- Issue #11614: import __hello__ prints "Hello World!". Patch written by + Andreas St?hrk. + - Issue #5723: Improve json tests to be executed with and without accelerations. - Issue #12041: Make test_wait3 more robust. diff --git a/Python/frozen.c b/Python/frozen.c --- a/Python/frozen.c +++ b/Python/frozen.c @@ -12,14 +12,17 @@ the appropriate bytes from M___main__.c. */ static unsigned char M___hello__[] = { - 99,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, - 0,64,0,0,0,115,10,0,0,0,100,1,0,90,1,0, - 100,0,0,83,40,2,0,0,0,78,84,40,2,0,0,0, - 117,4,0,0,0,84,114,117,101,117,11,0,0,0,105,110, - 105,116,105,97,108,105,122,101,100,40,0,0,0,0,40,0, - 0,0,0,40,0,0,0,0,117,7,0,0,0,102,108,97, - 103,46,112,121,117,8,0,0,0,60,109,111,100,117,108,101, - 62,1,0,0,0,115,0,0,0,0, + 99,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, + 0,64,0,0,0,115,20,0,0,0,100,2,0,90,1,0, + 101,2,0,100,0,0,131,1,0,1,100,1,0,83,40,3, + 0,0,0,117,12,0,0,0,72,101,108,108,111,32,119,111, + 114,108,100,33,78,84,40,3,0,0,0,117,4,0,0,0, + 84,114,117,101,117,11,0,0,0,105,110,105,116,105,97,108, + 105,122,101,100,117,5,0,0,0,112,114,105,110,116,40,0, + 0,0,0,40,0,0,0,0,40,0,0,0,0,117,7,0, + 0,0,102,108,97,103,46,112,121,117,8,0,0,0,60,109, + 111,100,117,108,101,62,1,0,0,0,115,2,0,0,0,6, + 1, }; #define SIZE (int)sizeof(M___hello__) diff --git a/Tools/freeze/flag.py b/Tools/freeze/flag.py --- a/Tools/freeze/flag.py +++ b/Tools/freeze/flag.py @@ -1,1 +1,2 @@ initialized = True +print("Hello world!") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 16 16:50:35 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 16 May 2011 16:50:35 +0200 Subject: [Python-checkins] cpython (3.1): Issue #12057: Convert CJK encoding testcase BLOB into multiple text files Message-ID: http://hg.python.org/cpython/rev/16503022c4b8 changeset: 70155:16503022c4b8 branch: 3.1 parent: 70152:44fd95cead7b user: Victor Stinner date: Mon May 16 16:43:38 2011 +0200 summary: Issue #12057: Convert CJK encoding testcase BLOB into multiple text files files: .hgeol | 1 + Lib/test/cjkencodings/big5-utf8.txt | 9 + Lib/test/cjkencodings/big5.txt | 9 + Lib/test/cjkencodings/big5hkscs-utf8.txt | 2 + Lib/test/cjkencodings/big5hkscs.txt | 2 + Lib/test/cjkencodings/cp949-utf8.txt | 9 + Lib/test/cjkencodings/cp949.txt | 9 + Lib/test/cjkencodings/euc_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/euc_jisx0213.txt | 8 + Lib/test/cjkencodings/euc_jp-utf8.txt | 7 + Lib/test/cjkencodings/euc_jp.txt | 7 + Lib/test/cjkencodings/euc_kr-utf8.txt | 7 + Lib/test/cjkencodings/euc_kr.txt | 7 + Lib/test/cjkencodings/gb18030-utf8.txt | 15 + Lib/test/cjkencodings/gb18030.txt | 15 + Lib/test/cjkencodings/gb2312-utf8.txt | 6 + Lib/test/cjkencodings/gb2312.txt | 6 + Lib/test/cjkencodings/gbk-utf8.txt | 14 + Lib/test/cjkencodings/gbk.txt | 14 + Lib/test/cjkencodings/johab-utf8.txt | 9 + Lib/test/cjkencodings/johab.txt | 9 + Lib/test/cjkencodings/shift_jis-utf8.txt | 7 + Lib/test/cjkencodings/shift_jis.txt | 7 + Lib/test/cjkencodings/shift_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/shift_jisx0213.txt | 8 + Lib/test/cjkencodings_test.py | 1019 ---------- Lib/test/test_multibytecodec_support.py | 17 +- 27 files changed, 215 insertions(+), 1024 deletions(-) diff --git a/.hgeol b/.hgeol --- a/.hgeol +++ b/.hgeol @@ -27,6 +27,7 @@ **.zip = BIN Lib/email/test/data/msg_26.txt = BIN +Lib/test/cjkencodings/* = BIN Lib/test/sndhdrdata/sndhdr.* = BIN Lib/test/decimaltestdata/*.decTest = BIN diff --git a/Lib/test/cjkencodings/big5-utf8.txt b/Lib/test/cjkencodings/big5-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5-utf8.txt @@ -0,0 +1,9 @@ +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/big5.txt b/Lib/test/cjkencodings/big5.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5.txt @@ -0,0 +1,9 @@ +?p???b Python ???????J???? C library? +?@?b???T???????t?o?i??????, ?}?o???????n?????t???O???e?????? +???D. ???[???}?o?????????t??, ?????K?`???????Q???@???w?}?o?n?? +library, ?????@?? fast prototyping ?? programming language ?i +??????. ???e???\?\?h?h?? library ?O?H C ?g??, ?? Python ?O?@?? +fast prototyping ?? programming language. ?G???????????N?J???? +C library ???? Python ?????????????????X. ???????D?n?]?O?????? +?n?Q???????D?N?O: + diff --git a/Lib/test/cjkencodings/big5hkscs-utf8.txt b/Lib/test/cjkencodings/big5hkscs-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs-utf8.txt @@ -0,0 +1,2 @@ +??????????????? +???????? ?????? diff --git a/Lib/test/cjkencodings/big5hkscs.txt b/Lib/test/cjkencodings/big5hkscs.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs.txt @@ -0,0 +1,2 @@ +?E?\?s???? +?f?b?? ???? diff --git a/Lib/test/cjkencodings/cp949-utf8.txt b/Lib/test/cjkencodings/cp949-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/cp949.txt b/Lib/test/cjkencodings/cp949.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949.txt @@ -0,0 +1,9 @@ +?c?????? ???????? + +??????!! ???????????p?? ?????R?????? ???? ???? ??. . +?????????? . . . . ?????? ?????? ???R ! ! !??.?? +?????? ??????????_?? ???? ?????O ???? ?h?????? ?????O +???j ???R . . . . ?????f ???? ???t???O ?????????????? +?????R ! ! ?????? ?????? ?????? ???????? ???????R ?????? +???????? ???????R ???? ??????????????????!! ???????? ????* + diff --git a/Lib/test/cjkencodings/euc_jisx0213-utf8.txt b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt @@ -0,0 +1,8 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + +????????? ?????? ???????????? ???????? ?????????? diff --git a/Lib/test/cjkencodings/euc_jisx0213.txt b/Lib/test/cjkencodings/euc_jisx0213.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213.txt @@ -0,0 +1,8 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + +???? ?? ???????? ????? ????????? diff --git a/Lib/test/cjkencodings/euc_jp-utf8.txt b/Lib/test/cjkencodings/euc_jp-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp-utf8.txt @@ -0,0 +1,7 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + diff --git a/Lib/test/cjkencodings/euc_jp.txt b/Lib/test/cjkencodings/euc_jp.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp.txt @@ -0,0 +1,7 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + diff --git a/Lib/test/cjkencodings/euc_kr-utf8.txt b/Lib/test/cjkencodings/euc_kr-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr-utf8.txt @@ -0,0 +1,7 @@ +??? ?????????(Python)??? ????????? ??????, ????????? ??????????????? ???????????????. ???????????? +???????????? ????????? ????????? ????????? ??????????????? ???????????? ?????????????????????????????? +???????????????. ???????????? ??????(??????)??? ????????? ?????? ?????????, ????????? ??????????????? +????????? ???????????? ??????????????? ?????? ??????????????? ???????????? ?????????????????? ?????? +?????????????????? ????????? ??? ??? ?????? ???????????? ????????? ??????????????????. + +????????????: ????????? ?????????~ ??????! ???????????? ????????????. ???. ????????? ??????. diff --git a/Lib/test/cjkencodings/euc_kr.txt b/Lib/test/cjkencodings/euc_kr.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr.txt @@ -0,0 +1,7 @@ +?? ??????(Python)?? ?????? ????, ?????? ?????????? ??????????. ???????? +???????? ?????? ?????? ?????? ?????????? ???????? ???????????????????? +??????????. ???????? ????(????)?? ?????? ???? ??????, ?????? ?????????? +?????? ???????? ?????????? ???? ?????????? ???????? ???????????? ???? +???????????? ?????? ?? ?? ???? ???????? ?????? ????????????. + +????????: ?????? ??????????????????~ ??????????! ?????????????? ??????????????. ????????. ?????? ??????????. diff --git a/Lib/test/cjkencodings/gb18030-utf8.txt b/Lib/test/cjkencodings/gb18030-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030-utf8.txt @@ -0,0 +1,15 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: +???????????? ????????? ????????? ?????? ?????? ????????? ??????????????? ?????????. + diff --git a/Lib/test/cjkencodings/gb18030.txt b/Lib/test/cjkencodings/gb18030.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030.txt @@ -0,0 +1,15 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: +?5?1?3?3?2?1?3?1 ?7?6?0?4?6?3 ?8?5?8?6?3?5 ?3?1?9?5 ?0?9?3?0 ?4?3?5?7?5?5 ?5?5?0?9?8?9?9?3?0?4 ?2?9?2?5?9?9. + diff --git a/Lib/test/cjkencodings/gb2312-utf8.txt b/Lib/test/cjkencodings/gb2312-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312-utf8.txt @@ -0,0 +1,6 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gb2312.txt b/Lib/test/cjkencodings/gb2312.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312.txt @@ -0,0 +1,6 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gbk-utf8.txt b/Lib/test/cjkencodings/gbk-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk-utf8.txt @@ -0,0 +1,14 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/gbk.txt b/Lib/test/cjkencodings/gbk.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk.txt @@ -0,0 +1,14 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: + diff --git a/Lib/test/cjkencodings/johab-utf8.txt b/Lib/test/cjkencodings/johab-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/johab.txt b/Lib/test/cjkencodings/johab.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab.txt @@ -0,0 +1,9 @@ +???w?b?a ?\?????a + +?????s!! ?g???U???????? ?????z?????? ?w?? ???? ??. . +? 3.2): (Merge 3.1) Issue #12057: Convert CJK encoding testcase BLOB into multiple text Message-ID: http://hg.python.org/cpython/rev/370db8da308f changeset: 70156:370db8da308f branch: 3.2 parent: 70153:2c5736e8a221 parent: 70155:16503022c4b8 user: Victor Stinner date: Mon May 16 16:45:15 2011 +0200 summary: (Merge 3.1) Issue #12057: Convert CJK encoding testcase BLOB into multiple text files files: .hgeol | 1 + Lib/test/cjkencodings/big5-utf8.txt | 9 + Lib/test/cjkencodings/big5.txt | 9 + Lib/test/cjkencodings/big5hkscs-utf8.txt | 2 + Lib/test/cjkencodings/big5hkscs.txt | 2 + Lib/test/cjkencodings/cp949-utf8.txt | 9 + Lib/test/cjkencodings/cp949.txt | 9 + Lib/test/cjkencodings/euc_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/euc_jisx0213.txt | 8 + Lib/test/cjkencodings/euc_jp-utf8.txt | 7 + Lib/test/cjkencodings/euc_jp.txt | 7 + Lib/test/cjkencodings/euc_kr-utf8.txt | 7 + Lib/test/cjkencodings/euc_kr.txt | 7 + Lib/test/cjkencodings/gb18030-utf8.txt | 15 + Lib/test/cjkencodings/gb18030.txt | 15 + Lib/test/cjkencodings/gb2312-utf8.txt | 6 + Lib/test/cjkencodings/gb2312.txt | 6 + Lib/test/cjkencodings/gbk-utf8.txt | 14 + Lib/test/cjkencodings/gbk.txt | 14 + Lib/test/cjkencodings/johab-utf8.txt | 9 + Lib/test/cjkencodings/johab.txt | 9 + Lib/test/cjkencodings/shift_jis-utf8.txt | 7 + Lib/test/cjkencodings/shift_jis.txt | 7 + Lib/test/cjkencodings/shift_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/shift_jisx0213.txt | 8 + Lib/test/cjkencodings_test.py | 1019 ---------- Lib/test/test_multibytecodec_support.py | 17 +- 27 files changed, 215 insertions(+), 1024 deletions(-) diff --git a/.hgeol b/.hgeol --- a/.hgeol +++ b/.hgeol @@ -27,6 +27,7 @@ **.zip = BIN Lib/email/test/data/msg_26.txt = BIN +Lib/test/cjkencodings/* = BIN Lib/test/sndhdrdata/sndhdr.* = BIN Lib/test/decimaltestdata/*.decTest = BIN diff --git a/Lib/test/cjkencodings/big5-utf8.txt b/Lib/test/cjkencodings/big5-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5-utf8.txt @@ -0,0 +1,9 @@ +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/big5.txt b/Lib/test/cjkencodings/big5.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5.txt @@ -0,0 +1,9 @@ +?p???b Python ???????J???? C library? +?@?b???T???????t?o?i??????, ?}?o???????n?????t???O???e?????? +???D. ???[???}?o?????????t??, ?????K?`???????Q???@???w?}?o?n?? +library, ?????@?? fast prototyping ?? programming language ?i +??????. ???e???\?\?h?h?? library ?O?H C ?g??, ?? Python ?O?@?? +fast prototyping ?? programming language. ?G???????????N?J???? +C library ???? Python ?????????????????X. ???????D?n?]?O?????? +?n?Q???????D?N?O: + diff --git a/Lib/test/cjkencodings/big5hkscs-utf8.txt b/Lib/test/cjkencodings/big5hkscs-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs-utf8.txt @@ -0,0 +1,2 @@ +??????????????? +???????? ?????? diff --git a/Lib/test/cjkencodings/big5hkscs.txt b/Lib/test/cjkencodings/big5hkscs.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs.txt @@ -0,0 +1,2 @@ +?E?\?s???? +?f?b?? ???? diff --git a/Lib/test/cjkencodings/cp949-utf8.txt b/Lib/test/cjkencodings/cp949-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/cp949.txt b/Lib/test/cjkencodings/cp949.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949.txt @@ -0,0 +1,9 @@ +?c?????? ???????? + +??????!! ???????????p?? ?????R?????? ???? ???? ??. . +?????????? . . . . ?????? ?????? ???R ! ! !??.?? +?????? ??????????_?? ???? ?????O ???? ?h?????? ?????O +???j ???R . . . . ?????f ???? ???t???O ?????????????? +?????R ! ! ?????? ?????? ?????? ???????? ???????R ?????? +???????? ???????R ???? ??????????????????!! ???????? ????* + diff --git a/Lib/test/cjkencodings/euc_jisx0213-utf8.txt b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt @@ -0,0 +1,8 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + +????????? ?????? ???????????? ???????? ?????????? diff --git a/Lib/test/cjkencodings/euc_jisx0213.txt b/Lib/test/cjkencodings/euc_jisx0213.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213.txt @@ -0,0 +1,8 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + +???? ?? ???????? ????? ????????? diff --git a/Lib/test/cjkencodings/euc_jp-utf8.txt b/Lib/test/cjkencodings/euc_jp-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp-utf8.txt @@ -0,0 +1,7 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + diff --git a/Lib/test/cjkencodings/euc_jp.txt b/Lib/test/cjkencodings/euc_jp.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp.txt @@ -0,0 +1,7 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + diff --git a/Lib/test/cjkencodings/euc_kr-utf8.txt b/Lib/test/cjkencodings/euc_kr-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr-utf8.txt @@ -0,0 +1,7 @@ +??? ?????????(Python)??? ????????? ??????, ????????? ??????????????? ???????????????. ???????????? +???????????? ????????? ????????? ????????? ??????????????? ???????????? ?????????????????????????????? +???????????????. ???????????? ??????(??????)??? ????????? ?????? ?????????, ????????? ??????????????? +????????? ???????????? ??????????????? ?????? ??????????????? ???????????? ?????????????????? ?????? +?????????????????? ????????? ??? ??? ?????? ???????????? ????????? ??????????????????. + +????????????: ????????? ?????????~ ??????! ???????????? ????????????. ???. ????????? ??????. diff --git a/Lib/test/cjkencodings/euc_kr.txt b/Lib/test/cjkencodings/euc_kr.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr.txt @@ -0,0 +1,7 @@ +?? ??????(Python)?? ?????? ????, ?????? ?????????? ??????????. ???????? +???????? ?????? ?????? ?????? ?????????? ???????? ???????????????????? +??????????. ???????? ????(????)?? ?????? ???? ??????, ?????? ?????????? +?????? ???????? ?????????? ???? ?????????? ???????? ???????????? ???? +???????????? ?????? ?? ?? ???? ???????? ?????? ????????????. + +????????: ?????? ??????????????????~ ??????????! ?????????????? ??????????????. ????????. ?????? ??????????. diff --git a/Lib/test/cjkencodings/gb18030-utf8.txt b/Lib/test/cjkencodings/gb18030-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030-utf8.txt @@ -0,0 +1,15 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: +???????????? ????????? ????????? ?????? ?????? ????????? ??????????????? ?????????. + diff --git a/Lib/test/cjkencodings/gb18030.txt b/Lib/test/cjkencodings/gb18030.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030.txt @@ -0,0 +1,15 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: +?5?1?3?3?2?1?3?1 ?7?6?0?4?6?3 ?8?5?8?6?3?5 ?3?1?9?5 ?0?9?3?0 ?4?3?5?7?5?5 ?5?5?0?9?8?9?9?3?0?4 ?2?9?2?5?9?9. + diff --git a/Lib/test/cjkencodings/gb2312-utf8.txt b/Lib/test/cjkencodings/gb2312-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312-utf8.txt @@ -0,0 +1,6 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gb2312.txt b/Lib/test/cjkencodings/gb2312.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312.txt @@ -0,0 +1,6 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gbk-utf8.txt b/Lib/test/cjkencodings/gbk-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk-utf8.txt @@ -0,0 +1,14 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/gbk.txt b/Lib/test/cjkencodings/gbk.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk.txt @@ -0,0 +1,14 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: + diff --git a/Lib/test/cjkencodings/johab-utf8.txt b/Lib/test/cjkencodings/johab-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/johab.txt b/Lib/test/cjkencodings/johab.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab.txt @@ -0,0 +1,9 @@ +???w?b?a ?\?????a + +?????s!! ?g???U???????? ?????z?????? ?w?? ???? ??. . +? default): (Merge 3.2) Issue #12057: Convert CJK encoding testcase BLOB into multiple text Message-ID: http://hg.python.org/cpython/rev/e7daf2acc3a7 changeset: 70157:e7daf2acc3a7 parent: 70154:79c49d2fc768 parent: 70156:370db8da308f user: Victor Stinner date: Mon May 16 16:50:23 2011 +0200 summary: (Merge 3.2) Issue #12057: Convert CJK encoding testcase BLOB into multiple text files files: .hgeol | 5 +- Lib/test/cjkencodings/big5-utf8.txt | 9 + Lib/test/cjkencodings/big5.txt | 9 + Lib/test/cjkencodings/big5hkscs-utf8.txt | 2 + Lib/test/cjkencodings/big5hkscs.txt | 2 + Lib/test/cjkencodings/cp949-utf8.txt | 9 + Lib/test/cjkencodings/cp949.txt | 9 + Lib/test/cjkencodings/euc_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/euc_jisx0213.txt | 8 + Lib/test/cjkencodings/euc_jp-utf8.txt | 7 + Lib/test/cjkencodings/euc_jp.txt | 7 + Lib/test/cjkencodings/euc_kr-utf8.txt | 7 + Lib/test/cjkencodings/euc_kr.txt | 7 + Lib/test/cjkencodings/gb18030-utf8.txt | 15 + Lib/test/cjkencodings/gb18030.txt | 15 + Lib/test/cjkencodings/gb2312-utf8.txt | 6 + Lib/test/cjkencodings/gb2312.txt | 6 + Lib/test/cjkencodings/gbk-utf8.txt | 14 + Lib/test/cjkencodings/gbk.txt | 14 + Lib/test/cjkencodings/johab-utf8.txt | 9 + Lib/test/cjkencodings/johab.txt | 9 + Lib/test/cjkencodings/shift_jis-utf8.txt | 7 + Lib/test/cjkencodings/shift_jis.txt | 7 + Lib/test/cjkencodings/shift_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/shift_jisx0213.txt | 8 + Lib/test/cjkencodings_test.py | 1019 ---------- Lib/test/test_multibytecodec_support.py | 17 +- 27 files changed, 217 insertions(+), 1026 deletions(-) diff --git a/.hgeol b/.hgeol --- a/.hgeol +++ b/.hgeol @@ -27,9 +27,10 @@ **.zip = BIN Lib/email/test/data/msg_26.txt = BIN +Lib/test/cjkencodings/* = BIN +Lib/test/decimaltestdata/*.decTest = BIN +Lib/test/sndhdrdata/sndhdr.* = BIN Lib/test/test_email/data/msg_26.txt = BIN -Lib/test/sndhdrdata/sndhdr.* = BIN -Lib/test/decimaltestdata/*.decTest = BIN # All other files (which presumably are human-editable) are "native". # This must be the last rule! diff --git a/Lib/test/cjkencodings/big5-utf8.txt b/Lib/test/cjkencodings/big5-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5-utf8.txt @@ -0,0 +1,9 @@ +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/big5.txt b/Lib/test/cjkencodings/big5.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5.txt @@ -0,0 +1,9 @@ +?p???b Python ???????J???? C library? +?@?b???T???????t?o?i??????, ?}?o???????n?????t???O???e?????? +???D. ???[???}?o?????????t??, ?????K?`???????Q???@???w?}?o?n?? +library, ?????@?? fast prototyping ?? programming language ?i +??????. ???e???\?\?h?h?? library ?O?H C ?g??, ?? Python ?O?@?? +fast prototyping ?? programming language. ?G???????????N?J???? +C library ???? Python ?????????????????X. ???????D?n?]?O?????? +?n?Q???????D?N?O: + diff --git a/Lib/test/cjkencodings/big5hkscs-utf8.txt b/Lib/test/cjkencodings/big5hkscs-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs-utf8.txt @@ -0,0 +1,2 @@ +??????????????? +???????? ?????? diff --git a/Lib/test/cjkencodings/big5hkscs.txt b/Lib/test/cjkencodings/big5hkscs.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs.txt @@ -0,0 +1,2 @@ +?E?\?s???? +?f?b?? ???? diff --git a/Lib/test/cjkencodings/cp949-utf8.txt b/Lib/test/cjkencodings/cp949-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/cp949.txt b/Lib/test/cjkencodings/cp949.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949.txt @@ -0,0 +1,9 @@ +?c?????? ???????? + +??????!! ???????????p?? ?????R?????? ???? ???? ??. . +?????????? . . . . ?????? ?????? ???R ! ! !??.?? +?????? ??????????_?? ???? ?????O ???? ?h?????? ?????O +???j ???R . . . . ?????f ???? ???t???O ?????????????? +?????R ! ! ?????? ?????? ?????? ???????? ???????R ?????? +???????? ???????R ???? ??????????????????!! ???????? ????* + diff --git a/Lib/test/cjkencodings/euc_jisx0213-utf8.txt b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt @@ -0,0 +1,8 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + +????????? ?????? ???????????? ???????? ?????????? diff --git a/Lib/test/cjkencodings/euc_jisx0213.txt b/Lib/test/cjkencodings/euc_jisx0213.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213.txt @@ -0,0 +1,8 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + +???? ?? ???????? ????? ????????? diff --git a/Lib/test/cjkencodings/euc_jp-utf8.txt b/Lib/test/cjkencodings/euc_jp-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp-utf8.txt @@ -0,0 +1,7 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + diff --git a/Lib/test/cjkencodings/euc_jp.txt b/Lib/test/cjkencodings/euc_jp.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp.txt @@ -0,0 +1,7 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + diff --git a/Lib/test/cjkencodings/euc_kr-utf8.txt b/Lib/test/cjkencodings/euc_kr-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr-utf8.txt @@ -0,0 +1,7 @@ +??? ?????????(Python)??? ????????? ??????, ????????? ??????????????? ???????????????. ???????????? +???????????? ????????? ????????? ????????? ??????????????? ???????????? ?????????????????????????????? +???????????????. ???????????? ??????(??????)??? ????????? ?????? ?????????, ????????? ??????????????? +????????? ???????????? ??????????????? ?????? ??????????????? ???????????? ?????????????????? ?????? +?????????????????? ????????? ??? ??? ?????? ???????????? ????????? ??????????????????. + +????????????: ????????? ?????????~ ??????! ???????????? ????????????. ???. ????????? ??????. diff --git a/Lib/test/cjkencodings/euc_kr.txt b/Lib/test/cjkencodings/euc_kr.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr.txt @@ -0,0 +1,7 @@ +?? ??????(Python)?? ?????? ????, ?????? ?????????? ??????????. ???????? +???????? ?????? ?????? ?????? ?????????? ???????? ???????????????????? +??????????. ???????? ????(????)?? ?????? ???? ??????, ?????? ?????????? +?????? ???????? ?????????? ???? ?????????? ???????? ???????????? ???? +???????????? ?????? ?? ?? ???? ???????? ?????? ????????????. + +????????: ?????? ??????????????????~ ??????????! ?????????????? ??????????????. ????????. ?????? ??????????. diff --git a/Lib/test/cjkencodings/gb18030-utf8.txt b/Lib/test/cjkencodings/gb18030-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030-utf8.txt @@ -0,0 +1,15 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: +???????????? ????????? ????????? ?????? ?????? ????????? ??????????????? ?????????. + diff --git a/Lib/test/cjkencodings/gb18030.txt b/Lib/test/cjkencodings/gb18030.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030.txt @@ -0,0 +1,15 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: +?5?1?3?3?2?1?3?1 ?7?6?0?4?6?3 ?8?5?8?6?3?5 ?3?1?9?5 ?0?9?3?0 ?4?3?5?7?5?5 ?5?5?0?9?8?9?9?3?0?4 ?2?9?2?5?9?9. + diff --git a/Lib/test/cjkencodings/gb2312-utf8.txt b/Lib/test/cjkencodings/gb2312-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312-utf8.txt @@ -0,0 +1,6 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gb2312.txt b/Lib/test/cjkencodings/gb2312.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312.txt @@ -0,0 +1,6 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gbk-utf8.txt b/Lib/test/cjkencodings/gbk-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk-utf8.txt @@ -0,0 +1,14 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/gbk.txt b/Lib/test/cjkencodings/gbk.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk.txt @@ -0,0 +1,14 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: + diff --git a/Lib/test/cjkencodings/johab-utf8.txt b/Lib/test/cjkencodings/johab-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/johab.txt b/Lib/test/cjkencodings/johab.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab.txt @@ -0,0 +1,9 @@ +???w?b?a ?\?????a + +?????s!! ?g???U???????? ?????z?????? ?w?? ???? ??. . +? http://hg.python.org/cpython/rev/9e1d7cd15d2e changeset: 70158:9e1d7cd15d2e branch: 3.1 parent: 70155:16503022c4b8 user: Victor Stinner date: Mon May 16 16:57:18 2011 +0200 summary: Issue #11614: Fix importlib tests for the new __hello__ module files: Lib/importlib/test/frozen/test_loader.py | 26 +++++++---- 1 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Lib/importlib/test/frozen/test_loader.py b/Lib/importlib/test/frozen/test_loader.py --- a/Lib/importlib/test/frozen/test_loader.py +++ b/Lib/importlib/test/frozen/test_loader.py @@ -3,20 +3,21 @@ import unittest from .. import abc from .. import util - +from test.support import captured_stdout class LoaderTests(abc.LoaderTests): def test_module(self): - with util.uncache('__hello__'): + with util.uncache('__hello__'), captured_stdout() as stdout: module = machinery.FrozenImporter.load_module('__hello__') check = {'__name__': '__hello__', '__file__': '', '__package__': '', '__loader__': machinery.FrozenImporter} for attr, value in check.items(): self.assertEqual(getattr(module, attr), value) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_package(self): - with util.uncache('__phello__'): + with util.uncache('__phello__'), captured_stdout() as stdout: module = machinery.FrozenImporter.load_module('__phello__') check = {'__name__': '__phello__', '__file__': '', '__package__': '__phello__', '__path__': ['__phello__'], @@ -26,9 +27,11 @@ self.assertEqual(attr_value, value, "for __phello__.%s, %r != %r" % (attr, attr_value, value)) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_lacking_parent(self): - with util.uncache('__phello__', '__phello__.spam'): + with util.uncache('__phello__', '__phello__.spam'), \ + captured_stdout() as stdout: module = machinery.FrozenImporter.load_module('__phello__.spam') check = {'__name__': '__phello__.spam', '__file__': '', '__package__': '__phello__', @@ -38,12 +41,15 @@ self.assertEqual(attr_value, value, "for __phello__.spam.%s, %r != %r" % (attr, attr_value, value)) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_module_reuse(self): - with util.uncache('__hello__'): + with util.uncache('__hello__'), captured_stdout() as stdout: module1 = machinery.FrozenImporter.load_module('__hello__') module2 = machinery.FrozenImporter.load_module('__hello__') self.assertTrue(module1 is module2) + self.assertEqual(stdout.getvalue(), + 'Hello world!\nHello world!\n') def test_state_after_failure(self): # No way to trigger an error in a frozen module. @@ -62,10 +68,12 @@ def test_get_code(self): # Make sure that the code object is good. name = '__hello__' - code = machinery.FrozenImporter.get_code(name) - mod = imp.new_module(name) - exec(code, mod.__dict__) - self.assertTrue(hasattr(mod, 'initialized')) + with captured_stdout() as stdout: + code = machinery.FrozenImporter.get_code(name) + mod = imp.new_module(name) + exec(code, mod.__dict__) + self.assertTrue(hasattr(mod, 'initialized')) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_get_source(self): # Should always return None. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 16 17:01:28 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 16 May 2011 17:01:28 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (Merge 3.1) Issue #11614: Fix importlib tests for the new __hello__ module Message-ID: http://hg.python.org/cpython/rev/6119f6cc9b2d changeset: 70159:6119f6cc9b2d branch: 3.2 parent: 70156:370db8da308f parent: 70158:9e1d7cd15d2e user: Victor Stinner date: Mon May 16 16:59:49 2011 +0200 summary: (Merge 3.1) Issue #11614: Fix importlib tests for the new __hello__ module files: Lib/importlib/test/frozen/test_loader.py | 26 +++++++---- 1 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Lib/importlib/test/frozen/test_loader.py b/Lib/importlib/test/frozen/test_loader.py --- a/Lib/importlib/test/frozen/test_loader.py +++ b/Lib/importlib/test/frozen/test_loader.py @@ -3,20 +3,21 @@ import unittest from .. import abc from .. import util - +from test.support import captured_stdout class LoaderTests(abc.LoaderTests): def test_module(self): - with util.uncache('__hello__'): + with util.uncache('__hello__'), captured_stdout() as stdout: module = machinery.FrozenImporter.load_module('__hello__') check = {'__name__': '__hello__', '__file__': '', '__package__': '', '__loader__': machinery.FrozenImporter} for attr, value in check.items(): self.assertEqual(getattr(module, attr), value) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_package(self): - with util.uncache('__phello__'): + with util.uncache('__phello__'), captured_stdout() as stdout: module = machinery.FrozenImporter.load_module('__phello__') check = {'__name__': '__phello__', '__file__': '', '__package__': '__phello__', '__path__': ['__phello__'], @@ -26,9 +27,11 @@ self.assertEqual(attr_value, value, "for __phello__.%s, %r != %r" % (attr, attr_value, value)) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_lacking_parent(self): - with util.uncache('__phello__', '__phello__.spam'): + with util.uncache('__phello__', '__phello__.spam'), \ + captured_stdout() as stdout: module = machinery.FrozenImporter.load_module('__phello__.spam') check = {'__name__': '__phello__.spam', '__file__': '', '__package__': '__phello__', @@ -38,12 +41,15 @@ self.assertEqual(attr_value, value, "for __phello__.spam.%s, %r != %r" % (attr, attr_value, value)) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_module_reuse(self): - with util.uncache('__hello__'): + with util.uncache('__hello__'), captured_stdout() as stdout: module1 = machinery.FrozenImporter.load_module('__hello__') module2 = machinery.FrozenImporter.load_module('__hello__') self.assertTrue(module1 is module2) + self.assertEqual(stdout.getvalue(), + 'Hello world!\nHello world!\n') def test_state_after_failure(self): # No way to trigger an error in a frozen module. @@ -62,10 +68,12 @@ def test_get_code(self): # Make sure that the code object is good. name = '__hello__' - code = machinery.FrozenImporter.get_code(name) - mod = imp.new_module(name) - exec(code, mod.__dict__) - self.assertTrue(hasattr(mod, 'initialized')) + with captured_stdout() as stdout: + code = machinery.FrozenImporter.get_code(name) + mod = imp.new_module(name) + exec(code, mod.__dict__) + self.assertTrue(hasattr(mod, 'initialized')) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_get_source(self): # Should always return None. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 16 17:01:30 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 16 May 2011 17:01:30 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #11614: Fix importlib tests for the new __hello__ module Message-ID: http://hg.python.org/cpython/rev/b61a1cd4943b changeset: 70160:b61a1cd4943b parent: 70157:e7daf2acc3a7 parent: 70159:6119f6cc9b2d user: Victor Stinner date: Mon May 16 17:00:41 2011 +0200 summary: (Merge 3.2) Issue #11614: Fix importlib tests for the new __hello__ module files: Lib/importlib/test/frozen/test_loader.py | 26 +++++++---- 1 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Lib/importlib/test/frozen/test_loader.py b/Lib/importlib/test/frozen/test_loader.py --- a/Lib/importlib/test/frozen/test_loader.py +++ b/Lib/importlib/test/frozen/test_loader.py @@ -3,20 +3,21 @@ import unittest from .. import abc from .. import util - +from test.support import captured_stdout class LoaderTests(abc.LoaderTests): def test_module(self): - with util.uncache('__hello__'): + with util.uncache('__hello__'), captured_stdout() as stdout: module = machinery.FrozenImporter.load_module('__hello__') check = {'__name__': '__hello__', '__file__': '', '__package__': '', '__loader__': machinery.FrozenImporter} for attr, value in check.items(): self.assertEqual(getattr(module, attr), value) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_package(self): - with util.uncache('__phello__'): + with util.uncache('__phello__'), captured_stdout() as stdout: module = machinery.FrozenImporter.load_module('__phello__') check = {'__name__': '__phello__', '__file__': '', '__package__': '__phello__', '__path__': ['__phello__'], @@ -26,9 +27,11 @@ self.assertEqual(attr_value, value, "for __phello__.%s, %r != %r" % (attr, attr_value, value)) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_lacking_parent(self): - with util.uncache('__phello__', '__phello__.spam'): + with util.uncache('__phello__', '__phello__.spam'), \ + captured_stdout() as stdout: module = machinery.FrozenImporter.load_module('__phello__.spam') check = {'__name__': '__phello__.spam', '__file__': '', '__package__': '__phello__', @@ -38,12 +41,15 @@ self.assertEqual(attr_value, value, "for __phello__.spam.%s, %r != %r" % (attr, attr_value, value)) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_module_reuse(self): - with util.uncache('__hello__'): + with util.uncache('__hello__'), captured_stdout() as stdout: module1 = machinery.FrozenImporter.load_module('__hello__') module2 = machinery.FrozenImporter.load_module('__hello__') self.assertTrue(module1 is module2) + self.assertEqual(stdout.getvalue(), + 'Hello world!\nHello world!\n') def test_state_after_failure(self): # No way to trigger an error in a frozen module. @@ -62,10 +68,12 @@ def test_get_code(self): # Make sure that the code object is good. name = '__hello__' - code = machinery.FrozenImporter.get_code(name) - mod = imp.new_module(name) - exec(code, mod.__dict__) - self.assertTrue(hasattr(mod, 'initialized')) + with captured_stdout() as stdout: + code = machinery.FrozenImporter.get_code(name) + mod = imp.new_module(name) + exec(code, mod.__dict__) + self.assertTrue(hasattr(mod, 'initialized')) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') def test_get_source(self): # Should always return None. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 16 17:16:28 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 16 May 2011 17:16:28 +0200 Subject: [Python-checkins] cpython (2.7): Issue #12057: Convert CJK encoding testcase BLOB into multiple text files Message-ID: http://hg.python.org/cpython/rev/1bd697cdd210 changeset: 70161:1bd697cdd210 branch: 2.7 parent: 70145:978016199be8 user: Victor Stinner date: Mon May 16 17:16:18 2011 +0200 summary: Issue #12057: Convert CJK encoding testcase BLOB into multiple text files files: Lib/test/cjkencodings/big5-utf8.txt | 9 + Lib/test/cjkencodings/big5.txt | 9 + Lib/test/cjkencodings/big5hkscs-utf8.txt | 2 + Lib/test/cjkencodings/big5hkscs.txt | 2 + Lib/test/cjkencodings/cp949-utf8.txt | 9 + Lib/test/cjkencodings/cp949.txt | 9 + Lib/test/cjkencodings/euc_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/euc_jisx0213.txt | 8 + Lib/test/cjkencodings/euc_jp-utf8.txt | 7 + Lib/test/cjkencodings/euc_jp.txt | 7 + Lib/test/cjkencodings/euc_kr-utf8.txt | 7 + Lib/test/cjkencodings/euc_kr.txt | 7 + Lib/test/cjkencodings/gb18030-utf8.txt | 15 + Lib/test/cjkencodings/gb18030.txt | 15 + Lib/test/cjkencodings/gb2312-utf8.txt | 6 + Lib/test/cjkencodings/gb2312.txt | 6 + Lib/test/cjkencodings/gbk-utf8.txt | 14 + Lib/test/cjkencodings/gbk.txt | 14 + Lib/test/cjkencodings/johab-utf8.txt | 9 + Lib/test/cjkencodings/johab.txt | 9 + Lib/test/cjkencodings/shift_jis-utf8.txt | 7 + Lib/test/cjkencodings/shift_jis.txt | 7 + Lib/test/cjkencodings/shift_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/shift_jisx0213.txt | 8 + Lib/test/cjkencodings_test.py | 1019 ---------- 25 files changed, 202 insertions(+), 1019 deletions(-) diff --git a/Lib/test/cjkencodings/big5-utf8.txt b/Lib/test/cjkencodings/big5-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5-utf8.txt @@ -0,0 +1,9 @@ +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/big5.txt b/Lib/test/cjkencodings/big5.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5.txt @@ -0,0 +1,9 @@ +?p???b Python ???????J???? C library? +?@?b???T???????t?o?i??????, ?}?o???????n?????t???O???e?????? +???D. ???[???}?o?????????t??, ?????K?`???????Q???@???w?}?o?n?? +library, ?????@?? fast prototyping ?? programming language ?i +??????. ???e???\?\?h?h?? library ?O?H C ?g??, ?? Python ?O?@?? +fast prototyping ?? programming language. ?G???????????N?J???? +C library ???? Python ?????????????????X. ???????D?n?]?O?????? +?n?Q???????D?N?O: + diff --git a/Lib/test/cjkencodings/big5hkscs-utf8.txt b/Lib/test/cjkencodings/big5hkscs-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs-utf8.txt @@ -0,0 +1,2 @@ +??????????????? +???????? ?????? diff --git a/Lib/test/cjkencodings/big5hkscs.txt b/Lib/test/cjkencodings/big5hkscs.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs.txt @@ -0,0 +1,2 @@ +?E?\?s???? +?f?b?? ???? diff --git a/Lib/test/cjkencodings/cp949-utf8.txt b/Lib/test/cjkencodings/cp949-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/cp949.txt b/Lib/test/cjkencodings/cp949.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949.txt @@ -0,0 +1,9 @@ +?c?????? ???????? + +??????!! ???????????p?? ?????R?????? ???? ???? ??. . +?????????? . . . . ?????? ?????? ???R ! ! !??.?? +?????? ??????????_?? ???? ?????O ???? ?h?????? ?????O +???j ???R . . . . ?????f ???? ???t???O ?????????????? +?????R ! ! ?????? ?????? ?????? ???????? ???????R ?????? +???????? ???????R ???? ??????????????????!! ???????? ????* + diff --git a/Lib/test/cjkencodings/euc_jisx0213-utf8.txt b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt @@ -0,0 +1,8 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + +????????? ?????? ???????????? ???????? ?????????? diff --git a/Lib/test/cjkencodings/euc_jisx0213.txt b/Lib/test/cjkencodings/euc_jisx0213.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213.txt @@ -0,0 +1,8 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + +???? ?? ???????? ????? ????????? diff --git a/Lib/test/cjkencodings/euc_jp-utf8.txt b/Lib/test/cjkencodings/euc_jp-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp-utf8.txt @@ -0,0 +1,7 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + diff --git a/Lib/test/cjkencodings/euc_jp.txt b/Lib/test/cjkencodings/euc_jp.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp.txt @@ -0,0 +1,7 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + diff --git a/Lib/test/cjkencodings/euc_kr-utf8.txt b/Lib/test/cjkencodings/euc_kr-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr-utf8.txt @@ -0,0 +1,7 @@ +??? ?????????(Python)??? ????????? ??????, ????????? ??????????????? ???????????????. ???????????? +???????????? ????????? ????????? ????????? ??????????????? ???????????? ?????????????????????????????? +???????????????. ???????????? ??????(??????)??? ????????? ?????? ?????????, ????????? ??????????????? +????????? ???????????? ??????????????? ?????? ??????????????? ???????????? ?????????????????? ?????? +?????????????????? ????????? ??? ??? ?????? ???????????? ????????? ??????????????????. + +????????????: ????????? ?????????~ ??????! ???????????? ????????????. ???. ????????? ??????. diff --git a/Lib/test/cjkencodings/euc_kr.txt b/Lib/test/cjkencodings/euc_kr.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr.txt @@ -0,0 +1,7 @@ +?? ??????(Python)?? ?????? ????, ?????? ?????????? ??????????. ???????? +???????? ?????? ?????? ?????? ?????????? ???????? ???????????????????? +??????????. ???????? ????(????)?? ?????? ???? ??????, ?????? ?????????? +?????? ???????? ?????????? ???? ?????????? ???????? ???????????? ???? +???????????? ?????? ?? ?? ???? ???????? ?????? ????????????. + +????????: ?????? ??????????????????~ ??????????! ?????????????? ??????????????. ????????. ?????? ??????????. diff --git a/Lib/test/cjkencodings/gb18030-utf8.txt b/Lib/test/cjkencodings/gb18030-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030-utf8.txt @@ -0,0 +1,15 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: +???????????? ????????? ????????? ?????? ?????? ????????? ??????????????? ?????????. + diff --git a/Lib/test/cjkencodings/gb18030.txt b/Lib/test/cjkencodings/gb18030.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030.txt @@ -0,0 +1,15 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: +?5?1?3?3?2?1?3?1 ?7?6?0?4?6?3 ?8?5?8?6?3?5 ?3?1?9?5 ?0?9?3?0 ?4?3?5?7?5?5 ?5?5?0?9?8?9?9?3?0?4 ?2?9?2?5?9?9. + diff --git a/Lib/test/cjkencodings/gb2312-utf8.txt b/Lib/test/cjkencodings/gb2312-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312-utf8.txt @@ -0,0 +1,6 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gb2312.txt b/Lib/test/cjkencodings/gb2312.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312.txt @@ -0,0 +1,6 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gbk-utf8.txt b/Lib/test/cjkencodings/gbk-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk-utf8.txt @@ -0,0 +1,14 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/gbk.txt b/Lib/test/cjkencodings/gbk.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk.txt @@ -0,0 +1,14 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: + diff --git a/Lib/test/cjkencodings/johab-utf8.txt b/Lib/test/cjkencodings/johab-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/johab.txt b/Lib/test/cjkencodings/johab.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab.txt @@ -0,0 +1,9 @@ +???w?b?a ?\?????a + +?????s!! ?g???U???????? ?????z?????? ?w?? ???? ??. . +? http://hg.python.org/cpython/rev/9a4d4506680a changeset: 70162:9a4d4506680a branch: 3.1 parent: 70158:9e1d7cd15d2e user: Victor Stinner date: Mon May 16 17:18:51 2011 +0200 summary: Issue #11614: Fix test_linecache, cjkencodings_test.py doesn't exist anymore files: Lib/test/test_linecache.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_linecache.py b/Lib/test/test_linecache.py --- a/Lib/test/test_linecache.py +++ b/Lib/test/test_linecache.py @@ -9,7 +9,7 @@ FILENAME = linecache.__file__ INVALID_NAME = '!@$)(!@#_1' EMPTY = '' -TESTS = 'cjkencodings_test inspect_fodder inspect_fodder2 mapping_tests' +TESTS = 'inspect_fodder inspect_fodder2 mapping_tests' TESTS = TESTS.split() TEST_PATH = os.path.dirname(support.__file__) MODULES = "linecache unittest".split() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 16 17:20:54 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 16 May 2011 17:20:54 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (Merge 3.1) Issue #11614: Fix test_linecache, cjkencodings_test.py doesn't Message-ID: http://hg.python.org/cpython/rev/43cbfacae463 changeset: 70163:43cbfacae463 branch: 3.2 parent: 70159:6119f6cc9b2d parent: 70162:9a4d4506680a user: Victor Stinner date: Mon May 16 17:20:07 2011 +0200 summary: (Merge 3.1) Issue #11614: Fix test_linecache, cjkencodings_test.py doesn't exist anymore files: Lib/test/test_linecache.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_linecache.py b/Lib/test/test_linecache.py --- a/Lib/test/test_linecache.py +++ b/Lib/test/test_linecache.py @@ -9,7 +9,7 @@ FILENAME = linecache.__file__ INVALID_NAME = '!@$)(!@#_1' EMPTY = '' -TESTS = 'cjkencodings_test inspect_fodder inspect_fodder2 mapping_tests' +TESTS = 'inspect_fodder inspect_fodder2 mapping_tests' TESTS = TESTS.split() TEST_PATH = os.path.dirname(support.__file__) MODULES = "linecache abc".split() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 16 17:20:55 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 16 May 2011 17:20:55 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #11614: Fix test_linecache, cjkencodings_test.py doesn't Message-ID: http://hg.python.org/cpython/rev/06473da99270 changeset: 70164:06473da99270 parent: 70160:b61a1cd4943b parent: 70163:43cbfacae463 user: Victor Stinner date: Mon May 16 17:20:47 2011 +0200 summary: (Merge 3.2) Issue #11614: Fix test_linecache, cjkencodings_test.py doesn't exist anymore files: Lib/test/test_linecache.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_linecache.py b/Lib/test/test_linecache.py --- a/Lib/test/test_linecache.py +++ b/Lib/test/test_linecache.py @@ -9,7 +9,7 @@ FILENAME = linecache.__file__ INVALID_NAME = '!@$)(!@#_1' EMPTY = '' -TESTS = 'cjkencodings_test inspect_fodder inspect_fodder2 mapping_tests' +TESTS = 'inspect_fodder inspect_fodder2 mapping_tests' TESTS = TESTS.split() TEST_PATH = os.path.dirname(support.__file__) MODULES = "linecache abc".split() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 01:19:16 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 May 2011 01:19:16 +0200 Subject: [Python-checkins] cpython (2.7): Issue #11614: Fix test_linecache, cjkencodings_test.py doesn't exist anymore Message-ID: http://hg.python.org/cpython/rev/47bc3509f76b changeset: 70165:47bc3509f76b branch: 2.7 parent: 70161:1bd697cdd210 user: Victor Stinner date: Tue May 17 01:18:33 2011 +0200 summary: Issue #11614: Fix test_linecache, cjkencodings_test.py doesn't exist anymore files: Lib/test/test_linecache.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_linecache.py b/Lib/test/test_linecache.py --- a/Lib/test/test_linecache.py +++ b/Lib/test/test_linecache.py @@ -9,7 +9,7 @@ FILENAME = linecache.__file__ INVALID_NAME = '!@$)(!@#_1' EMPTY = '' -TESTS = 'cjkencodings_test inspect_fodder inspect_fodder2 mapping_tests' +TESTS = 'inspect_fodder inspect_fodder2 mapping_tests' TESTS = TESTS.split() TEST_PATH = os.path.dirname(support.__file__) MODULES = "linecache abc".split() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 04:14:35 2011 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 17 May 2011 04:14:35 +0200 Subject: [Python-checkins] cpython (2.7): Fix closes issue #12088 - fixes the tarfile.extractall issue when the Message-ID: http://hg.python.org/cpython/rev/b29f0b6fcb76 changeset: 70166:b29f0b6fcb76 branch: 2.7 user: Senthil Kumaran date: Tue May 17 10:12:18 2011 +0800 summary: Fix closes issue #12088 - fixes the tarfile.extractall issue when the symlinks/hardlink was broken. It handles now in a graceful manner (No exception is raised, behavior similar GNU tar). files: Lib/tarfile.py | 4 +- Lib/test/test_tarfile.py | 60 ++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2239,12 +2239,14 @@ if hasattr(os, "symlink") and hasattr(os, "link"): # For systems that support symbolic and hard links. if tarinfo.issym(): - if os.path.exists(targetpath): + if os.path.lexists(targetpath): os.unlink(targetpath) os.symlink(tarinfo.linkname, targetpath) else: # See extract(). if os.path.exists(tarinfo._link_target): + if os.path.lexists(targetpath): + os.unlink(targetpath) os.link(tarinfo._link_target, targetpath) else: self._extract_member(self._find_link_target(tarinfo), targetpath) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -872,6 +872,66 @@ os.unlink(temparchive) shutil.rmtree(tempdir) + @unittest.skipUnless(hasattr(os, 'symlink'), "needs os.symlink") + def test_extractall_broken_symlinks(self): + # Test if extractall works properly when tarfile contains broken + # symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.symlink(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(target_file, arcname=os.path.basename(target_file)) + tar.close() + # remove the real file + os.unlink(source_file) + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with broken symlinked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) + + @unittest.skipUnless(hasattr(os, 'link'), "needs os.link") + def test_extractall_hardlinks(self): + # Test if extractall works properly when tarfile contains symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.link(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(source_file, arcname=os.path.basename(source_file)) + tar.add(target_file, arcname=os.path.basename(target_file)) + tar.close() + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with linked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) + class StreamWriteTest(WriteTestBase): mode = "w|" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 04:18:42 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 17 May 2011 04:18:42 +0200 Subject: [Python-checkins] cpython (2.7): #12093: fix typo in struct doc. Patch by Sandro Tosi. Message-ID: http://hg.python.org/cpython/rev/874309ce6e62 changeset: 70167:874309ce6e62 branch: 2.7 user: Ezio Melotti date: Tue May 17 05:17:35 2011 +0300 summary: #12093: fix typo in struct doc. Patch by Sandro Tosi. files: Doc/library/struct.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -314,7 +314,7 @@ >>> from collections import namedtuple >>> Student = namedtuple('Student', 'name serialnum school gradelevel') - >>> Student._make(unpack('<10sHHb', s)) + >>> Student._make(unpack('<10sHHb', record)) Student(name='raymond ', serialnum=4658, school=264, gradelevel=8) The ordering of format characters may have an impact on size since the padding -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 04:39:33 2011 From: python-checkins at python.org (ezio.melotti) Date: Tue, 17 May 2011 04:39:33 +0200 Subject: [Python-checkins] cpython (2.7): #12092: backport rephrasing of a paragraph in the tutorial. Message-ID: http://hg.python.org/cpython/rev/c449d3c3e0da changeset: 70168:c449d3c3e0da branch: 2.7 user: Ezio Melotti date: Tue May 17 05:39:22 2011 +0300 summary: #12092: backport rephrasing of a paragraph in the tutorial. files: Doc/tutorial/controlflow.rst | 7 +++---- 1 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -455,10 +455,9 @@ shopkeeper : Michael Palin sketch : Cheese Shop Sketch -Note that the :meth:`sort` method of the list of keyword argument names is -called before printing the contents of the ``keywords`` dictionary; if this is -not done, the order in which the arguments are printed is undefined. - +Note that the list of keyword argument names is created by sorting the result +of the keywords dictionary's ``keys()`` method before printing its contents; +if this is not done, the order in which the arguments are printed is undefined. .. _tut-arbitraryargs: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue May 17 05:00:06 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 17 May 2011 05:00:06 +0200 Subject: [Python-checkins] Daily reference leaks (06473da99270): sum=-323 Message-ID: results for 06473da99270 on branch "default" -------------------------------------------- test_pydoc leaked [0, 0, -323] references, sum=-323 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogXPuS6Q', '-x'] From python-checkins at python.org Tue May 17 08:16:00 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 17 May 2011 08:16:00 +0200 Subject: [Python-checkins] cpython: Skip some more tests in the absence of threading. Message-ID: http://hg.python.org/cpython/rev/c83fb59b73ea changeset: 70169:c83fb59b73ea parent: 70164:06473da99270 user: Vinay Sajip date: Tue May 17 07:15:53 2011 +0100 summary: Skip some more tests in the absence of threading. files: Lib/test/test_logging.py | 547 +++++++++++++------------- 1 files changed, 275 insertions(+), 272 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -25,24 +25,17 @@ import logging.handlers import logging.config -import asynchat -import asyncore import codecs import datetime -import errno import pickle import io import gc -from http.server import HTTPServer, BaseHTTPRequestHandler import json import os import queue import re import select -import smtpd import socket -from socketserver import (ThreadingUDPServer, DatagramRequestHandler, - ThreadingTCPServer, StreamRequestHandler) import struct import sys import tempfile @@ -51,11 +44,19 @@ import textwrap import time import unittest -from urllib.parse import urlparse, parse_qs import warnings import weakref try: import threading + # The following imports are needed only for tests which + import asynchat + import asyncore + import errno + from http.server import HTTPServer, BaseHTTPRequestHandler + import smtpd + from urllib.parse import urlparse, parse_qs + from socketserver import (ThreadingUDPServer, DatagramRequestHandler, + ThreadingTCPServer, StreamRequestHandler) except ImportError: threading = None try: @@ -611,284 +612,286 @@ # -- The following section could be moved into a server_helper.py module # -- if it proves to be of wider utility than just test_logging -class TestSMTPChannel(smtpd.SMTPChannel): - """ - This derived class has had to be created because smtpd does not - support use of custom channel maps, although they are allowed by - asyncore's design. Issue #11959 has been raised to address this, - and if resolved satisfactorily, some of this code can be removed. - """ - def __init__(self, server, conn, addr, sockmap): - asynchat.async_chat.__init__(self, conn, sockmap) - self.smtp_server = server - self.conn = conn - self.addr = addr - self.received_lines = [] - self.smtp_state = self.COMMAND - self.seen_greeting = '' - self.mailfrom = None - self.rcpttos = [] - self.received_data = '' - self.fqdn = socket.getfqdn() - self.num_bytes = 0 - try: - self.peer = conn.getpeername() - except socket.error as err: - # a race condition may occur if the other end is closing - # before we can get the peername - self.close() - if err.args[0] != errno.ENOTCONN: - raise - return - self.push('220 %s %s' % (self.fqdn, smtpd.__version__)) - self.set_terminator(b'\r\n') - - -class TestSMTPServer(smtpd.SMTPServer): - """ - This class implements a test SMTP server. - - :param addr: A (host, port) tuple which the server listens on. - You can specify a port value of zero: the server's - *port* attribute will hold the actual port number - used, which can be used in client connections. - :param handler: A callable which will be called to process - incoming messages. The handler will be passed - the client address tuple, who the message is from, - a list of recipients and the message data. - :param poll_interval: The interval, in seconds, used in the underlying - :func:`select` or :func:`poll` call by - :func:`asyncore.loop`. - :param sockmap: A dictionary which will be used to hold - :class:`asyncore.dispatcher` instances used by - :func:`asyncore.loop`. This avoids changing the - :mod:`asyncore` module's global state. - """ - channel_class = TestSMTPChannel - - def __init__(self, addr, handler, poll_interval, sockmap): - self._localaddr = addr - self._remoteaddr = None - self.sockmap = sockmap - asyncore.dispatcher.__init__(self, map=sockmap) - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setblocking(0) - self.set_socket(sock, map=sockmap) - # try to re-use a server port if possible - self.set_reuse_addr() - self.bind(addr) - self.port = sock.getsockname()[1] - self.listen(5) - except: - self.close() - raise - self._handler = handler - self._thread = None - self.poll_interval = poll_interval - - def handle_accepted(self, conn, addr): +if threading: + class TestSMTPChannel(smtpd.SMTPChannel): """ - Redefined only because the base class does not pass in a - map, forcing use of a global in :mod:`asyncore`. + This derived class has had to be created because smtpd does not + support use of custom channel maps, although they are allowed by + asyncore's design. Issue #11959 has been raised to address this, + and if resolved satisfactorily, some of this code can be removed. """ - channel = self.channel_class(self, conn, addr, self.sockmap) - - def process_message(self, peer, mailfrom, rcpttos, data): + def __init__(self, server, conn, addr, sockmap): + asynchat.async_chat.__init__(self, conn, sockmap) + self.smtp_server = server + self.conn = conn + self.addr = addr + self.received_lines = [] + self.smtp_state = self.COMMAND + self.seen_greeting = '' + self.mailfrom = None + self.rcpttos = [] + self.received_data = '' + self.fqdn = socket.getfqdn() + self.num_bytes = 0 + try: + self.peer = conn.getpeername() + except socket.error as err: + # a race condition may occur if the other end is closing + # before we can get the peername + self.close() + if err.args[0] != errno.ENOTCONN: + raise + return + self.push('220 %s %s' % (self.fqdn, smtpd.__version__)) + self.set_terminator(b'\r\n') + + + class TestSMTPServer(smtpd.SMTPServer): """ - Delegates to the handler passed in to the server's constructor. - - Typically, this will be a test case method. - :param peer: The client (host, port) tuple. - :param mailfrom: The address of the sender. - :param rcpttos: The addresses of the recipients. - :param data: The message. - """ - self._handler(peer, mailfrom, rcpttos, data) - - def start(self): - """ - Start the server running on a separate daemon thread. - """ - self._thread = t = threading.Thread(target=self.serve_forever, - args=(self.poll_interval,)) - t.setDaemon(True) - t.start() - - def serve_forever(self, poll_interval): - """ - Run the :mod:`asyncore` loop until normal termination - conditions arise. + This class implements a test SMTP server. + + :param addr: A (host, port) tuple which the server listens on. + You can specify a port value of zero: the server's + *port* attribute will hold the actual port number + used, which can be used in client connections. + :param handler: A callable which will be called to process + incoming messages. The handler will be passed + the client address tuple, who the message is from, + a list of recipients and the message data. :param poll_interval: The interval, in seconds, used in the underlying :func:`select` or :func:`poll` call by :func:`asyncore.loop`. + :param sockmap: A dictionary which will be used to hold + :class:`asyncore.dispatcher` instances used by + :func:`asyncore.loop`. This avoids changing the + :mod:`asyncore` module's global state. """ - try: - asyncore.loop(poll_interval, map=self.sockmap) - except select.error: - # On FreeBSD 8, closing the server repeatably - # raises this error. We swallow it if the - # server has been closed. - if self.connected or self.accepting: + channel_class = TestSMTPChannel + + def __init__(self, addr, handler, poll_interval, sockmap): + self._localaddr = addr + self._remoteaddr = None + self.sockmap = sockmap + asyncore.dispatcher.__init__(self, map=sockmap) + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setblocking(0) + self.set_socket(sock, map=sockmap) + # try to re-use a server port if possible + self.set_reuse_addr() + self.bind(addr) + self.port = sock.getsockname()[1] + self.listen(5) + except: + self.close() raise - - def stop(self, timeout=None): - """ - Stop the thread by closing the server instance. - Wait for the server thread to terminate. - - :param timeout: How long to wait for the server thread - to terminate. - """ - self.close() - self._thread.join(timeout) - self._thread = None - -class ControlMixin(object): - """ - This mixin is used to start a server on a separate thread, and - shut it down programmatically. Request handling is simplified - instead - of needing to derive a suitable RequestHandler subclass, you just - provide a callable which will be passed each received request to be - processed. - - :param handler: A handler callable which will be called with a - single parameter - the request - in order to - process the request. This handler is called on the - server thread, effectively meaning that requests are - processed serially. While not quite Web scale ;-), - this should be fine for testing applications. - :param poll_interval: The polling interval in seconds. - """ - def __init__(self, handler, poll_interval): - self._thread = None - self.poll_interval = poll_interval - self._handler = handler - self.ready = threading.Event() - - def start(self): - """ - Create a daemon thread to run the server, and start it. - """ - self._thread = t = threading.Thread(target=self.serve_forever, - args=(self.poll_interval,)) - t.setDaemon(True) - t.start() - - def serve_forever(self, poll_interval): - """ - Run the server. Set the ready flag before entering the - service loop. - """ - self.ready.set() - super(ControlMixin, self).serve_forever(poll_interval) - - def stop(self, timeout=None): - """ - Tell the server thread to stop, and wait for it to do so. - - :param timeout: How long to wait for the server thread - to terminate. - """ - self.shutdown() - if self._thread is not None: + self._handler = handler + self._thread = None + self.poll_interval = poll_interval + + def handle_accepted(self, conn, addr): + """ + Redefined only because the base class does not pass in a + map, forcing use of a global in :mod:`asyncore`. + """ + channel = self.channel_class(self, conn, addr, self.sockmap) + + def process_message(self, peer, mailfrom, rcpttos, data): + """ + Delegates to the handler passed in to the server's constructor. + + Typically, this will be a test case method. + :param peer: The client (host, port) tuple. + :param mailfrom: The address of the sender. + :param rcpttos: The addresses of the recipients. + :param data: The message. + """ + self._handler(peer, mailfrom, rcpttos, data) + + def start(self): + """ + Start the server running on a separate daemon thread. + """ + self._thread = t = threading.Thread(target=self.serve_forever, + args=(self.poll_interval,)) + t.setDaemon(True) + t.start() + + def serve_forever(self, poll_interval): + """ + Run the :mod:`asyncore` loop until normal termination + conditions arise. + :param poll_interval: The interval, in seconds, used in the underlying + :func:`select` or :func:`poll` call by + :func:`asyncore.loop`. + """ + try: + asyncore.loop(poll_interval, map=self.sockmap) + except select.error: + # On FreeBSD 8, closing the server repeatably + # raises this error. We swallow it if the + # server has been closed. + if self.connected or self.accepting: + raise + + def stop(self, timeout=None): + """ + Stop the thread by closing the server instance. + Wait for the server thread to terminate. + + :param timeout: How long to wait for the server thread + to terminate. + """ + self.close() self._thread.join(timeout) self._thread = None - self.server_close() - self.ready.clear() - -class TestHTTPServer(ControlMixin, HTTPServer): - """ - An HTTP server which is controllable using :class:`ControlMixin`. - - :param addr: A tuple with the IP address and port to listen on. - :param handler: A handler callable which will be called with a - single parameter - the request - in order to - process the request. - :param poll_interval: The polling interval in seconds. - :param log: Pass ``True`` to enable log messages. - """ - def __init__(self, addr, handler, poll_interval=0.5, log=False): - class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler): - def __getattr__(self, name, default=None): - if name.startswith('do_'): - return self.process_request - raise AttributeError(name) - - def process_request(self): - self.server._handler(self) - - def log_message(self, format, *args): - if log: - super(DelegatingHTTPRequestHandler, - self).log_message(format, *args) - HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler) - ControlMixin.__init__(self, handler, poll_interval) - -class TestTCPServer(ControlMixin, ThreadingTCPServer): - """ - A TCP server which is controllable using :class:`ControlMixin`. - - :param addr: A tuple with the IP address and port to listen on. - :param handler: A handler callable which will be called with a single - parameter - the request - in order to process the request. - :param poll_interval: The polling interval in seconds. - :bind_and_activate: If True (the default), binds the server and starts it - listening. If False, you need to call - :meth:`server_bind` and :meth:`server_activate` at - some later time before calling :meth:`start`, so that - the server will set up the socket and listen on it. - """ - - allow_reuse_address = True - - def __init__(self, addr, handler, poll_interval=0.5, - bind_and_activate=True): - class DelegatingTCPRequestHandler(StreamRequestHandler): - - def handle(self): - self.server._handler(self) - ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler, - bind_and_activate) - ControlMixin.__init__(self, handler, poll_interval) - - def server_bind(self): - super(TestTCPServer, self).server_bind() - self.port = self.socket.getsockname()[1] - -class TestUDPServer(ControlMixin, ThreadingUDPServer): - """ - A UDP server which is controllable using :class:`ControlMixin`. - - :param addr: A tuple with the IP address and port to listen on. - :param handler: A handler callable which will be called with a - single parameter - the request - in order to - process the request. - :param poll_interval: The polling interval for shutdown requests, - in seconds. - :bind_and_activate: If True (the default), binds the server and - starts it listening. If False, you need to - call :meth:`server_bind` and - :meth:`server_activate` at some later time - before calling :meth:`start`, so that the server will - set up the socket and listen on it. - """ - def __init__(self, addr, handler, poll_interval=0.5, bind_and_activate=True): - class DelegatingUDPRequestHandler(DatagramRequestHandler): - - def handle(self): - self.server._handler(self) - ThreadingUDPServer.__init__(self, addr, DelegatingUDPRequestHandler, - bind_and_activate) - ControlMixin.__init__(self, handler, poll_interval) - - def server_bind(self): - super(TestUDPServer, self).server_bind() - self.port = self.socket.getsockname()[1] + + class ControlMixin(object): + """ + This mixin is used to start a server on a separate thread, and + shut it down programmatically. Request handling is simplified - instead + of needing to derive a suitable RequestHandler subclass, you just + provide a callable which will be passed each received request to be + processed. + + :param handler: A handler callable which will be called with a + single parameter - the request - in order to + process the request. This handler is called on the + server thread, effectively meaning that requests are + processed serially. While not quite Web scale ;-), + this should be fine for testing applications. + :param poll_interval: The polling interval in seconds. + """ + def __init__(self, handler, poll_interval): + self._thread = None + self.poll_interval = poll_interval + self._handler = handler + self.ready = threading.Event() + + def start(self): + """ + Create a daemon thread to run the server, and start it. + """ + self._thread = t = threading.Thread(target=self.serve_forever, + args=(self.poll_interval,)) + t.setDaemon(True) + t.start() + + def serve_forever(self, poll_interval): + """ + Run the server. Set the ready flag before entering the + service loop. + """ + self.ready.set() + super(ControlMixin, self).serve_forever(poll_interval) + + def stop(self, timeout=None): + """ + Tell the server thread to stop, and wait for it to do so. + + :param timeout: How long to wait for the server thread + to terminate. + """ + self.shutdown() + if self._thread is not None: + self._thread.join(timeout) + self._thread = None + self.server_close() + self.ready.clear() + + class TestHTTPServer(ControlMixin, HTTPServer): + """ + An HTTP server which is controllable using :class:`ControlMixin`. + + :param addr: A tuple with the IP address and port to listen on. + :param handler: A handler callable which will be called with a + single parameter - the request - in order to + process the request. + :param poll_interval: The polling interval in seconds. + :param log: Pass ``True`` to enable log messages. + """ + def __init__(self, addr, handler, poll_interval=0.5, log=False): + class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler): + def __getattr__(self, name, default=None): + if name.startswith('do_'): + return self.process_request + raise AttributeError(name) + + def process_request(self): + self.server._handler(self) + + def log_message(self, format, *args): + if log: + super(DelegatingHTTPRequestHandler, + self).log_message(format, *args) + HTTPServer.__init__(self, addr, DelegatingHTTPRequestHandler) + ControlMixin.__init__(self, handler, poll_interval) + + class TestTCPServer(ControlMixin, ThreadingTCPServer): + """ + A TCP server which is controllable using :class:`ControlMixin`. + + :param addr: A tuple with the IP address and port to listen on. + :param handler: A handler callable which will be called with a single + parameter - the request - in order to process the request. + :param poll_interval: The polling interval in seconds. + :bind_and_activate: If True (the default), binds the server and starts it + listening. If False, you need to call + :meth:`server_bind` and :meth:`server_activate` at + some later time before calling :meth:`start`, so that + the server will set up the socket and listen on it. + """ + + allow_reuse_address = True + + def __init__(self, addr, handler, poll_interval=0.5, + bind_and_activate=True): + class DelegatingTCPRequestHandler(StreamRequestHandler): + + def handle(self): + self.server._handler(self) + ThreadingTCPServer.__init__(self, addr, DelegatingTCPRequestHandler, + bind_and_activate) + ControlMixin.__init__(self, handler, poll_interval) + + def server_bind(self): + super(TestTCPServer, self).server_bind() + self.port = self.socket.getsockname()[1] + + class TestUDPServer(ControlMixin, ThreadingUDPServer): + """ + A UDP server which is controllable using :class:`ControlMixin`. + + :param addr: A tuple with the IP address and port to listen on. + :param handler: A handler callable which will be called with a + single parameter - the request - in order to + process the request. + :param poll_interval: The polling interval for shutdown requests, + in seconds. + :bind_and_activate: If True (the default), binds the server and + starts it listening. If False, you need to + call :meth:`server_bind` and + :meth:`server_activate` at some later time + before calling :meth:`start`, so that the server will + set up the socket and listen on it. + """ + def __init__(self, addr, handler, poll_interval=0.5, bind_and_activate=True): + class DelegatingUDPRequestHandler(DatagramRequestHandler): + + def handle(self): + self.server._handler(self) + ThreadingUDPServer.__init__(self, addr, DelegatingUDPRequestHandler, + bind_and_activate) + ControlMixin.__init__(self, handler, poll_interval) + + def server_bind(self): + super(TestUDPServer, self).server_bind() + self.port = self.socket.getsockname()[1] # - end of server_helper section + at unittest.skipUnless(threading, 'Threading required for this test.') class SMTPHandlerTest(BaseTest): def test_basic(self): sockmap = {} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 08:41:28 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 17 May 2011 08:41:28 +0200 Subject: [Python-checkins] cpython: Skip some tests in the absence of multiprocessing. Message-ID: http://hg.python.org/cpython/rev/4b7c29201c60 changeset: 70170:4b7c29201c60 user: Vinay Sajip date: Tue May 17 07:41:18 2011 +0100 summary: Skip some tests in the absence of multiprocessing. files: Lib/test/test_logging.py | 16 +++++++++++----- 1 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2504,6 +2504,7 @@ logging.config.stopListening() t.join(2.0) + @unittest.skipUnless(threading, 'Threading required for this test.') def test_listen_config_10_ok(self): with captured_stdout() as output: self.setup_via_listener(json.dumps(self.config10)) @@ -2523,6 +2524,7 @@ ('ERROR', '4'), ], stream=output) + @unittest.skipUnless(threading, 'Threading required for this test.') def test_listen_config_1_ok(self): with captured_stdout() as output: self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1)) @@ -3062,15 +3064,19 @@ def test_multiprocessing(self): r = logging.makeLogRecord({}) self.assertEqual(r.processName, 'MainProcess') - import multiprocessing as mp - r = logging.makeLogRecord({}) - self.assertEqual(r.processName, mp.current_process().name) + try: + import multiprocessing as mp + r = logging.makeLogRecord({}) + self.assertEqual(r.processName, mp.current_process().name) + except ImportError: + pass def test_optional(self): r = logging.makeLogRecord({}) NOT_NONE = self.assertIsNotNone - NOT_NONE(r.thread) - NOT_NONE(r.threadName) + if threading: + NOT_NONE(r.thread) + NOT_NONE(r.threadName) NOT_NONE(r.process) NOT_NONE(r.processName) log_threads = logging.logThreads -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 09:36:55 2011 From: python-checkins at python.org (mark.hammond) Date: Tue, 17 May 2011 09:36:55 +0200 Subject: [Python-checkins] peps: new version of pep-0397 based on python-dev feedback Message-ID: http://hg.python.org/peps/rev/e438e3b7de95 changeset: 3882:e438e3b7de95 user: Mark Hammond date: Tue May 17 17:35:44 2011 +1000 summary: new version of pep-0397 based on python-dev feedback files: pep-0397.txt | 292 ++++++++++++++++++++++++-------------- 1 files changed, 180 insertions(+), 112 deletions(-) diff --git a/pep-0397.txt b/pep-0397.txt --- a/pep-0397.txt +++ b/pep-0397.txt @@ -7,7 +7,7 @@ Type: Standards Track Content-Type: text/plain Created: 15-Mar-2011 - +Post-History: 17-May-2011, 15-Mar-2011 Abstract @@ -67,8 +67,8 @@ An overview of the launcher. This PEP outlines the general functionality and key guidelines of a - launcher for Windows. It is accompanied by reference implementation, - written in Python, which defines the detailed implementation. Over + launcher for Windows. It is accompanied by a reference implementation + [3], written in Python, which defines the detailed implementation. Over time, changes to the implementation may be desired - if the changes adhere to the guidelines in this PEP and have been made following the standard Python development model this PEP need not change. @@ -103,7 +103,7 @@ on the system PATH (eg., the Windows System32) directory. If installed, the "console" version of the launcher should be associated with .py files and the "windows" version associated with .pyw files. - + The launcher will not be tied to a specific version of Python - eg., a launcher distributed with Python 3.3 should be capable of locating and executing any Python 2.x and Python 3.x version. Future versions of the @@ -141,16 +141,15 @@ feature offered by Unix and would be useful for Windows users in some cases. - The launcher should be capable of supporting implementations other - than CPython, such as jython and IronPython. In particular, if there - are common symbolic links used on Unix to specify such an - implementation (such as "/usr/bin/jython"), the launcher need not - support such references on Windows. However, if there is strong desire - from the community to support these other implementations in a Windows - specific way, any such proposals will be judged on their merit. Even - without specialized support for these alternate implementations, the - ability to specify the fully-qualified path to an executable could be - used as a fallback. + The launcher will be capable of supporting implementations other than + CPython, such as jython and IronPython, but given both the absence of + common links on Unix (such as "/usr/bin/jython") and the inability for the + launcher to automatically locate the installation location of these + implementations on Windows, the launcher will support this via + customization options. Scripts taking advantage of this will not be + portable (as these customization options must be set to reflect the + configuration of the machine on which the launcher is running) but this + ability is nonetheless considered worthwhile. On Unix, the user can control which specific version of Python is used by adjusting the links in /usr/bin to point to the desired version. As @@ -160,76 +159,155 @@ "/usr/bin/python2" will automatically locate a Python 2.x implementation, an environment variable can override exactly which Python 2.x implementation will be chosen. Similarly for "/usr/bin/python" and - "/usr/bin/python3". - - While the guidelines above are general, the launcher should make - concessions for any Windows specific issues which increase the - usefulness of the launcher on Windows. In other words, the - guidelines above will not prevent Windows specific functionality - which makes the launcher significantly more useful for Windows - users. + "/usr/bin/python3". This is specified in detail later in this PEP. Shebang line parsing If the first command-line argument does not start with a dash ('-') character, an attempt will be made to open that argument as a file and parsed for a shebang line according to the rules in [1]. Once - parsed, the command will be examined to see if it is a "virtual - command". A virtual command starts with either of the strings - '/usr/bin/python', '/usr/bin/env python' or 'python' - while the - latter will not work on Unix, it will be offered as a convenience - for Windows users not familiar with the Unix conventions and with no - desire to have the shebang line work on Unix. + parsed, the command will be categorized according to the following rules: - Commands which are virtual are not treated as containing a file-system - path, but instead are treated as references to an installed Python. - Optionally, the virtual command may include a specific version, such - as '/usr/bin/python2' or '/usr/bin/python3.2'. If only a "major version" - qualifier is found, the launcher will enumerate the installed Python - versions and use the latest minor release found for the major version, - which is likely, although not guaranteed, to be the most recently - installed version in that family. If major and minor version qualifiers - are found, that specific version will be located and used. + * If the command starts with the definition of a customized command + followed by a space character, the customized command will be used. + See below for a description of customized commands. - If a virtual command has no version specifier, or if no shebang line - is found, the launcher will attempt to locate a Python 2.x - installation and use the latest found. If none are found, it will - attempt to use the latest Python 3.x implementation found. + * If the command starts with the strings '/usr/bin/python', + '/usr/bin/env python' or 'python' the command will be treated as a + 'virtual command' and the rules described in Python Version Qualifiers + (below) will be used to locate the executable to use. + + * Otherwise the command is assumed to be directly ready to execute - ie. + a fully-qualified path optionally followed by arguments. The contents + of the string will not be parsed - it will be passed directly to the + Windows CreateProcess function after appending the name of the script + and the launcher command-line arguments. This means that the rules used + by CreateProcess will be used, including how relative path names and + executable references without extensions are treated. Notably, the + Windows command processor will not be used, so special rules used by the + command processor (such as automatic appending of extensions other than + '.exe', support for batch files, etc) will not be used. The use of 'virtual' shebang lines will be encouraged as this should allow for portable shebang lines to be specified which work on - multiple operating systems. - - If the shebang line is not a virtual one as described above, it is - assumed to be a path to an executable - presumably a Python - executable, but this will not be checked. No version qualifiers are - parsed - if a specific version is required, then the path should - reflect that. Relative path specifications will be considered - relative to the directory of the launcher. Thus, a shebang line of - '#! python' will look for a python executable in the same directory - as the launcher. - - Non-virtual shebang lines should be discouraged as they make the - script specific to a specific Windows installation. However, they - are supported for maximum flexibility. + multiple operating systems and different installations of the same + operating system. If the first argument can not be opened as a file or if no valid - shebang line can be found, a default Python interpreter will be + shebang line can be found, the launcher will act as if a shebang line of + '!#python' was found - ie., a default Python interpreter will be located and the arguments passed to that. However, if a valid shebang line is found but the process specified by that line can not be started, the default interpreter will not be started - the error - to create the specified child process will be considered fatal and - the launcher will display an appropriate message and terminate with - a specific exit code. + to create the specified child process will cause the launcher to display + an appropriate message and terminate with a specific exit code. + +Virtual commands in shebang lines: + + Virtual Commands are shebang lines which start with the strings + '/usr/bin/python', '/usr/bin/env python' or 'python'. Optionally, the + virtual command may be suffixed with a version qualifier (see below), + such as '/usr/bin/python2' or '/usr/bin/python3.2'. The command executed + is based on the rules described in Python Version Qualifiers below. + +Customized Commands: + + The launcher will support the ability to define "Customized Commands" in a + Windows .ini file (ie, a file which can be parsed by the Windows function + GetPrivateProfileString). A section called '[commands]' can be created + with key names defining the virtual command and the value specifying the + actual command-line to be used for this virtual command. + + For example, if an INI file has the contents: + + [commands] + vpython=c:\bin\vpython.exe -foo + + Then a shebang line of '#! vpython' in a script named 'doit.py' will + result in the launcher using the command-line 'c:\bin\vpython.exe -foo + doit.py' + + Two .ini files will be searched by the launcher - 'py.ini' in the + current user's "application data" directory (ie, the directory returned + by calling the Windows function SHGetFolderPath with CSIDL_APPDATA) and + 'py.ini' in the same directory as the launcher. Commands specified + in the "application directory" will have precendence over the one next to + the executable, and the same .ini files will be used by both the Windows + and Console versions of the launcher. + +Python Version Qualifiers + + Some of the features described allow an optional Python version qualifier + to be used. + + A version qualifier starts with a major version number and can optionally + be followed by a period ('.') and a minor version specifier. If the minor + qualifier is specified, it may optionally be followed by "-32" to indicate + the 32bit implementation of that version be used. Note that no "-64" + qualifier is necessary as this is the default implementation (see below). + + If no version qualifiers are found, the environment variable PY_PYTHON can + be set to specify the default version qualifier - the default value is + "2". Note this value could specify just a major version (eg., "2") or a + major.minor qualifier (eg., "2.6"), or even major.minor-32. + + If no minor version qualfiers are found, the environment variable + PY_PYTHON{major} (where {major} is the current major version qualifier + as determined above) can be set to specify the full version. If no such + option is found, the launcher will enumerate the installed Python + versions and use the latest minor release found for the major version, + which is likely, although not guaranteed, to be the most recently + installed version in that family. On 64bit Windows with both 32bit and 64bit implementations of the same (major.minor) Python version installed, the 64bit version will always be preferred. This will be true for both 32bit and 64bit implementations of the launcher - a 32bit launcher will prefer to - execute a 64bit Python installation of the same version if + execute a 64bit Python installation of the specified version if available. This is so the behavior of the launcher can be predicted knowing only what versions are installed on the PC and without - regard to the order in which they were installed. + regard to the order in which they were installed. As noted above, an + optional "-32" suffix can be used on a version specifier to change this + behaviour. + + Examples: + + * If no relevant options are set, the commands 'python' and + 'python2' will use the latest Python 2.x version installed and + the command 'python3' will use the lastest Python 3.x installed. + + * The commands 'python3.1' and 'python2.7' will not consult any + options at all as the versions are fully specified. + + * if 'PY_PYTHON=3', the commands 'python' and 'python3' will both use + the latest installed Python 3 version. + + * if 'PY_PYTHON=3.1-32', the command 'python' will use the 32bit + implementation of 3.1 whereas the command 'python3' will use the latest + installed Python (PY_PYTHON was not considered at all as a major + version was specified.) + + * if 'PY_PYTHON=3' and 'PY_PYTHON3=3.1', the commands + 'python' and 'python3' will both use specifically 3.1 + + In addition to environment variables, the same settings can be configured + in the .INI file used by the launcher. The section in the INI file will + be called '[defaults]' and the key name will be the same as the + environment variables without the leading 'PY_' prefix (and note that + the key names in the INI file are case insensitive. The contents of + an environment variable will override things specified in the INI file. + + For example: + * Setting 'PY_PYTHON=3.1' is equivilent to the INI file + containing: + [defaults] + python=3.1 + + * Setting 'PY_PYTHON=3' and 'PY_PYTHON3=3.1' is equivilent to the INI file + containing: + [defaults] + python=3 + python3=3.1 Command-line handling @@ -238,25 +316,25 @@ If the only command-line argument is "-h" or "--help", the launcher will print a small banner and command-line usage, then pass the argument to - the default Python. This will have the effect of help for the launcher - being printed followed by help for Python itself. The output from the - launcher will attempt to clearly indicate the extended help information - is coming from the launcher and not Python. + the default Python. This will cause help for the launcher being printed + followed by help for Python itself. The output from the launcher will + attempt to clearly indicate the extended help information is coming from + the launcher and not Python. As a concession to interactively launching Python, the launcher will - support the first command-line argument optionally being a version - specifier in the form "-n[.n][:bits]" (where n is a single integer and - bits is either '32' or '64') to nominate a specific version be used. For - example, while "py.exe" may locate and launch the latest Python 2.x - implementation installed, a command-line such as "py.exe -3" could specify - the latest Python 3.x implementation be launched, while "py.exe -2.6:32" - could specify a 32bit implementation Python 2.6 be located and launched. - If a Python 2.x implementation is desired to be launched with the -3 flag, - the command-line would need to be similar to "py.exe -2 -3" (or the - specific version of Python could obviously be launched manually without - use of this launcher.) Note that this feature can not be used with shebang - processing as the file scanned for a shebang line and this argument must - both be the first argument and therefore are mutually exclusive. + support the first command-line argument optionally being a dash ("-") + followed by a version qualifier, as described above, to nominate a + specific version be used. For example, while "py.exe" may locate and + launch the latest Python 2.x implementation installed, a command-line such + as "py.exe -3" could specify the latest Python 3.x implementation be + launched, while "py.exe -2.6-32" could specify a 32bit implementation + Python 2.6 be located and launched. If a Python 2.x implementation is + desired to be launched with the -3 flag, the command-line would need to be + similar to "py.exe -2 -3" (or the specific version of Python could + obviously be launched manually without use of this launcher.) Note that + this feature can not be used with shebang processing as the file scanned + for a shebang line and this argument must both be the first argument and + therefore are mutually exclusive. All other arguments will be passed untouched to the child Python process. @@ -275,44 +353,32 @@ side effect of this is that the value of sys.executable would refer to the launcher instead of the Python implementation. Many Python scripts use the value of sys.executable to launch child processes, and these scripts may - fail to work as expected if the launcher is used - consider a "parent" + fail to work as expected if the launcher is used. Consider a "parent" script with a shebang line of '#! /usr/bin/python3' which attempts to - launch a child script with no shebang line at all. Currently that - child script would be launched using the exact same version running - the parent script, but if sys.executable referred to the launcher the - child would be likely executed using a Python 2.x version and would be - likely to fail with a SyntaxError. A solution for this would need to be - found before this could be considered. + launch a child script (with no shebang) via sys.executable - currently the + child is launched using the exact same version running the parent script. + If sys.executable referred to the launcher the child would be likely + executed using a Python 2.x version and would be likely to fail with a + SyntaxError. A solution for this would need to be found before this could + be considered. - The rules mentioned above regarding 64bit and 32bit programs would also be - rendered impossible with this 'in-process' model - a 32bit launcher would - be unable to load the 64bit version of Python and vice-versa. + Another hurdle is the support for alternative Python implementations + using the "customized commands" feature described above, where loading + the command dynamically into a running executable is not possible. - Given the impossibility of supporting the 64bit and 32bit requirements - above, the launcher will execute Python in a child process, remaining - alive while the child process is executing, then terminate with the same - exit code as returned by the child. + The final hurdle is the rules above regarding 64bit and 32bit programs - + a 32bit launcher would be unable to load the 64bit version of Python and + vice-versa. - To address the concerns regarding the termination of the launcher not - killing the child, the Win32 Job API will be used to arrange so that the - child process is automatically killed when the parent is terminated - (although children of that child process will continue as is the case - now.) However, that functionality only works on Windows XP and later, so - the launcher running on the Windows 2000 platform will not have this - feature - killing the launcher on that platform will keep the child - process alive. This feature has been implemented in the reference - implementation. - -Alternative implementations and distributions of Python. - - While this PEP is primarily concerned with the python.org distributions of - CPython, it does not preclude future enhancements to support both - different distributions of CPython (eg. ActivePython, Enthought), nor - different implementations of Python (eg. jython, IronPython.) - Enhancements to support these alternatives should be proposed by - (community or corporate) representatives of these alternatives and - addressed via the normal Python development process and after relevant - patches have been submitted for the reference implementation. + Given these considerations, the launcher will execute it's command in a + child process, remaining alive while the child process is executing, then + terminate with the same exit code as returned by the child. To address the + concerns regarding the termination of the launcher not killing the child, + the Win32 Job API will be used to arrange so that the child process is + automatically killed when the parent is terminated (although children of + that child process will continue as is the case now.) As this Windows API + is available in Windows XP and later, this launcher will not work on + Windows 2000 or earlier. References @@ -320,6 +386,8 @@ [2] http://www.python.org/dev/peps/pep-0394/ + [3] http://bugs.python.org/issue11629 + Copyright This document has been placed in the public domain. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue May 17 14:10:11 2011 From: python-checkins at python.org (ronald.oussoren) Date: Tue, 17 May 2011 14:10:11 +0200 Subject: [Python-checkins] cpython (2.7): (backport)Fix #10154 and #10090: locale normalizes the UTF-8 encoding to Message-ID: http://hg.python.org/cpython/rev/932de36903e7 changeset: 70171:932de36903e7 branch: 2.7 parent: 70168:c449d3c3e0da user: Ronald Oussoren date: Tue May 17 13:22:30 2011 +0200 summary: (backport)Fix #10154 and #10090: locale normalizes the UTF-8 encoding to "UTF-8" instead of "UTF8" On MacOSX and OpenBSD (and possibly other BSDs) "en_US.UTF-8" is a valid locale while "en_US.UTF8" is not. As the former works on Linux as well it is better to normalize to that value. files: Lib/locale.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/locale.py b/Lib/locale.py --- a/Lib/locale.py +++ b/Lib/locale.py @@ -621,7 +621,7 @@ 'tactis': 'TACTIS', 'euc_jp': 'eucJP', 'euc_kr': 'eucKR', - 'utf_8': 'UTF8', + 'utf_8': 'UTF-8', 'koi8_r': 'KOI8-R', 'koi8_u': 'KOI8-U', # XXX This list is still incomplete. If you know more diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,9 @@ Library ------- +- Issue #10154, #10090: change the normalization of UTF-8 to "UTF-8" instead + of "UTF8" in the locale module as the latter is not supported MacOSX and OpenBSD. + - Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in shell. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 14:10:12 2011 From: python-checkins at python.org (ronald.oussoren) Date: Tue, 17 May 2011 14:10:12 +0200 Subject: [Python-checkins] cpython (3.1): Fix #10154 and #10090: locale normalizes the UTF-8 encoding to "UTF-8" instead Message-ID: http://hg.python.org/cpython/rev/28e410eb86af changeset: 70172:28e410eb86af branch: 3.1 parent: 70162:9a4d4506680a user: Ronald Oussoren date: Tue May 17 12:44:54 2011 +0200 summary: Fix #10154 and #10090: locale normalizes the UTF-8 encoding to "UTF-8" instead of "UTF8" On MacOSX and OpenBSD (and possibly other BSDs) "en_US.UTF-8" is a valid locale while "en_US.UTF8" is not. As the former works on Linux as well it is better to normalize to that value. files: Lib/locale.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/locale.py b/Lib/locale.py --- a/Lib/locale.py +++ b/Lib/locale.py @@ -640,7 +640,7 @@ 'tactis': 'TACTIS', 'euc_jp': 'eucJP', 'euc_kr': 'eucKR', - 'utf_8': 'UTF8', + 'utf_8': 'UTF-8', 'koi8_r': 'KOI8-R', 'koi8_u': 'KOI8-U', # XXX This list is still incomplete. If you know more diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,6 +72,9 @@ Library ------- +- Issue #10154, #10090: change the normalization of UTF-8 to "UTF-8" instead + of "UTF8" in the locale module as the latter is not supported MacOSX and OpenBSD. + - Issue #10756: atexit normalizes the exception before displaying it. Patch by Andreas St?hrk. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 14:10:13 2011 From: python-checkins at python.org (ronald.oussoren) Date: Tue, 17 May 2011 14:10:13 +0200 Subject: [Python-checkins] cpython (merge 3.1 -> 3.2): (merge) Fix #10154 and #10090: locale normalizes the UTF-8 encoding to "UTF-8" Message-ID: http://hg.python.org/cpython/rev/454d13e535ff changeset: 70173:454d13e535ff branch: 3.2 parent: 70163:43cbfacae463 parent: 70172:28e410eb86af user: Ronald Oussoren date: Tue May 17 13:03:54 2011 +0200 summary: (merge) Fix #10154 and #10090: locale normalizes the UTF-8 encoding to "UTF-8" instead of "UTF8" On MacOSX and OpenBSD (and possibly other BSDs) "en_US.UTF-8" is a valid locale while "en_US.UTF8" is not. As the former works on Linux as well it is better to normalize to that value. files: Lib/locale.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/locale.py b/Lib/locale.py --- a/Lib/locale.py +++ b/Lib/locale.py @@ -643,7 +643,7 @@ 'tactis': 'TACTIS', 'euc_jp': 'eucJP', 'euc_kr': 'eucKR', - 'utf_8': 'UTF8', + 'utf_8': 'UTF-8', 'koi8_r': 'KOI8-R', 'koi8_u': 'KOI8-U', # XXX This list is still incomplete. If you know more diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -698,6 +698,9 @@ and a non-zero offset, and an attempt to read past the end of file is made (IndexError is raised instead). Patch by Ross Lagerwall. +- Issue #10154, #10090: change the normalization of UTF-8 to "UTF-8" instead + of "UTF8" in the locale module as the latter is not supported MacOSX and OpenBSD. + - Issue #10684: shutil.move used to delete a folder on case insensitive filesystems when the source and destination name where the same except for the case. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 14:49:50 2011 From: python-checkins at python.org (ronald.oussoren) Date: Tue, 17 May 2011 14:49:50 +0200 Subject: [Python-checkins] cpython (3.2): Fixes #11088: IDLE crashes when using F5 to run a script on OSX with Tk 8.5 Message-ID: http://hg.python.org/cpython/rev/1c6823317a06 changeset: 70174:1c6823317a06 branch: 3.2 user: Ronald Oussoren date: Tue May 17 14:48:40 2011 +0200 summary: Fixes #11088: IDLE crashes when using F5 to run a script on OSX with Tk 8.5 Without this patch IDLE will crash reliably on OSX when Tkinter is linked to TkCocoa 8.5.x. To reproduce: * Create a new file (script.py) with the following two lines: x = input('prompt: ') print(x) * Save the script * Run the script using the F5 keyboard shortcut (running from the menu works fine) The patch is a fairly crude hack, but we haven't found a better workaround for this Tk bug yet. files: Lib/idlelib/ScriptBinding.py | 19 ++++++++++++++++++- Misc/NEWS | 3 +++ 2 files changed, 21 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -27,6 +27,7 @@ from idlelib import PyShell, IOBinding from idlelib.configHandler import idleConf +from idlelib import macosxSupport indent_message = """Error: Inconsistent indentation detected! @@ -52,6 +53,9 @@ self.flist = self.editwin.flist self.root = self.editwin.root + if macosxSupport.runningAsOSXApp(): + self.editwin.text_frame.bind('<>', self._run_module_event) + def check_module_event(self, event): filename = self.getfilename() if not filename: @@ -116,14 +120,27 @@ shell.set_warning_stream(saved_stream) def run_module_event(self, event): + if macosxSupport.runningAsOSXApp(): + # Tk-Cocoa in MacOSX is broken until at least + # Tk 8.5.9, and without this rather + # crude workaround IDLE would hang when a user + # tries to run a module using the keyboard shortcut + # (the menu item works fine). + self.editwin.text_frame.after(200, + lambda: self.editwin.text_frame.event_generate('<>')) + return 'break' + else: + return self._run_module_event(event) + + def _run_module_event(self, event): """Run the module after setting up the environment. First check the syntax. If OK, make sure the shell is active and then transfer the arguments, set the run environment's working directory to the directory of the module being executed and also add that directory to its sys.path if not already included. + """ - """ filename = self.getfilename() if not filename: return 'break' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ Library ------- +- Issue #11088: don't crash when using F5 to run a script in IDLE on MacOSX + with Tk 8.5. + - Issue #9516: Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in shell. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 14:49:51 2011 From: python-checkins at python.org (ronald.oussoren) Date: Tue, 17 May 2011 14:49:51 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Fix for issue 10154, merge from 3.2 Message-ID: http://hg.python.org/cpython/rev/3d7cb852a176 changeset: 70175:3d7cb852a176 parent: 70170:4b7c29201c60 parent: 70173:454d13e535ff user: Ronald Oussoren date: Tue May 17 14:49:44 2011 +0200 summary: Fix for issue 10154, merge from 3.2 files: Lib/locale.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/locale.py b/Lib/locale.py --- a/Lib/locale.py +++ b/Lib/locale.py @@ -643,7 +643,7 @@ 'tactis': 'TACTIS', 'euc_jp': 'eucJP', 'euc_kr': 'eucKR', - 'utf_8': 'UTF8', + 'utf_8': 'UTF-8', 'koi8_r': 'KOI8-R', 'koi8_u': 'KOI8-U', # XXX This list is still incomplete. If you know more diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -999,6 +999,9 @@ and a non-zero offset, and an attempt to read past the end of file is made (IndexError is raised instead). Patch by Ross Lagerwall. +- Issue #10154, #10090: change the normalization of UTF-8 to "UTF-8" instead + of "UTF8" in the locale module as the latter is not supported MacOSX and OpenBSD. + - 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. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 14:52:47 2011 From: python-checkins at python.org (ronald.oussoren) Date: Tue, 17 May 2011 14:52:47 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Fixes #11088: IDLE crashes when using F5 to run a script on OSX with Tk 8.5 Message-ID: http://hg.python.org/cpython/rev/85aa02bc674c changeset: 70176:85aa02bc674c parent: 70175:3d7cb852a176 parent: 70174:1c6823317a06 user: Ronald Oussoren date: Tue May 17 14:52:21 2011 +0200 summary: Fixes #11088: IDLE crashes when using F5 to run a script on OSX with Tk 8.5 Without this patch IDLE will crash reliably on OSX when Tkinter is linked to TkCocoa 8.5.x. To reproduce: * Create a new file (script.py) with the following two lines: x = input('prompt: ') print(x) * Save the script * Run the script using the F5 keyboard shortcut (running from the menu works fine) The patch is a fairly crude hack, but we haven't found a better workaround for this Tk bug yet. files: Lib/idlelib/ScriptBinding.py | 19 ++++++++++++++++++- Misc/NEWS | 3 +++ 2 files changed, 21 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -27,6 +27,7 @@ from idlelib import PyShell, IOBinding from idlelib.configHandler import idleConf +from idlelib import macosxSupport indent_message = """Error: Inconsistent indentation detected! @@ -52,6 +53,9 @@ self.flist = self.editwin.flist self.root = self.editwin.root + if macosxSupport.runningAsOSXApp(): + self.editwin.text_frame.bind('<>', self._run_module_event) + def check_module_event(self, event): filename = self.getfilename() if not filename: @@ -116,14 +120,27 @@ shell.set_warning_stream(saved_stream) def run_module_event(self, event): + if macosxSupport.runningAsOSXApp(): + # Tk-Cocoa in MacOSX is broken until at least + # Tk 8.5.9, and without this rather + # crude workaround IDLE would hang when a user + # tries to run a module using the keyboard shortcut + # (the menu item works fine). + self.editwin.text_frame.after(200, + lambda: self.editwin.text_frame.event_generate('<>')) + return 'break' + else: + return self._run_module_event(event) + + def _run_module_event(self, event): """Run the module after setting up the environment. First check the syntax. If OK, make sure the shell is active and then transfer the arguments, set the run environment's working directory to the directory of the module being executed and also add that directory to its sys.path if not already included. + """ - """ filename = self.getfilename() if not filename: return 'break' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -153,6 +153,9 @@ Library ------- +- Issue #11088: don't crash when using F5 to run a script in IDLE on MacOSX + with Tk 8.5. + - Issue #9516: Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in shell. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 15:13:55 2011 From: python-checkins at python.org (ronald.oussoren) Date: Tue, 17 May 2011 15:13:55 +0200 Subject: [Python-checkins] cpython (2.7): (backport) Fixes #11088: IDLE crashes when using F5 to run a script on OSX with Message-ID: http://hg.python.org/cpython/rev/578020fe2875 changeset: 70177:578020fe2875 branch: 2.7 parent: 70171:932de36903e7 user: Ronald Oussoren date: Tue May 17 15:13:46 2011 +0200 summary: (backport) Fixes #11088: IDLE crashes when using F5 to run a script on OSX with Tk 8.5 Without this patch IDLE will crash reliably on OSX when Tkinter is linked to TkCocoa 8.5.x. To reproduce: * Create a new file (script.py) with the following two lines: x = raw_input('prompt: ') print x * Save the script * Run the script using the F5 keyboard shortcut (running from the menu works fine) The patch is a fairly crude hack, but we haven't found a better workaround for this Tk bug yet. files: Lib/idlelib/ScriptBinding.py | 17 +++++++++++++++++ Misc/NEWS | 3 +++ 2 files changed, 20 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -26,6 +26,7 @@ from idlelib import PyShell from idlelib.configHandler import idleConf +from idlelib import macosxSupport IDENTCHARS = string.ascii_letters + string.digits + "_" @@ -53,6 +54,9 @@ self.flist = self.editwin.flist self.root = self.editwin.root + if macosxSupport.runningAsOSXApp(): + self.editwin.text_frame.bind('<>', self._run_module_event) + def check_module_event(self, event): filename = self.getfilename() if not filename: @@ -166,6 +170,19 @@ interp.runcode(code) return 'break' + if macosxSupport.runningAsOSXApp(): + # Tk-Cocoa in MacOSX is broken until at least + # Tk 8.5.9, and without this rather + # crude workaround IDLE would hang when a user + # tries to run a module using the keyboard shortcut + # (the menu item works fine). + _run_module_event = run_module_event + + def run_module_event(self, event): + self.editwin.text_frame.after(200, + lambda: self.editwin.text_frame.event_generate('<>')) + return 'break' + def getfilename(self): """Get source filename. If not saved, offer to save (or create) file diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,9 @@ Library ------- +- Issue #11088: don't crash when using F5 to run a script in IDLE on MacOSX + with Tk 8.5. + - Issue #10154, #10090: change the normalization of UTF-8 to "UTF-8" instead of "UTF8" in the locale module as the latter is not supported MacOSX and OpenBSD. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 17 15:50:16 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 May 2011 15:50:16 +0200 Subject: [Python-checkins] cpython (2.7): Issue #12057: Fix .hgeol and test_multibytecodec_support for the conversion of Message-ID: http://hg.python.org/cpython/rev/83f4c270b27d changeset: 70178:83f4c270b27d branch: 2.7 user: Victor Stinner date: Tue May 17 15:49:56 2011 +0200 summary: Issue #12057: Fix .hgeol and test_multibytecodec_support for the conversion of the CJK encoding testcase BLOB into multiple text files. files: .hgeol | 3 +- Lib/test/test_multibytecodec_support.py | 17 +++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.hgeol b/.hgeol --- a/.hgeol +++ b/.hgeol @@ -27,8 +27,9 @@ **.zip = BIN Lib/email/test/data/msg_26.txt = BIN +Lib/test/cjkencodings/* = BIN +Lib/test/decimaltestdata/*.decTest = BIN Lib/test/sndhdrdata/sndhdr.* = BIN -Lib/test/decimaltestdata/*.decTest = BIN # All other files (which presumably are human-editable) are "native". # This must be the last rule! diff --git a/Lib/test/test_multibytecodec_support.py b/Lib/test/test_multibytecodec_support.py --- a/Lib/test/test_multibytecodec_support.py +++ b/Lib/test/test_multibytecodec_support.py @@ -4,8 +4,11 @@ # Common Unittest Routines for CJK codecs # -import sys, codecs -import unittest, re +import codecs +import os +import re +import sys +import unittest from httplib import HTTPException from test import test_support from StringIO import StringIO @@ -326,6 +329,10 @@ self.fail('Decoding failed while testing %s -> %s: %s' % ( repr(csetch), repr(unich), exc.reason)) -def load_teststring(encoding): - from test import cjkencodings_test - return cjkencodings_test.teststring[encoding] +def load_teststring(name): + dir = os.path.join(os.path.dirname(__file__), 'cjkencodings') + with open(os.path.join(dir, name + '.txt'), 'rb') as f: + encoded = f.read() + with open(os.path.join(dir, name + '-utf8.txt'), 'rb') as f: + utf8 = f.read() + return encoded, utf8 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 00:20:48 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 18 May 2011 00:20:48 +0200 Subject: [Python-checkins] cpython (3.2): Issue #12096: Fix a race condition in test_threading.test_waitfor(). Patch Message-ID: http://hg.python.org/cpython/rev/a6b4a00fb1c7 changeset: 70179:a6b4a00fb1c7 branch: 3.2 parent: 70174:1c6823317a06 user: Victor Stinner date: Wed May 18 00:16:14 2011 +0200 summary: Issue #12096: Fix a race condition in test_threading.test_waitfor(). Patch written by Charles-Fran?ois Natali. files: Lib/test/lock_tests.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -472,7 +472,7 @@ self.assertEqual(state, 4) b = Bunch(f, 1) b.wait_for_started() - for i in range(5): + for i in range(4): time.sleep(0.01) with cond: state += 1 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -75,6 +75,9 @@ Tests ----- +- Issue #12096: Fix a race condition in test_threading.test_waitfor(). Patch + written by Charles-Fran?ois Natali. + - Issue #11614: import __hello__ prints "Hello World!". Patch written by Andreas St?hrk. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 00:20:48 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 18 May 2011 00:20:48 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): (Merge 3.2) Issue #12096: Fix a race condition in Message-ID: http://hg.python.org/cpython/rev/c52807b17e03 changeset: 70180:c52807b17e03 parent: 70176:85aa02bc674c parent: 70179:a6b4a00fb1c7 user: Victor Stinner date: Wed May 18 00:20:18 2011 +0200 summary: (Merge 3.2) Issue #12096: Fix a race condition in test_threading.test_waitfor(). Patch written by Charles-Fran?ois Natali. files: Lib/test/lock_tests.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -474,7 +474,7 @@ self.assertEqual(state, 4) b = Bunch(f, 1) b.wait_for_started() - for i in range(5): + for i in range(4): time.sleep(0.01) with cond: state += 1 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -679,6 +679,9 @@ Tests ----- +- Issue #12096: Fix a race condition in test_threading.test_waitfor(). Patch + written by Charles-Fran?ois Natali. + - Issue #11614: import __hello__ prints "Hello World!". Patch written by Andreas St?hrk. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 01:30:13 2011 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 May 2011 01:30:13 +0200 Subject: [Python-checkins] cpython (2.7): stop using the old brain-dead interface for providing attributes/methods Message-ID: http://hg.python.org/cpython/rev/c9df95b57af3 changeset: 70181:c9df95b57af3 branch: 2.7 parent: 70145:978016199be8 user: Benjamin Peterson date: Tue May 17 18:31:20 2011 -0500 summary: stop using the old brain-dead interface for providing attributes/methods This closes #12099. files: Misc/NEWS | 4 + Modules/_sre.c | 246 ++++++++++++++++++------------------ 2 files changed, 126 insertions(+), 124 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -382,6 +382,10 @@ Extension Modules ----------------- +- Stop using the old interface for providing methods and attributes in the _sre + module. Among other things, this gives these classes ``__class__`` + attributes. (See #12099) + - Issue #10169: Fix argument parsing in socket.sendto() to avoid error masking. - Issue #12051: Fix segfault in json.dumps() while encoding highly-nested diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -2598,46 +2598,22 @@ {NULL, NULL} }; -static PyObject* -pattern_getattr(PatternObject* self, char* name) -{ - PyObject* res; - - res = Py_FindMethod(pattern_methods, (PyObject*) self, name); - - if (res) - return res; - - PyErr_Clear(); - - /* attributes */ - if (!strcmp(name, "pattern")) { - Py_INCREF(self->pattern); - return self->pattern; - } - - if (!strcmp(name, "flags")) - return Py_BuildValue("i", self->flags); - - if (!strcmp(name, "groups")) - return Py_BuildValue("i", self->groups); - - if (!strcmp(name, "groupindex") && self->groupindex) { - Py_INCREF(self->groupindex); - return self->groupindex; - } - - PyErr_SetString(PyExc_AttributeError, name); - return NULL; -} +#define PAT_OFF(x) offsetof(PatternObject, x) +static PyMemberDef pattern_members[] = { + {"pattern", T_OBJECT, PAT_OFF(pattern), READONLY}, + {"flags", T_INT, PAT_OFF(flags), READONLY}, + {"groups", T_PYSSIZET, PAT_OFF(groups), READONLY}, + {"groupindex", T_OBJECT, PAT_OFF(groupindex), READONLY}, + {NULL} /* Sentinel */ +}; statichere PyTypeObject Pattern_Type = { PyObject_HEAD_INIT(NULL) 0, "_" SRE_MODULE ".SRE_Pattern", sizeof(PatternObject), sizeof(SRE_CODE), (destructor)pattern_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - (getattrfunc)pattern_getattr, /*tp_getattr*/ + 0, /* tp_print */ + 0, /* tp_getattrn */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ @@ -2650,12 +2626,16 @@ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ pattern_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ offsetof(PatternObject, weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + pattern_methods, /* tp_methods */ + pattern_members, /* tp_members */ }; static int _validate(PatternObject *self); /* Forward */ @@ -3562,7 +3542,7 @@ #endif } -static PyMethodDef match_methods[] = { +static struct PyMethodDef match_methods[] = { {"group", (PyCFunction) match_group, METH_VARARGS}, {"start", (PyCFunction) match_start, METH_VARARGS}, {"end", (PyCFunction) match_end, METH_VARARGS}, @@ -3575,80 +3555,90 @@ {NULL, NULL} }; -static PyObject* -match_getattr(MatchObject* self, char* name) +static PyObject * +match_lastindex_get(MatchObject *self) { - PyObject* res; - - res = Py_FindMethod(match_methods, (PyObject*) self, name); - if (res) - return res; - - PyErr_Clear(); - - if (!strcmp(name, "lastindex")) { - if (self->lastindex >= 0) - return Py_BuildValue("i", self->lastindex); - Py_INCREF(Py_None); - return Py_None; + if (self->lastindex >= 0) + return Py_BuildValue("i", self->lastindex); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +match_lastgroup_get(MatchObject *self) +{ + if (self->pattern->indexgroup && self->lastindex >= 0) { + PyObject* result = PySequence_GetItem( + self->pattern->indexgroup, self->lastindex + ); + if (result) + return result; + PyErr_Clear(); } - - if (!strcmp(name, "lastgroup")) { - if (self->pattern->indexgroup && self->lastindex >= 0) { - PyObject* result = PySequence_GetItem( - self->pattern->indexgroup, self->lastindex - ); - if (result) - return result; - PyErr_Clear(); - } - Py_INCREF(Py_None); - return Py_None; - } - - if (!strcmp(name, "string")) { - if (self->string) { - Py_INCREF(self->string); - return self->string; - } else { - Py_INCREF(Py_None); - return Py_None; - } - } - - if (!strcmp(name, "regs")) { - if (self->regs) { - Py_INCREF(self->regs); - return self->regs; - } else - return match_regs(self); - } - - if (!strcmp(name, "re")) { - Py_INCREF(self->pattern); - return (PyObject*) self->pattern; - } - - if (!strcmp(name, "pos")) - return Py_BuildValue("i", self->pos); - - if (!strcmp(name, "endpos")) - return Py_BuildValue("i", self->endpos); - - PyErr_SetString(PyExc_AttributeError, name); - return NULL; + Py_INCREF(Py_None); + return Py_None; } +static PyObject * +match_regs_get(MatchObject *self) +{ + if (self->regs) { + Py_INCREF(self->regs); + return self->regs; + } else + return match_regs(self); +} + +static PyGetSetDef match_getset[] = { + {"lastindex", (getter)match_lastindex_get, (setter)NULL}, + {"lastgroup", (getter)match_lastgroup_get, (setter)NULL}, + {"regs", (getter)match_regs_get, (setter)NULL}, + {NULL} +}; + +#define MATCH_OFF(x) offsetof(MatchObject, x) +static PyMemberDef match_members[] = { + {"string", T_OBJECT, MATCH_OFF(string), READONLY}, + {"re", T_OBJECT, MATCH_OFF(pattern), READONLY}, + {"pos", T_PYSSIZET, MATCH_OFF(pos), READONLY}, + {"endpos", T_PYSSIZET, MATCH_OFF(endpos), READONLY}, + {NULL} +}; + + /* FIXME: implement setattr("string", None) as a special case (to detach the associated string, if any */ -statichere PyTypeObject Match_Type = { - PyObject_HEAD_INIT(NULL) - 0, "_" SRE_MODULE ".SRE_Match", +static PyTypeObject Match_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_" SRE_MODULE ".SRE_Match", sizeof(MatchObject), sizeof(Py_ssize_t), - (destructor)match_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - (getattrfunc)match_getattr /*tp_getattr*/ + (destructor)match_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + match_methods, /* tp_methods */ + match_members, /* tp_members */ + match_getset, /* tp_getset */ }; static PyObject* @@ -3797,34 +3787,42 @@ {NULL, NULL} }; -static PyObject* -scanner_getattr(ScannerObject* self, char* name) -{ - PyObject* res; - - res = Py_FindMethod(scanner_methods, (PyObject*) self, name); - if (res) - return res; - - PyErr_Clear(); - - /* attributes */ - if (!strcmp(name, "pattern")) { - Py_INCREF(self->pattern); - return self->pattern; - } - - PyErr_SetString(PyExc_AttributeError, name); - return NULL; -} +#define SCAN_OFF(x) offsetof(ScannerObject, x) +static PyMemberDef scanner_members[] = { + {"pattern", T_OBJECT, SCAN_OFF(pattern), READONLY}, + {NULL} /* Sentinel */ +}; statichere PyTypeObject Scanner_Type = { PyObject_HEAD_INIT(NULL) 0, "_" SRE_MODULE ".SRE_Scanner", sizeof(ScannerObject), 0, (destructor)scanner_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - (getattrfunc)scanner_getattr, /*tp_getattr*/ + 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 */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + scanner_methods, /* tp_methods */ + scanner_members, /* tp_members */ + 0, /* tp_getset */ }; static PyObject* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 01:30:14 2011 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 May 2011 01:30:14 +0200 Subject: [Python-checkins] cpython (merge 2.7 -> 2.7): merge heads Message-ID: http://hg.python.org/cpython/rev/31cd146d725c changeset: 70182:31cd146d725c branch: 2.7 parent: 70181:c9df95b57af3 parent: 70178:83f4c270b27d user: Benjamin Peterson date: Tue May 17 18:32:26 2011 -0500 summary: merge heads files: .hgeol | 3 +- Doc/library/struct.rst | 2 +- Doc/tutorial/controlflow.rst | 7 +- Lib/idlelib/ScriptBinding.py | 17 + Lib/locale.py | 2 +- Lib/tarfile.py | 4 +- Lib/test/cjkencodings/big5-utf8.txt | 9 + Lib/test/cjkencodings/big5.txt | 9 + Lib/test/cjkencodings/big5hkscs-utf8.txt | 2 + Lib/test/cjkencodings/big5hkscs.txt | 2 + Lib/test/cjkencodings/cp949-utf8.txt | 9 + Lib/test/cjkencodings/cp949.txt | 9 + Lib/test/cjkencodings/euc_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/euc_jisx0213.txt | 8 + Lib/test/cjkencodings/euc_jp-utf8.txt | 7 + Lib/test/cjkencodings/euc_jp.txt | 7 + Lib/test/cjkencodings/euc_kr-utf8.txt | 7 + Lib/test/cjkencodings/euc_kr.txt | 7 + Lib/test/cjkencodings/gb18030-utf8.txt | 15 + Lib/test/cjkencodings/gb18030.txt | 15 + Lib/test/cjkencodings/gb2312-utf8.txt | 6 + Lib/test/cjkencodings/gb2312.txt | 6 + Lib/test/cjkencodings/gbk-utf8.txt | 14 + Lib/test/cjkencodings/gbk.txt | 14 + Lib/test/cjkencodings/johab-utf8.txt | 9 + Lib/test/cjkencodings/johab.txt | 9 + Lib/test/cjkencodings/shift_jis-utf8.txt | 7 + Lib/test/cjkencodings/shift_jis.txt | 7 + Lib/test/cjkencodings/shift_jisx0213-utf8.txt | 8 + Lib/test/cjkencodings/shift_jisx0213.txt | 8 + Lib/test/cjkencodings_test.py | 1019 ---------- Lib/test/test_linecache.py | 2 +- Lib/test/test_multibytecodec_support.py | 17 +- Lib/test/test_tarfile.py | 60 + Misc/NEWS | 6 + 35 files changed, 308 insertions(+), 1033 deletions(-) diff --git a/.hgeol b/.hgeol --- a/.hgeol +++ b/.hgeol @@ -27,8 +27,9 @@ **.zip = BIN Lib/email/test/data/msg_26.txt = BIN +Lib/test/cjkencodings/* = BIN +Lib/test/decimaltestdata/*.decTest = BIN Lib/test/sndhdrdata/sndhdr.* = BIN -Lib/test/decimaltestdata/*.decTest = BIN # All other files (which presumably are human-editable) are "native". # This must be the last rule! diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -314,7 +314,7 @@ >>> from collections import namedtuple >>> Student = namedtuple('Student', 'name serialnum school gradelevel') - >>> Student._make(unpack('<10sHHb', s)) + >>> Student._make(unpack('<10sHHb', record)) Student(name='raymond ', serialnum=4658, school=264, gradelevel=8) The ordering of format characters may have an impact on size since the padding diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -455,10 +455,9 @@ shopkeeper : Michael Palin sketch : Cheese Shop Sketch -Note that the :meth:`sort` method of the list of keyword argument names is -called before printing the contents of the ``keywords`` dictionary; if this is -not done, the order in which the arguments are printed is undefined. - +Note that the list of keyword argument names is created by sorting the result +of the keywords dictionary's ``keys()`` method before printing its contents; +if this is not done, the order in which the arguments are printed is undefined. .. _tut-arbitraryargs: diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -26,6 +26,7 @@ from idlelib import PyShell from idlelib.configHandler import idleConf +from idlelib import macosxSupport IDENTCHARS = string.ascii_letters + string.digits + "_" @@ -53,6 +54,9 @@ self.flist = self.editwin.flist self.root = self.editwin.root + if macosxSupport.runningAsOSXApp(): + self.editwin.text_frame.bind('<>', self._run_module_event) + def check_module_event(self, event): filename = self.getfilename() if not filename: @@ -166,6 +170,19 @@ interp.runcode(code) return 'break' + if macosxSupport.runningAsOSXApp(): + # Tk-Cocoa in MacOSX is broken until at least + # Tk 8.5.9, and without this rather + # crude workaround IDLE would hang when a user + # tries to run a module using the keyboard shortcut + # (the menu item works fine). + _run_module_event = run_module_event + + def run_module_event(self, event): + self.editwin.text_frame.after(200, + lambda: self.editwin.text_frame.event_generate('<>')) + return 'break' + def getfilename(self): """Get source filename. If not saved, offer to save (or create) file diff --git a/Lib/locale.py b/Lib/locale.py --- a/Lib/locale.py +++ b/Lib/locale.py @@ -621,7 +621,7 @@ 'tactis': 'TACTIS', 'euc_jp': 'eucJP', 'euc_kr': 'eucKR', - 'utf_8': 'UTF8', + 'utf_8': 'UTF-8', 'koi8_r': 'KOI8-R', 'koi8_u': 'KOI8-U', # XXX This list is still incomplete. If you know more diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2239,12 +2239,14 @@ if hasattr(os, "symlink") and hasattr(os, "link"): # For systems that support symbolic and hard links. if tarinfo.issym(): - if os.path.exists(targetpath): + if os.path.lexists(targetpath): os.unlink(targetpath) os.symlink(tarinfo.linkname, targetpath) else: # See extract(). if os.path.exists(tarinfo._link_target): + if os.path.lexists(targetpath): + os.unlink(targetpath) os.link(tarinfo._link_target, targetpath) else: self._extract_member(self._find_link_target(tarinfo), targetpath) diff --git a/Lib/test/cjkencodings/big5-utf8.txt b/Lib/test/cjkencodings/big5-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5-utf8.txt @@ -0,0 +1,9 @@ +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/big5.txt b/Lib/test/cjkencodings/big5.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5.txt @@ -0,0 +1,9 @@ +?p???b Python ???????J???? C library? +?@?b???T???????t?o?i??????, ?}?o???????n?????t???O???e?????? +???D. ???[???}?o?????????t??, ?????K?`???????Q???@???w?}?o?n?? +library, ?????@?? fast prototyping ?? programming language ?i +??????. ???e???\?\?h?h?? library ?O?H C ?g??, ?? Python ?O?@?? +fast prototyping ?? programming language. ?G???????????N?J???? +C library ???? Python ?????????????????X. ???????D?n?]?O?????? +?n?Q???????D?N?O: + diff --git a/Lib/test/cjkencodings/big5hkscs-utf8.txt b/Lib/test/cjkencodings/big5hkscs-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs-utf8.txt @@ -0,0 +1,2 @@ +??????????????? +???????? ?????? diff --git a/Lib/test/cjkencodings/big5hkscs.txt b/Lib/test/cjkencodings/big5hkscs.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/big5hkscs.txt @@ -0,0 +1,2 @@ +?E?\?s???? +?f?b?? ???? diff --git a/Lib/test/cjkencodings/cp949-utf8.txt b/Lib/test/cjkencodings/cp949-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/cp949.txt b/Lib/test/cjkencodings/cp949.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/cp949.txt @@ -0,0 +1,9 @@ +?c?????? ???????? + +??????!! ???????????p?? ?????R?????? ???? ???? ??. . +?????????? . . . . ?????? ?????? ???R ! ! !??.?? +?????? ??????????_?? ???? ?????O ???? ?h?????? ?????O +???j ???R . . . . ?????f ???? ???t???O ?????????????? +?????R ! ! ?????? ?????? ?????? ???????? ???????R ?????? +???????? ???????R ???? ??????????????????!! ???????? ????* + diff --git a/Lib/test/cjkencodings/euc_jisx0213-utf8.txt b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213-utf8.txt @@ -0,0 +1,8 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + +????????? ?????? ???????????? ???????? ?????????? diff --git a/Lib/test/cjkencodings/euc_jisx0213.txt b/Lib/test/cjkencodings/euc_jisx0213.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jisx0213.txt @@ -0,0 +1,8 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + +???? ?? ???????? ????? ????????? diff --git a/Lib/test/cjkencodings/euc_jp-utf8.txt b/Lib/test/cjkencodings/euc_jp-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp-utf8.txt @@ -0,0 +1,7 @@ +Python ???????????????1990 ?????????????????????????????????????????? +???????????? Guido van Rossum ?????????????????????????????????????????????ABC?????????????????????????????????????????????ABC ????????????????????????????????????????????????????????????????????? +???????????????Guido ?????????????????????????????????????????????????????????????????????????????? BBS ?????????????????????????????????????????? ???????????????????????????????????? Guido ?????????????????????Python??????????????????????????? +??????????????????????????????????????? Python ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? Python ???????????????????????? + diff --git a/Lib/test/cjkencodings/euc_jp.txt b/Lib/test/cjkencodings/euc_jp.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_jp.txt @@ -0,0 +1,7 @@ +Python ??????????1990 ???????????????????????????? +???????? Guido van Rossum ??????????????????????????????ABC??????????????????????????????ABC ?????????????????????????????????????????????? +??????????Guido ???????????????????????????????????????????????????? BBS ???????????????????????????? ???????????????????????? Guido ??????????????Python?????????????????? +?????????????????????????? Python ???????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????????????????????????????????Python ???????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????? Python ???????????????? + diff --git a/Lib/test/cjkencodings/euc_kr-utf8.txt b/Lib/test/cjkencodings/euc_kr-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr-utf8.txt @@ -0,0 +1,7 @@ +??? ?????????(Python)??? ????????? ??????, ????????? ??????????????? ???????????????. ???????????? +???????????? ????????? ????????? ????????? ??????????????? ???????????? ?????????????????????????????? +???????????????. ???????????? ??????(??????)??? ????????? ?????? ?????????, ????????? ??????????????? +????????? ???????????? ??????????????? ?????? ??????????????? ???????????? ?????????????????? ?????? +?????????????????? ????????? ??? ??? ?????? ???????????? ????????? ??????????????????. + +????????????: ????????? ?????????~ ??????! ???????????? ????????????. ???. ????????? ??????. diff --git a/Lib/test/cjkencodings/euc_kr.txt b/Lib/test/cjkencodings/euc_kr.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/euc_kr.txt @@ -0,0 +1,7 @@ +?? ??????(Python)?? ?????? ????, ?????? ?????????? ??????????. ???????? +???????? ?????? ?????? ?????? ?????????? ???????? ???????????????????? +??????????. ???????? ????(????)?? ?????? ???? ??????, ?????? ?????????? +?????? ???????? ?????????? ???? ?????????? ???????? ???????????? ???? +???????????? ?????? ?? ?? ???? ???????? ?????? ????????????. + +????????: ?????? ??????????????????~ ??????????! ?????????????? ??????????????. ????????. ?????? ??????????. diff --git a/Lib/test/cjkencodings/gb18030-utf8.txt b/Lib/test/cjkencodings/gb18030-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030-utf8.txt @@ -0,0 +1,15 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: +???????????? ????????? ????????? ?????? ?????? ????????? ??????????????? ?????????. + diff --git a/Lib/test/cjkencodings/gb18030.txt b/Lib/test/cjkencodings/gb18030.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb18030.txt @@ -0,0 +1,15 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: +?5?1?3?3?2?1?3?1 ?7?6?0?4?6?3 ?8?5?8?6?3?5 ?3?1?9?5 ?0?9?3?0 ?4?3?5?7?5?5 ?5?5?0?9?8?9?9?3?0?4 ?2?9?2?5?9?9. + diff --git a/Lib/test/cjkencodings/gb2312-utf8.txt b/Lib/test/cjkencodings/gb2312-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312-utf8.txt @@ -0,0 +1,6 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gb2312.txt b/Lib/test/cjkencodings/gb2312.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gb2312.txt @@ -0,0 +1,6 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? + diff --git a/Lib/test/cjkencodings/gbk-utf8.txt b/Lib/test/cjkencodings/gbk-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk-utf8.txt @@ -0,0 +1,14 @@ +Python?????????????????????????????????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????? +?????????????????????????????????????????????????????????????????????????????????????????????????????? +????????? Python ?????????????????? C library? +???????????????????????????????????????, ???????????????????????????????????????????????? +??????. ?????????????????????????????????, ???????????????????????????????????????????????? +library, ???????????? fast prototyping ??? programming language ??? +?????????. ???????????????????????? library ?????? C ??????, ??? Python ????????? +fast prototyping ??? programming language. ?????????????????????????????? +C library ?????? Python ???????????????????????????. ?????????????????????????????? +????????????????????????: + diff --git a/Lib/test/cjkencodings/gbk.txt b/Lib/test/cjkencodings/gbk.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/gbk.txt @@ -0,0 +1,14 @@ +Python???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????? +???????????????????????????????????????????????????????????????????? +?????? Python ???????????? C library? +?????Y???????????l????????, ?_?l???y?????w?????????????????? +?n?}. ???????_?l???y????????, ?????????????????????????_?l???? +library, ?K?????? fast prototyping ?? programming language ?? +??????. ???????S?S?????? library ???? C ????, ?? Python ?????? +fast prototyping ?? programming language. ???????????????????? +C library ???? Python ???h?????y????????. ???????????????????? +???????????}????: + diff --git a/Lib/test/cjkencodings/johab-utf8.txt b/Lib/test/cjkencodings/johab-utf8.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab-utf8.txt @@ -0,0 +1,9 @@ +???????????? ???????????? + +?????????!! ????????????????????? ??????????????? ?????? ?????? ???. . +??????????????? . . . . ????????? ????????? ?????? ! ! !???.??? +????????? ???????????????_??? ?????? ????????? ?????? ???????????? ????????? +?????? ?????? . . . . ????????? ?????? ???????????? ????????????????????? +????????? ! ! ????????? ????????? ????????? ???????????? ???????????? ????????? +???????????? ???????????? ?????? ???????????????????????????!! ???????????? ??????* + diff --git a/Lib/test/cjkencodings/johab.txt b/Lib/test/cjkencodings/johab.txt new file mode 100644 --- /dev/null +++ b/Lib/test/cjkencodings/johab.txt @@ -0,0 +1,9 @@ +???w?b?a ?\?????a + +?????s!! ?g???U???????? ?????z?????? ?w?? ???? ??. . +? %s: %s' % ( repr(csetch), repr(unich), exc.reason)) -def load_teststring(encoding): - from test import cjkencodings_test - return cjkencodings_test.teststring[encoding] +def load_teststring(name): + dir = os.path.join(os.path.dirname(__file__), 'cjkencodings') + with open(os.path.join(dir, name + '.txt'), 'rb') as f: + encoded = f.read() + with open(os.path.join(dir, name + '-utf8.txt'), 'rb') as f: + utf8 = f.read() + return encoded, utf8 diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -872,6 +872,66 @@ os.unlink(temparchive) shutil.rmtree(tempdir) + @unittest.skipUnless(hasattr(os, 'symlink'), "needs os.symlink") + def test_extractall_broken_symlinks(self): + # Test if extractall works properly when tarfile contains broken + # symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.symlink(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(target_file, arcname=os.path.basename(target_file)) + tar.close() + # remove the real file + os.unlink(source_file) + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with broken symlinked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) + + @unittest.skipUnless(hasattr(os, 'link'), "needs os.link") + def test_extractall_hardlinks(self): + # Test if extractall works properly when tarfile contains symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.link(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(source_file, arcname=os.path.basename(source_file)) + tar.add(target_file, arcname=os.path.basename(target_file)) + tar.close() + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with linked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) + class StreamWriteTest(WriteTestBase): mode = "w|" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,12 @@ Library ------- +- Issue #11088: don't crash when using F5 to run a script in IDLE on MacOSX + with Tk 8.5. + +- Issue #10154, #10090: change the normalization of UTF-8 to "UTF-8" instead + of "UTF8" in the locale module as the latter is not supported MacOSX and OpenBSD. + - Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET is set in shell. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed May 18 05:00:20 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 18 May 2011 05:00:20 +0200 Subject: [Python-checkins] Daily reference leaks (c52807b17e03): sum=0 Message-ID: results for c52807b17e03 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogyK37ER', '-x'] From python-checkins at python.org Wed May 18 13:43:28 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 18 May 2011 13:43:28 +0200 Subject: [Python-checkins] cpython (3.1): Backport commit 33543b4e0e5d from Python 3.2: #10801: In zipfile, support Message-ID: http://hg.python.org/cpython/rev/1f0f0e317873 changeset: 70183:1f0f0e317873 branch: 3.1 parent: 70172:28e410eb86af user: Victor Stinner date: Wed May 18 13:43:23 2011 +0200 summary: Backport commit 33543b4e0e5d from Python 3.2: #10801: In zipfile, support different encodings for the header and the filenames. Patch by MvL, test by Eli Bendersky. files: Lib/test/test_zipfile.py | 29 +++++++++++++++++++++++++-- Lib/zipfile.py | 8 ++++++- Misc/NEWS | 3 ++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -3,7 +3,13 @@ import zlib except ImportError: zlib = None -import zipfile, os, unittest, sys, shutil, struct, io +import io +import os +import shutil +import struct +import sys +import unittest +import zipfile from tempfile import TemporaryFile from random import randint, random @@ -14,6 +20,7 @@ TESTFN2 = TESTFN + "2" TESTFNDIR = TESTFN + "d" FIXEDTEST_SIZE = 1000 +DATAFILES_DIR = 'zipfile_datafiles' SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'), ('ziptest2dir/_ziptest2', 'qawsedrftg'), @@ -387,9 +394,25 @@ orig_zip.writestr(zinfo, data) orig_zip.close() + 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') + + print(fname) + zipfp = zipfile.ZipFile(fname) + try: + zipfp.extractall() + finally: + zipfp.close() + def tearDown(self): - os.remove(TESTFN) - os.remove(TESTFN2) + support.unlink(TESTFN) + support.unlink(TESTFN2) class TestZip64InSmallFiles(unittest.TestCase): # These tests test the ZIP64 functionality without using large files, diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -928,7 +928,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: raise BadZipfile( 'File name in directory %r and header %r differ.' % (zinfo.orig_filename, fname)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,6 +72,9 @@ Library ------- +- Issue #10801: In zipfile, support different encodings for the header and + the filenames. + - Issue #10154, #10090: change the normalization of UTF-8 to "UTF-8" instead of "UTF8" in the locale module as the latter is not supported MacOSX and OpenBSD. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 13:48:42 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 18 May 2011 13:48:42 +0200 Subject: [Python-checkins] cpython (3.1): Ooops, add the missing file of the backport of commit 33543b4e0e5d from Python Message-ID: http://hg.python.org/cpython/rev/243c78fbbb49 changeset: 70184:243c78fbbb49 branch: 3.1 user: Victor Stinner date: Wed May 18 13:48:41 2011 +0200 summary: Ooops, add the missing file of the backport of commit 33543b4e0e5d from Python 3.2 (#10801: In zipfile, support different encodings for the header and the filenames. Patch by MvL, test by Eli Bendersky.) files: Lib/test/zip_cp437_header.zip | Bin 1 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Lib/test/zip_cp437_header.zip b/Lib/test/zip_cp437_header.zip new file mode 100644 index 0000000000000000000000000000000000000000..f7c6cf170422c48ce1337a4c05843fe66a4b0bbf GIT binary patch literal 270 zc$^FHW at Zs#U}E54IGj1(Hjhth3p)b?11k`V0&!YqPHJ9aZfbmaW=Tf;#QZkBl8Tbz zujP-QGBE_;)G30lGrzP1MI$4V2m@|QAwU62V|4;PBScV)u)^V%0B=?{kQyc+Yz5NA GU>yL~Xgs?B -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 18:04:18 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 18 May 2011 18:04:18 +0200 Subject: [Python-checkins] cpython: Issue #8809: The SMTP_SSL constructor and SMTP.starttls() now support Message-ID: http://hg.python.org/cpython/rev/6737de76487b changeset: 70185:6737de76487b parent: 70180:c52807b17e03 user: Antoine Pitrou date: Wed May 18 18:03:09 2011 +0200 summary: Issue #8809: The SMTP_SSL constructor and SMTP.starttls() now support passing a `context` argument pointing to an ssl.SSLContext instance. Patch by Kasun Herath. files: Doc/library/smtplib.rst | 17 ++++++++++++-- Lib/smtplib.py | 31 +++++++++++++++++++++++---- Lib/test/test_smtpnet.py | 27 +++++++++++++++++++++++- Misc/NEWS | 4 +++ 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -49,7 +49,7 @@ Support for the :keyword:`with` statement was added. -.. class:: SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, certfile=None[, timeout]) +.. class:: SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, certfile=None[, timeout], context=None) A :class:`SMTP_SSL` instance behaves exactly the same as instances of :class:`SMTP`. :class:`SMTP_SSL` should be used for situations where SSL is @@ -57,11 +57,16 @@ not appropriate. If *host* is not specified, the local host is used. If *port* is zero, the standard SMTP-over-SSL port (465) is used. *keyfile* and *certfile* are also optional, and can contain a PEM formatted private key - and certificate chain file for the SSL connection. The optional *timeout* + and certificate chain file for the SSL connection. *context* also optional, can contain + a SSLContext, and is an alternative to keyfile and certfile; If it is specified both + keyfile and certfile must be None. The optional *timeout* parameter specifies a timeout in seconds for blocking operations like the connection attempt (if not specified, the global default timeout setting will be used). + .. versionchanged:: 3.3 + *context* was added. + .. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None) @@ -256,7 +261,7 @@ No suitable authentication method was found. -.. method:: SMTP.starttls(keyfile=None, certfile=None) +.. method:: SMTP.starttls(keyfile=None, certfile=None, context=None) Put the SMTP connection in TLS (Transport Layer Security) mode. All SMTP commands that follow will be encrypted. You should then call :meth:`ehlo` @@ -265,6 +270,9 @@ If *keyfile* and *certfile* are provided, these are passed to the :mod:`socket` module's :func:`ssl` function. + Optional *context* parameter is a :class:`ssl.SSLContext` object; This is an alternative to + using a keyfile and a certfile and if specified both *keyfile* and *certfile* should be None. + If there has been no previous ``EHLO`` or ``HELO`` command this session, this method tries ESMTP ``EHLO`` first. @@ -277,6 +285,9 @@ :exc:`RuntimeError` SSL/TLS support is not available to your Python interpreter. + .. versionchanged:: 3.3 + *context* was added. + .. method:: SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[]) diff --git a/Lib/smtplib.py b/Lib/smtplib.py --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -635,7 +635,7 @@ # We could not login sucessfully. Return result of last attempt. raise SMTPAuthenticationError(code, resp) - def starttls(self, keyfile=None, certfile=None): + def starttls(self, keyfile=None, certfile=None, context=None): """Puts the connection to the SMTP server into TLS mode. If there has been no previous EHLO or HELO command this session, this @@ -659,7 +659,16 @@ if resp == 220: if not _have_ssl: raise RuntimeError("No SSL support included in this Python") - self.sock = ssl.wrap_socket(self.sock, keyfile, certfile) + if context is not None and keyfile is not None: + raise ValueError("context and keyfile arguments are mutually " + "exclusive") + if context is not None and certfile is not None: + raise ValueError("context and certfile arguments are mutually " + "exclusive") + if context is not None: + self.sock = context.wrap_socket(self.sock) + else: + self.sock = ssl.wrap_socket(self.sock, keyfile, certfile) self.file = SSLFakeFile(self.sock) # RFC 3207: # The client MUST discard any knowledge obtained from @@ -815,23 +824,35 @@ support). If host is not specified, '' (the local host) is used. If port is omitted, the standard SMTP-over-SSL port (465) is used. keyfile and certfile are also optional - they can contain a PEM formatted private key and - certificate chain file for the SSL connection. + certificate chain file for the SSL connection. context also optional, can contain + a SSLContext, and is an alternative to keyfile and certfile; If it is specified both + keyfile and certfile must be None. """ default_port = SMTP_SSL_PORT def __init__(self, host='', port=0, local_hostname=None, keyfile=None, certfile=None, - timeout=socket._GLOBAL_DEFAULT_TIMEOUT): + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, context=None): + if context is not None and keyfile is not None: + raise ValueError("context and keyfile arguments are mutually " + "exclusive") + if context is not None and certfile is not None: + raise ValueError("context and certfile arguments are mutually " + "exclusive") self.keyfile = keyfile self.certfile = certfile + self.context = context SMTP.__init__(self, host, port, local_hostname, timeout) def _get_socket(self, host, port, timeout): if self.debuglevel > 0: print('connect:', (host, port), file=stderr) new_socket = socket.create_connection((host, port), timeout) - new_socket = ssl.wrap_socket(new_socket, self.keyfile, self.certfile) + if self.context is not None: + new_socket = self.context.wrap_socket(new_socket) + else: + new_socket = ssl.wrap_socket(new_socket, self.keyfile, self.certfile) self.file = SSLFakeFile(new_socket) return new_socket diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -3,12 +3,29 @@ import unittest from test import support import smtplib +import ssl support.requires("network") + +class SmtpTest(unittest.TestCase): + testServer = 'smtp.gmail.com' + remotePort = 25 + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + + def test_connect_starttls(self): + support.get_attribute(smtplib, 'SMTP_SSL') + with support.transient_internet(self.testServer): + server = smtplib.SMTP(self.testServer, self.remotePort) + server.starttls(context=self.context) + server.ehlo() + server.quit() + + class SmtpSSLTest(unittest.TestCase): testServer = 'smtp.gmail.com' remotePort = 465 + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) def test_connect(self): support.get_attribute(smtplib, 'SMTP_SSL') @@ -24,8 +41,16 @@ server.ehlo() server.quit() + def test_connect_using_sslcontext(self): + support.get_attribute(smtplib, 'SMTP_SSL') + with support.transient_internet(self.testServer): + server = smtplib.SMTP_SSL(self.testServer, self.remotePort, context=self.context) + server.ehlo() + server.quit() + + def test_main(): - support.run_unittest(SmtpSSLTest) + support.run_unittest(SmtpTest, SmtpSSLTest) if __name__ == "__main__": test_main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -153,6 +153,10 @@ Library ------- +- Issue #8809: The SMTP_SSL constructor and SMTP.starttls() now support + passing a ``context`` argument pointing to an ssl.SSLContext instance. + Patch by Kasun Herath. + - Issue #11088: don't crash when using F5 to run a script in IDLE on MacOSX with Tk 8.5. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 18:04:19 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 18 May 2011 18:04:19 +0200 Subject: [Python-checkins] cpython: Also protect ehlo() and quit() with the transient_internet() context manager Message-ID: http://hg.python.org/cpython/rev/ebe93fec1558 changeset: 70186:ebe93fec1558 user: Antoine Pitrou date: Wed May 18 18:04:04 2011 +0200 summary: Also protect ehlo() and quit() with the transient_internet() context manager files: Lib/test/test_smtpnet.py | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -18,8 +18,8 @@ with support.transient_internet(self.testServer): server = smtplib.SMTP(self.testServer, self.remotePort) server.starttls(context=self.context) - server.ehlo() - server.quit() + server.ehlo() + server.quit() class SmtpSSLTest(unittest.TestCase): @@ -31,22 +31,22 @@ support.get_attribute(smtplib, 'SMTP_SSL') with support.transient_internet(self.testServer): server = smtplib.SMTP_SSL(self.testServer, self.remotePort) - server.ehlo() - server.quit() + server.ehlo() + server.quit() def test_connect_default_port(self): support.get_attribute(smtplib, 'SMTP_SSL') with support.transient_internet(self.testServer): server = smtplib.SMTP_SSL(self.testServer) - server.ehlo() - server.quit() + server.ehlo() + server.quit() def test_connect_using_sslcontext(self): support.get_attribute(smtplib, 'SMTP_SSL') with support.transient_internet(self.testServer): server = smtplib.SMTP_SSL(self.testServer, self.remotePort, context=self.context) - server.ehlo() - server.quit() + server.ehlo() + server.quit() def test_main(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 18:52:34 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 18 May 2011 18:52:34 +0200 Subject: [Python-checkins] cpython (3.2): Issue #12065: connect_ex() on an SSL socket now returns the original errno Message-ID: http://hg.python.org/cpython/rev/019d8ccdf03b changeset: 70187:019d8ccdf03b branch: 3.2 parent: 70179:a6b4a00fb1c7 user: Antoine Pitrou date: Wed May 18 18:51:06 2011 +0200 summary: Issue #12065: connect_ex() on an SSL socket now returns the original errno when the socket's timeout expires (it used to return None). files: Lib/ssl.py | 24 +++++++++++++----------- Lib/test/test_ssl.py | 17 +++++++++++++++++ Misc/NEWS | 15 +++++++++++++++ 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -442,7 +442,7 @@ finally: self.settimeout(timeout) - def _real_connect(self, addr, return_errno): + def _real_connect(self, addr, connect_ex): if self.server_side: raise ValueError("can't connect in server-side mode") # Here we assume that the socket is client-side, and not @@ -451,17 +451,19 @@ raise ValueError("attempt to connect already-connected SSLSocket!") self._sslobj = self.context._wrap_socket(self, False, self.server_hostname) try: - socket.connect(self, addr) - if self.do_handshake_on_connect: - self.do_handshake() - except socket_error as e: - if return_errno: - return e.errno + if connect_ex: + rc = socket.connect_ex(self, addr) else: - self._sslobj = None - raise e - self._connected = True - return 0 + rc = None + socket.connect(self, addr) + if not rc: + if self.do_handshake_on_connect: + self.do_handshake() + self._connected = True + return rc + except socket_error: + self._sslobj = None + raise def connect(self, addr): """Connects to remote ADDR, and then wraps the connection in diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -519,6 +519,23 @@ finally: s.close() + def test_timeout_connect_ex(self): + # Issue #12065: on a timeout, connect_ex() should return the original + # errno (mimicking the behaviour of non-SSL sockets). + with support.transient_internet("svn.python.org"): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=SVN_PYTHON_ORG_ROOT_CERT, + do_handshake_on_connect=False) + try: + s.settimeout(0.0000001) + rc = s.connect_ex(('svn.python.org', 443)) + if rc == 0: + self.skipTest("svn.python.org responded too quickly") + self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK)) + finally: + s.close() + def test_connect_with_context(self): with support.transient_internet("svn.python.org"): # Same as test_connect, but with a separately created context diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,21 @@ Python News +++++++++++ +What's New in Python 3.2.2? +=========================== + +*Release date: XX-XXX-2011* + +Core and Builtins +----------------- + +Library +------- + +- Issue #12065: connect_ex() on an SSL socket now returns the original errno + when the socket's timeout expires (it used to return None). + + What's New in Python 3.2.1 release candidate 1? =============================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 18:52:35 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 18 May 2011 18:52:35 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Issue #12065: connect_ex() on an SSL socket now returns the original errno Message-ID: http://hg.python.org/cpython/rev/162ed9841f14 changeset: 70188:162ed9841f14 parent: 70186:ebe93fec1558 parent: 70187:019d8ccdf03b user: Antoine Pitrou date: Wed May 18 18:52:20 2011 +0200 summary: Issue #12065: connect_ex() on an SSL socket now returns the original errno when the socket's timeout expires (it used to return None). files: Lib/ssl.py | 24 +++++++++++++----------- Lib/test/test_ssl.py | 17 +++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -443,7 +443,7 @@ finally: self.settimeout(timeout) - def _real_connect(self, addr, return_errno): + def _real_connect(self, addr, connect_ex): if self.server_side: raise ValueError("can't connect in server-side mode") # Here we assume that the socket is client-side, and not @@ -452,17 +452,19 @@ raise ValueError("attempt to connect already-connected SSLSocket!") self._sslobj = self.context._wrap_socket(self, False, self.server_hostname) try: - socket.connect(self, addr) - if self.do_handshake_on_connect: - self.do_handshake() - except socket_error as e: - if return_errno: - return e.errno + if connect_ex: + rc = socket.connect_ex(self, addr) else: - self._sslobj = None - raise e - self._connected = True - return 0 + rc = None + socket.connect(self, addr) + if not rc: + if self.do_handshake_on_connect: + self.do_handshake() + self._connected = True + return rc + except socket_error: + self._sslobj = None + raise def connect(self, addr): """Connects to remote ADDR, and then wraps the connection in diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -519,6 +519,23 @@ finally: s.close() + def test_timeout_connect_ex(self): + # Issue #12065: on a timeout, connect_ex() should return the original + # errno (mimicking the behaviour of non-SSL sockets). + with support.transient_internet("svn.python.org"): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=SVN_PYTHON_ORG_ROOT_CERT, + do_handshake_on_connect=False) + try: + s.settimeout(0.0000001) + rc = s.connect_ex(('svn.python.org', 443)) + if rc == 0: + self.skipTest("svn.python.org responded too quickly") + self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK)) + finally: + s.close() + def test_connect_with_context(self): with support.transient_internet("svn.python.org"): # Same as test_connect, but with a separately created context diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -153,6 +153,9 @@ Library ------- +- Issue #12065: connect_ex() on an SSL socket now returns the original errno + when the socket's timeout expires (it used to return None). + - Issue #8809: The SMTP_SSL constructor and SMTP.starttls() now support passing a ``context`` argument pointing to an ssl.SSLContext instance. Patch by Kasun Herath. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 18:58:53 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 18 May 2011 18:58:53 +0200 Subject: [Python-checkins] cpython (3.2): Fix section title Message-ID: http://hg.python.org/cpython/rev/4b8b749ed1f0 changeset: 70189:4b8b749ed1f0 branch: 3.2 parent: 70187:019d8ccdf03b user: Antoine Pitrou date: Wed May 18 18:58:09 2011 +0200 summary: Fix section title files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,7 +2,7 @@ Python News +++++++++++ -What's New in Python 3.2.2? +What's New in Python 3.2.1? =========================== *Release date: XX-XXX-2011* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 18:58:53 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 18 May 2011 18:58:53 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): Null merge Message-ID: http://hg.python.org/cpython/rev/f0f4bcfde761 changeset: 70190:f0f4bcfde761 parent: 70188:162ed9841f14 parent: 70189:4b8b749ed1f0 user: Antoine Pitrou date: Wed May 18 18:58:48 2011 +0200 summary: Null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 20:02:55 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 18 May 2011 20:02:55 +0200 Subject: [Python-checkins] cpython: Skip test_smtpnet when ssl is not available Message-ID: http://hg.python.org/cpython/rev/05836e84e584 changeset: 70191:05836e84e584 user: Antoine Pitrou date: Wed May 18 20:02:50 2011 +0200 summary: Skip test_smtpnet when ssl is not available files: Lib/test/test_smtpnet.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -3,7 +3,8 @@ import unittest from test import support import smtplib -import ssl + +ssl = support.import_module("ssl") support.requires("network") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 18 21:28:45 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Wed, 18 May 2011 21:28:45 +0200 Subject: [Python-checkins] cpython: os.sendfile() test: fix "AttributeError: 'NoneType' object has no attribute Message-ID: http://hg.python.org/cpython/rev/c45e92bd4d81 changeset: 70192:c45e92bd4d81 user: Giampaolo Rodola' date: Wed May 18 21:28:39 2011 +0200 summary: os.sendfile() test: fix "AttributeError: 'NoneType' object has no attribute 'Thread'" when running tests with --without-threads option. reference: http://bugs.python.org/issue10882#msg136257 files: Lib/test/test_os.py | 147 ++++++++++++++++--------------- 1 files changed, 74 insertions(+), 73 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1309,89 +1309,90 @@ raise -class SendfileTestServer(asyncore.dispatcher, threading.Thread): +if threading is not None: + class SendfileTestServer(asyncore.dispatcher, threading.Thread): - class Handler(asynchat.async_chat): + class Handler(asynchat.async_chat): - def __init__(self, conn): - asynchat.async_chat.__init__(self, conn) - self.in_buffer = [] - self.closed = False - self.push(b"220 ready\r\n") + def __init__(self, conn): + asynchat.async_chat.__init__(self, conn) + self.in_buffer = [] + self.closed = False + self.push(b"220 ready\r\n") - def handle_read(self): - data = self.recv(4096) - self.in_buffer.append(data) + def handle_read(self): + data = self.recv(4096) + self.in_buffer.append(data) - def get_data(self): - return b''.join(self.in_buffer) + def get_data(self): + return b''.join(self.in_buffer) - def handle_close(self): + def handle_close(self): + self.close() + self.closed = True + + def handle_error(self): + raise + + def __init__(self, address): + threading.Thread.__init__(self) + asyncore.dispatcher.__init__(self) + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.bind(address) + self.listen(5) + self.host, self.port = self.socket.getsockname()[:2] + self.handler_instance = None + self._active = False + self._active_lock = threading.Lock() + + # --- public API + + @property + def running(self): + return self._active + + def start(self): + assert not self.running + self.__flag = threading.Event() + threading.Thread.start(self) + self.__flag.wait() + + def stop(self): + assert self.running + self._active = False + self.join() + + def wait(self): + # wait for handler connection to be closed, then stop the server + while not getattr(self.handler_instance, "closed", False): + time.sleep(0.001) + self.stop() + + # --- internals + + def run(self): + self._active = True + self.__flag.set() + while self._active and asyncore.socket_map: + self._active_lock.acquire() + asyncore.loop(timeout=0.001, count=1) + self._active_lock.release() + asyncore.close_all() + + def handle_accept(self): + conn, addr = self.accept() + self.handler_instance = self.Handler(conn) + + def handle_connect(self): self.close() - self.closed = True + handle_read = handle_connect + + def writable(self): + return 0 def handle_error(self): raise - def __init__(self, address): - threading.Thread.__init__(self) - asyncore.dispatcher.__init__(self) - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.bind(address) - self.listen(5) - self.host, self.port = self.socket.getsockname()[:2] - self.handler_instance = None - self._active = False - self._active_lock = threading.Lock() - - # --- public API - - @property - def running(self): - return self._active - - def start(self): - assert not self.running - self.__flag = threading.Event() - threading.Thread.start(self) - self.__flag.wait() - - def stop(self): - assert self.running - self._active = False - self.join() - - def wait(self): - # wait for handler connection to be closed, then stop the server - while not getattr(self.handler_instance, "closed", False): - time.sleep(0.001) - self.stop() - - # --- internals - - def run(self): - self._active = True - self.__flag.set() - while self._active and asyncore.socket_map: - self._active_lock.acquire() - asyncore.loop(timeout=0.001, count=1) - self._active_lock.release() - asyncore.close_all() - - def handle_accept(self): - conn, addr = self.accept() - self.handler_instance = self.Handler(conn) - - def handle_connect(self): - self.close() - handle_read = handle_connect - - def writable(self): - return 0 - - def handle_error(self): - raise - @unittest.skipUnless(threading is not None, "test needs threading module") @unittest.skipUnless(hasattr(os, 'sendfile'), "test needs os.sendfile()") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 19 00:28:58 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 19 May 2011 00:28:58 +0200 Subject: [Python-checkins] cpython (2.7): Minor code cleanup. Message-ID: http://hg.python.org/cpython/rev/828e29cee88e changeset: 70193:828e29cee88e branch: 2.7 parent: 70182:31cd146d725c user: Raymond Hettinger date: Wed May 18 17:28:50 2011 -0500 summary: Minor code cleanup. files: Lib/random.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -317,7 +317,7 @@ n = len(population) if not 0 <= k <= n: - raise ValueError, "sample larger than population" + raise ValueError("sample larger than population") random = self.random _int = int result = [None] * k -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu May 19 05:00:28 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 19 May 2011 05:00:28 +0200 Subject: [Python-checkins] Daily reference leaks (c45e92bd4d81): sum=0 Message-ID: results for c45e92bd4d81 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogUbZlf6', '-x'] From python-checkins at python.org Thu May 19 13:08:16 2011 From: python-checkins at python.org (tarek.ziade) Date: Thu, 19 May 2011 13:08:16 +0200 Subject: [Python-checkins] cpython: initial import of the packaging package in the standard library Message-ID: http://hg.python.org/cpython/rev/1a31c3be88b1 changeset: 70194:1a31c3be88b1 parent: 70192:c45e92bd4d81 user: Tarek Ziade date: Thu May 19 13:07:25 2011 +0200 summary: initial import of the packaging package in the standard library files: Lib/packaging/__init__.py | 17 + Lib/packaging/_trove.py | 552 +++ Lib/packaging/command/__init__.py | 56 + Lib/packaging/command/bdist.py | 141 + Lib/packaging/command/bdist_dumb.py | 137 + Lib/packaging/command/bdist_msi.py | 740 +++++ Lib/packaging/command/bdist_wininst.py | 342 ++ Lib/packaging/command/build.py | 151 + Lib/packaging/command/build_clib.py | 198 + Lib/packaging/command/build_ext.py | 666 ++++ Lib/packaging/command/build_py.py | 410 ++ Lib/packaging/command/build_scripts.py | 132 + Lib/packaging/command/check.py | 88 + Lib/packaging/command/clean.py | 76 + Lib/packaging/command/cmd.py | 440 +++ Lib/packaging/command/command_template | 35 + Lib/packaging/command/config.py | 351 ++ Lib/packaging/command/install_data.py | 79 + Lib/packaging/command/install_dist.py | 625 ++++ Lib/packaging/command/install_distinfo.py | 175 + Lib/packaging/command/install_headers.py | 43 + Lib/packaging/command/install_lib.py | 222 + Lib/packaging/command/install_scripts.py | 59 + Lib/packaging/command/register.py | 282 + Lib/packaging/command/sdist.py | 375 ++ Lib/packaging/command/test.py | 81 + Lib/packaging/command/upload.py | 201 + Lib/packaging/command/upload_docs.py | 173 + Lib/packaging/command/wininst-10.0-amd64.exe | Bin Lib/packaging/command/wininst-10.0.exe | Bin Lib/packaging/command/wininst-6.0.exe | Bin Lib/packaging/command/wininst-7.1.exe | Bin Lib/packaging/command/wininst-8.0.exe | Bin Lib/packaging/command/wininst-9.0-amd64.exe | Bin Lib/packaging/command/wininst-9.0.exe | Bin Lib/packaging/compat.py | 57 + Lib/packaging/compiler/__init__.py | 282 + Lib/packaging/compiler/bcppcompiler.py | 356 ++ Lib/packaging/compiler/ccompiler.py | 868 +++++ Lib/packaging/compiler/cygwinccompiler.py | 355 ++ Lib/packaging/compiler/extension.py | 121 + Lib/packaging/compiler/msvc9compiler.py | 720 ++++ Lib/packaging/compiler/msvccompiler.py | 636 ++++ Lib/packaging/compiler/unixccompiler.py | 339 ++ Lib/packaging/config.py | 357 ++ Lib/packaging/create.py | 693 ++++ Lib/packaging/database.py | 627 ++++ Lib/packaging/depgraph.py | 270 + Lib/packaging/dist.py | 819 +++++ Lib/packaging/errors.py | 142 + Lib/packaging/fancy_getopt.py | 451 +++ Lib/packaging/install.py | 483 +++ Lib/packaging/manifest.py | 372 ++ Lib/packaging/markers.py | 187 + Lib/packaging/metadata.py | 552 +++ Lib/packaging/pypi/__init__.py | 9 + Lib/packaging/pypi/base.py | 48 + Lib/packaging/pypi/dist.py | 547 +++ Lib/packaging/pypi/errors.py | 39 + Lib/packaging/pypi/mirrors.py | 52 + Lib/packaging/pypi/simple.py | 452 +++ Lib/packaging/pypi/wrapper.py | 99 + Lib/packaging/pypi/xmlrpc.py | 200 + Lib/packaging/resources.py | 25 + Lib/packaging/run.py | 645 ++++ Lib/packaging/tests/LONG_DESC.txt | 44 + Lib/packaging/tests/PKG-INFO | 57 + Lib/packaging/tests/SETUPTOOLS-PKG-INFO | 182 + Lib/packaging/tests/SETUPTOOLS-PKG-INFO2 | 183 + Lib/packaging/tests/__init__.py | 133 + Lib/packaging/tests/__main__.py | 20 + Lib/packaging/tests/fake_dists/babar-0.1.dist-info/INSTALLER | Bin Lib/packaging/tests/fake_dists/babar-0.1.dist-info/METADATA | 4 + Lib/packaging/tests/fake_dists/babar-0.1.dist-info/RECORD | Bin Lib/packaging/tests/fake_dists/babar-0.1.dist-info/REQUESTED | Bin Lib/packaging/tests/fake_dists/babar-0.1.dist-info/RESOURCES | 2 + Lib/packaging/tests/fake_dists/babar.cfg | 1 + Lib/packaging/tests/fake_dists/babar.png | Bin Lib/packaging/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO | 6 + Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/PKG-INFO | 18 + Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/SOURCES.txt | Bin Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/dependency_links.txt | 1 + Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/entry_points.txt | 3 + Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/not-zip-safe | 1 + Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/requires.txt | 6 + Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/top_level.txt | Bin Lib/packaging/tests/fake_dists/cheese-2.0.2.egg-info | 5 + Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER | Bin Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA | 9 + Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD | Bin Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED | Bin Lib/packaging/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py | 1 + Lib/packaging/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py | 10 + Lib/packaging/tests/fake_dists/choxie-2.0.0.9/truffles.py | 5 + Lib/packaging/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO | 5 + Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/INSTALLER | Bin Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/METADATA | 5 + Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/RECORD | Bin Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/REQUESTED | Bin Lib/packaging/tests/fake_dists/grammar-1.0a4/grammar/__init__.py | 1 + Lib/packaging/tests/fake_dists/grammar-1.0a4/grammar/utils.py | 8 + Lib/packaging/tests/fake_dists/nut-funkyversion.egg-info | 3 + Lib/packaging/tests/fake_dists/strawberry-0.6.egg | Bin Lib/packaging/tests/fake_dists/towel_stuff-0.1.dist-info/INSTALLER | Bin Lib/packaging/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA | 7 + Lib/packaging/tests/fake_dists/towel_stuff-0.1.dist-info/RECORD | Bin Lib/packaging/tests/fake_dists/towel_stuff-0.1.dist-info/REQUESTED | Bin Lib/packaging/tests/fake_dists/towel_stuff-0.1/towel_stuff/__init__.py | 18 + Lib/packaging/tests/fake_dists/truffles-5.0.egg-info | 3 + Lib/packaging/tests/fixer/__init__.py | Bin Lib/packaging/tests/fixer/fix_idioms.py | 134 + Lib/packaging/tests/pypi_server.py | 444 +++ Lib/packaging/tests/pypi_test_server.py | 59 + Lib/packaging/tests/pypiserver/downloads_with_md5/packages/source/f/foobar/foobar-0.1.tar.gz | Bin Lib/packaging/tests/pypiserver/downloads_with_md5/simple/badmd5/badmd5-0.1.tar.gz | Bin Lib/packaging/tests/pypiserver/downloads_with_md5/simple/badmd5/index.html | 3 + Lib/packaging/tests/pypiserver/downloads_with_md5/simple/foobar/index.html | 3 + Lib/packaging/tests/pypiserver/downloads_with_md5/simple/index.html | 2 + Lib/packaging/tests/pypiserver/foo_bar_baz/simple/bar/index.html | 6 + Lib/packaging/tests/pypiserver/foo_bar_baz/simple/baz/index.html | 6 + Lib/packaging/tests/pypiserver/foo_bar_baz/simple/foo/index.html | 6 + Lib/packaging/tests/pypiserver/foo_bar_baz/simple/index.html | 3 + Lib/packaging/tests/pypiserver/project_list/simple/index.html | 5 + Lib/packaging/tests/pypiserver/test_found_links/simple/foobar/index.html | 6 + Lib/packaging/tests/pypiserver/test_found_links/simple/index.html | 1 + Lib/packaging/tests/pypiserver/test_pypi_server/external/index.html | 1 + Lib/packaging/tests/pypiserver/test_pypi_server/simple/index.html | 1 + Lib/packaging/tests/pypiserver/with_externals/external/external.html | 3 + Lib/packaging/tests/pypiserver/with_externals/simple/foobar/index.html | 4 + Lib/packaging/tests/pypiserver/with_externals/simple/index.html | 1 + Lib/packaging/tests/pypiserver/with_norel_links/external/homepage.html | 7 + Lib/packaging/tests/pypiserver/with_norel_links/external/nonrel.html | 1 + Lib/packaging/tests/pypiserver/with_norel_links/simple/foobar/index.html | 6 + Lib/packaging/tests/pypiserver/with_norel_links/simple/index.html | 1 + Lib/packaging/tests/pypiserver/with_real_externals/simple/foobar/index.html | 4 + Lib/packaging/tests/pypiserver/with_real_externals/simple/index.html | 1 + Lib/packaging/tests/support.py | 259 + Lib/packaging/tests/test_ccompiler.py | 15 + Lib/packaging/tests/test_command_bdist.py | 77 + Lib/packaging/tests/test_command_bdist_dumb.py | 103 + Lib/packaging/tests/test_command_bdist_msi.py | 25 + Lib/packaging/tests/test_command_bdist_wininst.py | 32 + Lib/packaging/tests/test_command_build.py | 55 + Lib/packaging/tests/test_command_build_clib.py | 141 + Lib/packaging/tests/test_command_build_ext.py | 353 ++ Lib/packaging/tests/test_command_build_py.py | 124 + Lib/packaging/tests/test_command_build_scripts.py | 112 + Lib/packaging/tests/test_command_check.py | 131 + Lib/packaging/tests/test_command_clean.py | 48 + Lib/packaging/tests/test_command_cmd.py | 101 + Lib/packaging/tests/test_command_config.py | 76 + Lib/packaging/tests/test_command_install_data.py | 80 + Lib/packaging/tests/test_command_install_dist.py | 210 + Lib/packaging/tests/test_command_install_distinfo.py | 192 + Lib/packaging/tests/test_command_install_headers.py | 38 + Lib/packaging/tests/test_command_install_lib.py | 111 + Lib/packaging/tests/test_command_install_scripts.py | 78 + Lib/packaging/tests/test_command_register.py | 259 + Lib/packaging/tests/test_command_sdist.py | 407 ++ Lib/packaging/tests/test_command_test.py | 225 + Lib/packaging/tests/test_command_upload.py | 157 + Lib/packaging/tests/test_command_upload_docs.py | 205 + Lib/packaging/tests/test_compiler.py | 66 + Lib/packaging/tests/test_config.py | 424 ++ Lib/packaging/tests/test_create.py | 235 + Lib/packaging/tests/test_cygwinccompiler.py | 88 + Lib/packaging/tests/test_database.py | 506 +++ Lib/packaging/tests/test_depgraph.py | 301 ++ Lib/packaging/tests/test_dist.py | 445 +++ Lib/packaging/tests/test_extension.py | 15 + Lib/packaging/tests/test_install.py | 353 ++ Lib/packaging/tests/test_manifest.py | 72 + Lib/packaging/tests/test_markers.py | 71 + Lib/packaging/tests/test_metadata.py | 279 + Lib/packaging/tests/test_mixin2to3.py | 75 + Lib/packaging/tests/test_msvc9compiler.py | 140 + Lib/packaging/tests/test_pypi_dist.py | 277 + Lib/packaging/tests/test_pypi_server.py | 81 + Lib/packaging/tests/test_pypi_simple.py | 326 ++ Lib/packaging/tests/test_pypi_xmlrpc.py | 93 + Lib/packaging/tests/test_resources.py | 168 + Lib/packaging/tests/test_run.py | 62 + Lib/packaging/tests/test_uninstall.py | 99 + Lib/packaging/tests/test_unixccompiler.py | 132 + Lib/packaging/tests/test_util.py | 928 ++++++ Lib/packaging/tests/test_version.py | 252 + Lib/packaging/util.py | 1451 ++++++++++ Lib/packaging/version.py | 449 +++ Lib/sysconfig.cfg | 111 + Lib/sysconfig.py | 277 +- Lib/test/test_packaging.py | 5 + Lib/test/test_sysconfig.py | 27 +- Tools/scripts/pysetup3 | 4 + 193 files changed, 30376 insertions(+), 149 deletions(-) diff --git a/Lib/packaging/__init__.py b/Lib/packaging/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/__init__.py @@ -0,0 +1,17 @@ +"""Support for packaging, distribution and installation of Python projects. + +Third-party tools can use parts of packaging as building blocks +without causing the other modules to be imported: + + import packaging.version + import packaging.metadata + import packaging.pypi.simple + import packaging.tests.pypi_server +""" + +from logging import getLogger + +__all__ = ['__version__', 'logger'] + +__version__ = "1.0a3" +logger = getLogger('packaging') diff --git a/Lib/packaging/_trove.py b/Lib/packaging/_trove.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/_trove.py @@ -0,0 +1,552 @@ +"""Temporary helper for create.""" + +# XXX get the list from PyPI and cache it instead of hardcoding + +# XXX see if it would be more useful to store it as another structure +# than a list of strings + +all_classifiers = [ +'Development Status :: 1 - Planning', +'Development Status :: 2 - Pre-Alpha', +'Development Status :: 3 - Alpha', +'Development Status :: 4 - Beta', +'Development Status :: 5 - Production/Stable', +'Development Status :: 6 - Mature', +'Development Status :: 7 - Inactive', +'Environment :: Console', +'Environment :: Console :: Curses', +'Environment :: Console :: Framebuffer', +'Environment :: Console :: Newt', +'Environment :: Console :: svgalib', +"Environment :: Handhelds/PDA's", +'Environment :: MacOS X', +'Environment :: MacOS X :: Aqua', +'Environment :: MacOS X :: Carbon', +'Environment :: MacOS X :: Cocoa', +'Environment :: No Input/Output (Daemon)', +'Environment :: Other Environment', +'Environment :: Plugins', +'Environment :: Web Environment', +'Environment :: Web Environment :: Buffet', +'Environment :: Web Environment :: Mozilla', +'Environment :: Web Environment :: ToscaWidgets', +'Environment :: Win32 (MS Windows)', +'Environment :: X11 Applications', +'Environment :: X11 Applications :: Gnome', +'Environment :: X11 Applications :: GTK', +'Environment :: X11 Applications :: KDE', +'Environment :: X11 Applications :: Qt', +'Framework :: BFG', +'Framework :: Buildout', +'Framework :: Chandler', +'Framework :: CubicWeb', +'Framework :: Django', +'Framework :: IDLE', +'Framework :: Paste', +'Framework :: Plone', +'Framework :: Pylons', +'Framework :: Setuptools Plugin', +'Framework :: Trac', +'Framework :: TurboGears', +'Framework :: TurboGears :: Applications', +'Framework :: TurboGears :: Widgets', +'Framework :: Twisted', +'Framework :: ZODB', +'Framework :: Zope2', +'Framework :: Zope3', +'Intended Audience :: Customer Service', +'Intended Audience :: Developers', +'Intended Audience :: Education', +'Intended Audience :: End Users/Desktop', +'Intended Audience :: Financial and Insurance Industry', +'Intended Audience :: Healthcare Industry', +'Intended Audience :: Information Technology', +'Intended Audience :: Legal Industry', +'Intended Audience :: Manufacturing', +'Intended Audience :: Other Audience', +'Intended Audience :: Religion', +'Intended Audience :: Science/Research', +'Intended Audience :: System Administrators', +'Intended Audience :: Telecommunications Industry', +'License :: Aladdin Free Public License (AFPL)', +'License :: DFSG approved', +'License :: Eiffel Forum License (EFL)', +'License :: Free For Educational Use', +'License :: Free For Home Use', +'License :: Free for non-commercial use', +'License :: Freely Distributable', +'License :: Free To Use But Restricted', +'License :: Freeware', +'License :: Netscape Public License (NPL)', +'License :: Nokia Open Source License (NOKOS)', +'License :: OSI Approved', +'License :: OSI Approved :: Academic Free License (AFL)', +'License :: OSI Approved :: Apache Software License', +'License :: OSI Approved :: Apple Public Source License', +'License :: OSI Approved :: Artistic License', +'License :: OSI Approved :: Attribution Assurance License', +'License :: OSI Approved :: BSD License', +'License :: OSI Approved :: Common Public License', +'License :: OSI Approved :: Eiffel Forum License', +'License :: OSI Approved :: European Union Public Licence 1.0 (EUPL 1.0)', +'License :: OSI Approved :: European Union Public Licence 1.1 (EUPL 1.1)', +'License :: OSI Approved :: GNU Affero General Public License v3', +'License :: OSI Approved :: GNU Free Documentation License (FDL)', +'License :: OSI Approved :: GNU General Public License (GPL)', +'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', +'License :: OSI Approved :: IBM Public License', +'License :: OSI Approved :: Intel Open Source License', +'License :: OSI Approved :: ISC License (ISCL)', +'License :: OSI Approved :: Jabber Open Source License', +'License :: OSI Approved :: MIT License', +'License :: OSI Approved :: MITRE Collaborative Virtual Workspace License (CVW)', +'License :: OSI Approved :: Motosoto License', +'License :: OSI Approved :: Mozilla Public License 1.0 (MPL)', +'License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)', +'License :: OSI Approved :: Nethack General Public License', +'License :: OSI Approved :: Nokia Open Source License', +'License :: OSI Approved :: Open Group Test Suite License', +'License :: OSI Approved :: Python License (CNRI Python License)', +'License :: OSI Approved :: Python Software Foundation License', +'License :: OSI Approved :: Qt Public License (QPL)', +'License :: OSI Approved :: Ricoh Source Code Public License', +'License :: OSI Approved :: Sleepycat License', +'License :: OSI Approved :: Sun Industry Standards Source License (SISSL)', +'License :: OSI Approved :: Sun Public License', +'License :: OSI Approved :: University of Illinois/NCSA Open Source License', +'License :: OSI Approved :: Vovida Software License 1.0', +'License :: OSI Approved :: W3C License', +'License :: OSI Approved :: X.Net License', +'License :: OSI Approved :: zlib/libpng License', +'License :: OSI Approved :: Zope Public License', +'License :: Other/Proprietary License', +'License :: Public Domain', +'License :: Repoze Public License', +'Natural Language :: Afrikaans', +'Natural Language :: Arabic', +'Natural Language :: Bengali', +'Natural Language :: Bosnian', +'Natural Language :: Bulgarian', +'Natural Language :: Catalan', +'Natural Language :: Chinese (Simplified)', +'Natural Language :: Chinese (Traditional)', +'Natural Language :: Croatian', +'Natural Language :: Czech', +'Natural Language :: Danish', +'Natural Language :: Dutch', +'Natural Language :: English', +'Natural Language :: Esperanto', +'Natural Language :: Finnish', +'Natural Language :: French', +'Natural Language :: German', +'Natural Language :: Greek', +'Natural Language :: Hebrew', +'Natural Language :: Hindi', +'Natural Language :: Hungarian', +'Natural Language :: Icelandic', +'Natural Language :: Indonesian', +'Natural Language :: Italian', +'Natural Language :: Japanese', +'Natural Language :: Javanese', +'Natural Language :: Korean', +'Natural Language :: Latin', +'Natural Language :: Latvian', +'Natural Language :: Macedonian', +'Natural Language :: Malay', +'Natural Language :: Marathi', +'Natural Language :: Norwegian', +'Natural Language :: Panjabi', +'Natural Language :: Persian', +'Natural Language :: Polish', +'Natural Language :: Portuguese', +'Natural Language :: Portuguese (Brazilian)', +'Natural Language :: Romanian', +'Natural Language :: Russian', +'Natural Language :: Serbian', +'Natural Language :: Slovak', +'Natural Language :: Slovenian', +'Natural Language :: Spanish', +'Natural Language :: Swedish', +'Natural Language :: Tamil', +'Natural Language :: Telugu', +'Natural Language :: Thai', +'Natural Language :: Turkish', +'Natural Language :: Ukranian', +'Natural Language :: Urdu', +'Natural Language :: Vietnamese', +'Operating System :: BeOS', +'Operating System :: MacOS', +'Operating System :: MacOS :: MacOS 9', +'Operating System :: MacOS :: MacOS X', +'Operating System :: Microsoft', +'Operating System :: Microsoft :: MS-DOS', +'Operating System :: Microsoft :: Windows', +'Operating System :: Microsoft :: Windows :: Windows 3.1 or Earlier', +'Operating System :: Microsoft :: Windows :: Windows 95/98/2000', +'Operating System :: Microsoft :: Windows :: Windows CE', +'Operating System :: Microsoft :: Windows :: Windows NT/2000', +'Operating System :: OS/2', +'Operating System :: OS Independent', +'Operating System :: Other OS', +'Operating System :: PalmOS', +'Operating System :: PDA Systems', +'Operating System :: POSIX', +'Operating System :: POSIX :: AIX', +'Operating System :: POSIX :: BSD', +'Operating System :: POSIX :: BSD :: BSD/OS', +'Operating System :: POSIX :: BSD :: FreeBSD', +'Operating System :: POSIX :: BSD :: NetBSD', +'Operating System :: POSIX :: BSD :: OpenBSD', +'Operating System :: POSIX :: GNU Hurd', +'Operating System :: POSIX :: HP-UX', +'Operating System :: POSIX :: IRIX', +'Operating System :: POSIX :: Linux', +'Operating System :: POSIX :: Other', +'Operating System :: POSIX :: SCO', +'Operating System :: POSIX :: SunOS/Solaris', +'Operating System :: Unix', +'Programming Language :: Ada', +'Programming Language :: APL', +'Programming Language :: ASP', +'Programming Language :: Assembly', +'Programming Language :: Awk', +'Programming Language :: Basic', +'Programming Language :: C', +'Programming Language :: C#', +'Programming Language :: C++', +'Programming Language :: Cold Fusion', +'Programming Language :: Cython', +'Programming Language :: Delphi/Kylix', +'Programming Language :: Dylan', +'Programming Language :: Eiffel', +'Programming Language :: Emacs-Lisp', +'Programming Language :: Erlang', +'Programming Language :: Euler', +'Programming Language :: Euphoria', +'Programming Language :: Forth', +'Programming Language :: Fortran', +'Programming Language :: Haskell', +'Programming Language :: Java', +'Programming Language :: JavaScript', +'Programming Language :: Lisp', +'Programming Language :: Logo', +'Programming Language :: ML', +'Programming Language :: Modula', +'Programming Language :: Objective C', +'Programming Language :: Object Pascal', +'Programming Language :: OCaml', +'Programming Language :: Other', +'Programming Language :: Other Scripting Engines', +'Programming Language :: Pascal', +'Programming Language :: Perl', +'Programming Language :: PHP', +'Programming Language :: Pike', +'Programming Language :: Pliant', +'Programming Language :: PL/SQL', +'Programming Language :: PROGRESS', +'Programming Language :: Prolog', +'Programming Language :: Python', +'Programming Language :: Python :: 2', +'Programming Language :: Python :: 2.3', +'Programming Language :: Python :: 2.4', +'Programming Language :: Python :: 2.5', +'Programming Language :: Python :: 2.6', +'Programming Language :: Python :: 2.7', +'Programming Language :: Python :: 3', +'Programming Language :: Python :: 3.0', +'Programming Language :: Python :: 3.1', +'Programming Language :: Python :: 3.2', +'Programming Language :: REBOL', +'Programming Language :: Rexx', +'Programming Language :: Ruby', +'Programming Language :: Scheme', +'Programming Language :: Simula', +'Programming Language :: Smalltalk', +'Programming Language :: SQL', +'Programming Language :: Tcl', +'Programming Language :: Unix Shell', +'Programming Language :: Visual Basic', +'Programming Language :: XBasic', +'Programming Language :: YACC', +'Programming Language :: Zope', +'Topic :: Adaptive Technologies', +'Topic :: Artistic Software', +'Topic :: Communications', +'Topic :: Communications :: BBS', +'Topic :: Communications :: Chat', +'Topic :: Communications :: Chat :: AOL Instant Messenger', +'Topic :: Communications :: Chat :: ICQ', +'Topic :: Communications :: Chat :: Internet Relay Chat', +'Topic :: Communications :: Chat :: Unix Talk', +'Topic :: Communications :: Conferencing', +'Topic :: Communications :: Email', +'Topic :: Communications :: Email :: Address Book', +'Topic :: Communications :: Email :: Email Clients (MUA)', +'Topic :: Communications :: Email :: Filters', +'Topic :: Communications :: Email :: Mailing List Servers', +'Topic :: Communications :: Email :: Mail Transport Agents', +'Topic :: Communications :: Email :: Post-Office', +'Topic :: Communications :: Email :: Post-Office :: IMAP', +'Topic :: Communications :: Email :: Post-Office :: POP3', +'Topic :: Communications :: Fax', +'Topic :: Communications :: FIDO', +'Topic :: Communications :: File Sharing', +'Topic :: Communications :: File Sharing :: Gnutella', +'Topic :: Communications :: File Sharing :: Napster', +'Topic :: Communications :: Ham Radio', +'Topic :: Communications :: Internet Phone', +'Topic :: Communications :: Telephony', +'Topic :: Communications :: Usenet News', +'Topic :: Database', +'Topic :: Database :: Database Engines/Servers', +'Topic :: Database :: Front-Ends', +'Topic :: Desktop Environment', +'Topic :: Desktop Environment :: File Managers', +'Topic :: Desktop Environment :: Gnome', +'Topic :: Desktop Environment :: GNUstep', +'Topic :: Desktop Environment :: K Desktop Environment (KDE)', +'Topic :: Desktop Environment :: K Desktop Environment (KDE) :: Themes', +'Topic :: Desktop Environment :: PicoGUI', +'Topic :: Desktop Environment :: PicoGUI :: Applications', +'Topic :: Desktop Environment :: PicoGUI :: Themes', +'Topic :: Desktop Environment :: Screen Savers', +'Topic :: Desktop Environment :: Window Managers', +'Topic :: Desktop Environment :: Window Managers :: Afterstep', +'Topic :: Desktop Environment :: Window Managers :: Afterstep :: Themes', +'Topic :: Desktop Environment :: Window Managers :: Applets', +'Topic :: Desktop Environment :: Window Managers :: Blackbox', +'Topic :: Desktop Environment :: Window Managers :: Blackbox :: Themes', +'Topic :: Desktop Environment :: Window Managers :: CTWM', +'Topic :: Desktop Environment :: Window Managers :: CTWM :: Themes', +'Topic :: Desktop Environment :: Window Managers :: Enlightenment', +'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Epplets', +'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR15', +'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR16', +'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR17', +'Topic :: Desktop Environment :: Window Managers :: Fluxbox', +'Topic :: Desktop Environment :: Window Managers :: Fluxbox :: Themes', +'Topic :: Desktop Environment :: Window Managers :: FVWM', +'Topic :: Desktop Environment :: Window Managers :: FVWM :: Themes', +'Topic :: Desktop Environment :: Window Managers :: IceWM', +'Topic :: Desktop Environment :: Window Managers :: IceWM :: Themes', +'Topic :: Desktop Environment :: Window Managers :: MetaCity', +'Topic :: Desktop Environment :: Window Managers :: MetaCity :: Themes', +'Topic :: Desktop Environment :: Window Managers :: Oroborus', +'Topic :: Desktop Environment :: Window Managers :: Oroborus :: Themes', +'Topic :: Desktop Environment :: Window Managers :: Sawfish', +'Topic :: Desktop Environment :: Window Managers :: Sawfish :: Themes 0.30', +'Topic :: Desktop Environment :: Window Managers :: Sawfish :: Themes pre-0.30', +'Topic :: Desktop Environment :: Window Managers :: Waimea', +'Topic :: Desktop Environment :: Window Managers :: Waimea :: Themes', +'Topic :: Desktop Environment :: Window Managers :: Window Maker', +'Topic :: Desktop Environment :: Window Managers :: Window Maker :: Applets', +'Topic :: Desktop Environment :: Window Managers :: Window Maker :: Themes', +'Topic :: Desktop Environment :: Window Managers :: XFCE', +'Topic :: Desktop Environment :: Window Managers :: XFCE :: Themes', +'Topic :: Documentation', +'Topic :: Education', +'Topic :: Education :: Computer Aided Instruction (CAI)', +'Topic :: Education :: Testing', +'Topic :: Games/Entertainment', +'Topic :: Games/Entertainment :: Arcade', +'Topic :: Games/Entertainment :: Board Games', +'Topic :: Games/Entertainment :: First Person Shooters', +'Topic :: Games/Entertainment :: Fortune Cookies', +'Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)', +'Topic :: Games/Entertainment :: Puzzle Games', +'Topic :: Games/Entertainment :: Real Time Strategy', +'Topic :: Games/Entertainment :: Role-Playing', +'Topic :: Games/Entertainment :: Side-Scrolling/Arcade Games', +'Topic :: Games/Entertainment :: Simulation', +'Topic :: Games/Entertainment :: Turn Based Strategy', +'Topic :: Home Automation', +'Topic :: Internet', +'Topic :: Internet :: File Transfer Protocol (FTP)', +'Topic :: Internet :: Finger', +'Topic :: Internet :: Log Analysis', +'Topic :: Internet :: Name Service (DNS)', +'Topic :: Internet :: Proxy Servers', +'Topic :: Internet :: WAP', +'Topic :: Internet :: WWW/HTTP', +'Topic :: Internet :: WWW/HTTP :: Browsers', +'Topic :: Internet :: WWW/HTTP :: Dynamic Content', +'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries', +'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Message Boards', +'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: News/Diary', +'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Page Counters', +'Topic :: Internet :: WWW/HTTP :: HTTP Servers', +'Topic :: Internet :: WWW/HTTP :: Indexing/Search', +'Topic :: Internet :: WWW/HTTP :: Site Management', +'Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking', +'Topic :: Internet :: WWW/HTTP :: WSGI', +'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', +'Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware', +'Topic :: Internet :: WWW/HTTP :: WSGI :: Server', +'Topic :: Internet :: Z39.50', +'Topic :: Multimedia', +'Topic :: Multimedia :: Graphics', +'Topic :: Multimedia :: Graphics :: 3D Modeling', +'Topic :: Multimedia :: Graphics :: 3D Rendering', +'Topic :: Multimedia :: Graphics :: Capture', +'Topic :: Multimedia :: Graphics :: Capture :: Digital Camera', +'Topic :: Multimedia :: Graphics :: Capture :: Scanners', +'Topic :: Multimedia :: Graphics :: Capture :: Screen Capture', +'Topic :: Multimedia :: Graphics :: Editors', +'Topic :: Multimedia :: Graphics :: Editors :: Raster-Based', +'Topic :: Multimedia :: Graphics :: Editors :: Vector-Based', +'Topic :: Multimedia :: Graphics :: Graphics Conversion', +'Topic :: Multimedia :: Graphics :: Presentation', +'Topic :: Multimedia :: Graphics :: Viewers', +'Topic :: Multimedia :: Sound/Audio', +'Topic :: Multimedia :: Sound/Audio :: Analysis', +'Topic :: Multimedia :: Sound/Audio :: Capture/Recording', +'Topic :: Multimedia :: Sound/Audio :: CD Audio', +'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Playing', +'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Ripping', +'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Writing', +'Topic :: Multimedia :: Sound/Audio :: Conversion', +'Topic :: Multimedia :: Sound/Audio :: Editors', +'Topic :: Multimedia :: Sound/Audio :: MIDI', +'Topic :: Multimedia :: Sound/Audio :: Mixers', +'Topic :: Multimedia :: Sound/Audio :: Players', +'Topic :: Multimedia :: Sound/Audio :: Players :: MP3', +'Topic :: Multimedia :: Sound/Audio :: Sound Synthesis', +'Topic :: Multimedia :: Sound/Audio :: Speech', +'Topic :: Multimedia :: Video', +'Topic :: Multimedia :: Video :: Capture', +'Topic :: Multimedia :: Video :: Conversion', +'Topic :: Multimedia :: Video :: Display', +'Topic :: Multimedia :: Video :: Non-Linear Editor', +'Topic :: Office/Business', +'Topic :: Office/Business :: Financial', +'Topic :: Office/Business :: Financial :: Accounting', +'Topic :: Office/Business :: Financial :: Investment', +'Topic :: Office/Business :: Financial :: Point-Of-Sale', +'Topic :: Office/Business :: Financial :: Spreadsheet', +'Topic :: Office/Business :: Groupware', +'Topic :: Office/Business :: News/Diary', +'Topic :: Office/Business :: Office Suites', +'Topic :: Office/Business :: Scheduling', +'Topic :: Other/Nonlisted Topic', +'Topic :: Printing', +'Topic :: Religion', +'Topic :: Scientific/Engineering', +'Topic :: Scientific/Engineering :: Artificial Intelligence', +'Topic :: Scientific/Engineering :: Astronomy', +'Topic :: Scientific/Engineering :: Atmospheric Science', +'Topic :: Scientific/Engineering :: Bio-Informatics', +'Topic :: Scientific/Engineering :: Chemistry', +'Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)', +'Topic :: Scientific/Engineering :: GIS', +'Topic :: Scientific/Engineering :: Human Machine Interfaces', +'Topic :: Scientific/Engineering :: Image Recognition', +'Topic :: Scientific/Engineering :: Information Analysis', +'Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator', +'Topic :: Scientific/Engineering :: Mathematics', +'Topic :: Scientific/Engineering :: Medical Science Apps.', +'Topic :: Scientific/Engineering :: Physics', +'Topic :: Scientific/Engineering :: Visualization', +'Topic :: Security', +'Topic :: Security :: Cryptography', +'Topic :: Sociology', +'Topic :: Sociology :: Genealogy', +'Topic :: Sociology :: History', +'Topic :: Software Development', +'Topic :: Software Development :: Assemblers', +'Topic :: Software Development :: Bug Tracking', +'Topic :: Software Development :: Build Tools', +'Topic :: Software Development :: Code Generators', +'Topic :: Software Development :: Compilers', +'Topic :: Software Development :: Debuggers', +'Topic :: Software Development :: Disassemblers', +'Topic :: Software Development :: Documentation', +'Topic :: Software Development :: Embedded Systems', +'Topic :: Software Development :: Internationalization', +'Topic :: Software Development :: Interpreters', +'Topic :: Software Development :: Libraries', +'Topic :: Software Development :: Libraries :: Application Frameworks', +'Topic :: Software Development :: Libraries :: Java Libraries', +'Topic :: Software Development :: Libraries :: Perl Modules', +'Topic :: Software Development :: Libraries :: PHP Classes', +'Topic :: Software Development :: Libraries :: Pike Modules', +'Topic :: Software Development :: Libraries :: pygame', +'Topic :: Software Development :: Libraries :: Python Modules', +'Topic :: Software Development :: Libraries :: Ruby Modules', +'Topic :: Software Development :: Libraries :: Tcl Extensions', +'Topic :: Software Development :: Localization', +'Topic :: Software Development :: Object Brokering', +'Topic :: Software Development :: Object Brokering :: CORBA', +'Topic :: Software Development :: Pre-processors', +'Topic :: Software Development :: Quality Assurance', +'Topic :: Software Development :: Testing', +'Topic :: Software Development :: Testing :: Traffic Generation', +'Topic :: Software Development :: User Interfaces', +'Topic :: Software Development :: Version Control', +'Topic :: Software Development :: Version Control :: CVS', +'Topic :: Software Development :: Version Control :: RCS', +'Topic :: Software Development :: Version Control :: SCCS', +'Topic :: Software Development :: Widget Sets', +'Topic :: System', +'Topic :: System :: Archiving', +'Topic :: System :: Archiving :: Backup', +'Topic :: System :: Archiving :: Compression', +'Topic :: System :: Archiving :: Mirroring', +'Topic :: System :: Archiving :: Packaging', +'Topic :: System :: Benchmark', +'Topic :: System :: Boot', +'Topic :: System :: Boot :: Init', +'Topic :: System :: Clustering', +'Topic :: System :: Console Fonts', +'Topic :: System :: Distributed Computing', +'Topic :: System :: Emulators', +'Topic :: System :: Filesystems', +'Topic :: System :: Hardware', +'Topic :: System :: Hardware :: Hardware Drivers', +'Topic :: System :: Hardware :: Mainframes', +'Topic :: System :: Hardware :: Symmetric Multi-processing', +'Topic :: System :: Installation/Setup', +'Topic :: System :: Logging', +'Topic :: System :: Monitoring', +'Topic :: System :: Networking', +'Topic :: System :: Networking :: Firewalls', +'Topic :: System :: Networking :: Monitoring', +'Topic :: System :: Networking :: Monitoring :: Hardware Watchdog', +'Topic :: System :: Networking :: Time Synchronization', +'Topic :: System :: Operating System', +'Topic :: System :: Operating System Kernels', +'Topic :: System :: Operating System Kernels :: BSD', +'Topic :: System :: Operating System Kernels :: GNU Hurd', +'Topic :: System :: Operating System Kernels :: Linux', +'Topic :: System :: Power (UPS)', +'Topic :: System :: Recovery Tools', +'Topic :: System :: Shells', +'Topic :: System :: Software Distribution', +'Topic :: System :: Systems Administration', +'Topic :: System :: Systems Administration :: Authentication/Directory', +'Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP', +'Topic :: System :: Systems Administration :: Authentication/Directory :: NIS', +'Topic :: System :: System Shells', +'Topic :: Terminals', +'Topic :: Terminals :: Serial', +'Topic :: Terminals :: Telnet', +'Topic :: Terminals :: Terminal Emulators/X Terminals', +'Topic :: Text Editors', +'Topic :: Text Editors :: Documentation', +'Topic :: Text Editors :: Emacs', +'Topic :: Text Editors :: Integrated Development Environments (IDE)', +'Topic :: Text Editors :: Text Processing', +'Topic :: Text Editors :: Word Processors', +'Topic :: Text Processing', +'Topic :: Text Processing :: Filters', +'Topic :: Text Processing :: Fonts', +'Topic :: Text Processing :: General', +'Topic :: Text Processing :: Indexing', +'Topic :: Text Processing :: Linguistic', +'Topic :: Text Processing :: Markup', +'Topic :: Text Processing :: Markup :: HTML', +'Topic :: Text Processing :: Markup :: LaTeX', +'Topic :: Text Processing :: Markup :: SGML', +'Topic :: Text Processing :: Markup :: VRML', +'Topic :: Text Processing :: Markup :: XML', +'Topic :: Utilities', +] diff --git a/Lib/packaging/command/__init__.py b/Lib/packaging/command/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/__init__.py @@ -0,0 +1,56 @@ +"""Subpackage containing all standard commands.""" + +from packaging.errors import PackagingModuleError +from packaging.util import resolve_name + +__all__ = ['get_command_names', 'set_command', 'get_command_class', + 'STANDARD_COMMANDS'] + +_COMMANDS = { + 'check': 'packaging.command.check.check', + 'test': 'packaging.command.test.test', + 'build': 'packaging.command.build.build', + 'build_py': 'packaging.command.build_py.build_py', + 'build_ext': 'packaging.command.build_ext.build_ext', + 'build_clib': 'packaging.command.build_clib.build_clib', + 'build_scripts': 'packaging.command.build_scripts.build_scripts', + 'clean': 'packaging.command.clean.clean', + 'install_dist': 'packaging.command.install_dist.install_dist', + 'install_lib': 'packaging.command.install_lib.install_lib', + 'install_headers': 'packaging.command.install_headers.install_headers', + 'install_scripts': 'packaging.command.install_scripts.install_scripts', + 'install_data': 'packaging.command.install_data.install_data', + 'install_distinfo': + 'packaging.command.install_distinfo.install_distinfo', + 'sdist': 'packaging.command.sdist.sdist', + 'bdist': 'packaging.command.bdist.bdist', + 'bdist_dumb': 'packaging.command.bdist_dumb.bdist_dumb', + 'bdist_wininst': 'packaging.command.bdist_wininst.bdist_wininst', + 'register': 'packaging.command.register.register', + 'upload': 'packaging.command.upload.upload', + 'upload_docs': 'packaging.command.upload_docs.upload_docs'} + +STANDARD_COMMANDS = set(_COMMANDS) + + +def get_command_names(): + """Return registered commands""" + return sorted(_COMMANDS) + + +def set_command(location): + cls = resolve_name(location) + # XXX we want to do the duck-type checking here + _COMMANDS[cls.get_command_name()] = cls + + +def get_command_class(name): + """Return the registered command""" + try: + cls = _COMMANDS[name] + if isinstance(cls, str): + cls = resolve_name(cls) + _COMMANDS[name] = cls + return cls + except KeyError: + raise PackagingModuleError("Invalid command %s" % name) diff --git a/Lib/packaging/command/bdist.py b/Lib/packaging/command/bdist.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/bdist.py @@ -0,0 +1,141 @@ +"""Create a built (binary) distribution. + +If a --formats option was given on the command line, this command will +call the corresponding bdist_* commands; if the option was absent, a +bdist_* command depending on the current platform will be called. +""" + +import os + +from packaging import util +from packaging.command.cmd import Command +from packaging.errors import PackagingPlatformError, PackagingOptionError + + +def show_formats(): + """Print list of available formats (arguments to "--format" option). + """ + from packaging.fancy_getopt import FancyGetopt + formats = [] + for format in bdist.format_commands: + formats.append(("formats=" + format, None, + bdist.format_command[format][1])) + pretty_printer = FancyGetopt(formats) + pretty_printer.print_help("List of available distribution formats:") + + +class bdist(Command): + + description = "create a built (binary) distribution" + + user_options = [('bdist-base=', 'b', + "temporary directory for creating built distributions"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % util.get_platform()), + ('formats=', None, + "formats for distribution (comma-separated list)"), + ('dist-dir=', 'd', + "directory to put final built distributions in " + "[default: dist]"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ('owner=', 'u', + "Owner name used when creating a tar file" + " [default: current user]"), + ('group=', 'g', + "Group name used when creating a tar file" + " [default: current group]"), + ] + + boolean_options = ['skip-build'] + + help_options = [ + ('help-formats', None, + "lists available distribution formats", show_formats), + ] + + # This is of course very simplistic. The various UNIX family operating + # systems have their specific formats, but they are out of scope for us; + # bdist_dumb is, well, dumb; it's more a building block for other + # packaging tools than a real end-user binary format. + default_format = {'posix': 'gztar', + 'nt': 'zip', + 'os2': 'zip'} + + # Establish the preferred order (for the --help-formats option). + format_commands = ['gztar', 'bztar', 'ztar', 'tar', + 'wininst', 'zip', 'msi'] + + # And the real information. + format_command = {'gztar': ('bdist_dumb', "gzip'ed tar file"), + 'bztar': ('bdist_dumb', "bzip2'ed tar file"), + 'ztar': ('bdist_dumb', "compressed tar file"), + 'tar': ('bdist_dumb', "tar file"), + 'wininst': ('bdist_wininst', + "Windows executable installer"), + 'zip': ('bdist_dumb', "ZIP file"), + 'msi': ('bdist_msi', "Microsoft Installer") + } + + + def initialize_options(self): + self.bdist_base = None + self.plat_name = None + self.formats = None + self.dist_dir = None + self.skip_build = False + self.group = None + self.owner = None + + def finalize_options(self): + # have to finalize 'plat_name' before 'bdist_base' + if self.plat_name is None: + if self.skip_build: + self.plat_name = util.get_platform() + else: + self.plat_name = self.get_finalized_command('build').plat_name + + # 'bdist_base' -- parent of per-built-distribution-format + # temporary directories (eg. we'll probably have + # "build/bdist./dumb", etc.) + if self.bdist_base is None: + build_base = self.get_finalized_command('build').build_base + self.bdist_base = os.path.join(build_base, + 'bdist.' + self.plat_name) + + self.ensure_string_list('formats') + if self.formats is None: + try: + self.formats = [self.default_format[os.name]] + except KeyError: + raise PackagingPlatformError("don't know how to create built distributions " + \ + "on platform %s" % os.name) + + if self.dist_dir is None: + self.dist_dir = "dist" + + def run(self): + # Figure out which sub-commands we need to run. + commands = [] + for format in self.formats: + try: + commands.append(self.format_command[format][0]) + except KeyError: + raise PackagingOptionError("invalid format '%s'" % format) + + # Reinitialize and run each command. + for i in range(len(self.formats)): + cmd_name = commands[i] + sub_cmd = self.get_reinitialized_command(cmd_name) + + # passing the owner and group names for tar archiving + if cmd_name == 'bdist_dumb': + sub_cmd.owner = self.owner + sub_cmd.group = self.group + + # If we're going to need to run this command again, tell it to + # keep its temporary files around so subsequent runs go faster. + if cmd_name in commands[i+1:]: + sub_cmd.keep_temp = True + self.run_command(cmd_name) diff --git a/Lib/packaging/command/bdist_dumb.py b/Lib/packaging/command/bdist_dumb.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/bdist_dumb.py @@ -0,0 +1,137 @@ +"""Create a "dumb" built distribution. + +A dumb distribution is just an archive meant to be unpacked under +sys.prefix or sys.exec_prefix. +""" + +import os + +from shutil import rmtree +from sysconfig import get_python_version +from packaging.util import get_platform +from packaging.command.cmd import Command +from packaging.errors import PackagingPlatformError +from packaging import logger + +class bdist_dumb(Command): + + description = 'create a "dumb" built distribution' + + user_options = [('bdist-dir=', 'd', + "temporary directory for creating the distribution"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform()), + ('format=', 'f', + "archive format to create (tar, ztar, gztar, zip)"), + ('keep-temp', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('dist-dir=', 'd', + "directory to put final built distributions in"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ('relative', None, + "build the archive using relative paths" + "(default: false)"), + ('owner=', 'u', + "Owner name used when creating a tar file" + " [default: current user]"), + ('group=', 'g', + "Group name used when creating a tar file" + " [default: current group]"), + ] + + boolean_options = ['keep-temp', 'skip-build', 'relative'] + + default_format = { 'posix': 'gztar', + 'nt': 'zip', + 'os2': 'zip' } + + + def initialize_options(self): + self.bdist_dir = None + self.plat_name = None + self.format = None + self.keep_temp = False + self.dist_dir = None + self.skip_build = False + self.relative = False + self.owner = None + self.group = None + + def finalize_options(self): + if self.bdist_dir is None: + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'dumb') + + if self.format is None: + try: + self.format = self.default_format[os.name] + except KeyError: + raise PackagingPlatformError(("don't know how to create dumb built distributions " + + "on platform %s") % os.name) + + self.set_undefined_options('bdist', 'dist_dir', 'plat_name') + + def run(self): + if not self.skip_build: + self.run_command('build') + + install = self.get_reinitialized_command('install_dist', + reinit_subcommands=True) + install.root = self.bdist_dir + install.skip_build = self.skip_build + install.warn_dir = False + + logger.info("installing to %s", self.bdist_dir) + self.run_command('install_dist') + + # And make an archive relative to the root of the + # pseudo-installation tree. + archive_basename = "%s.%s" % (self.distribution.get_fullname(), + self.plat_name) + + # OS/2 objects to any ":" characters in a filename (such as when + # a timestamp is used in a version) so change them to hyphens. + if os.name == "os2": + archive_basename = archive_basename.replace(":", "-") + + pseudoinstall_root = os.path.join(self.dist_dir, archive_basename) + if not self.relative: + archive_root = self.bdist_dir + else: + if (self.distribution.has_ext_modules() and + (install.install_base != install.install_platbase)): + raise PackagingPlatformError( + "can't make a dumb built distribution where base and " + "platbase are different (%r, %r)" % + (install.install_base, install.install_platbase)) + else: + archive_root = os.path.join( + self.bdist_dir, + self._ensure_relative(install.install_base)) + + # Make the archive + filename = self.make_archive(pseudoinstall_root, + self.format, root_dir=archive_root, + owner=self.owner, group=self.group) + if self.distribution.has_ext_modules(): + pyversion = get_python_version() + else: + pyversion = 'any' + self.distribution.dist_files.append(('bdist_dumb', pyversion, + filename)) + + if not self.keep_temp: + if self.dry_run: + logger.info('removing %s', self.bdist_dir) + else: + rmtree(self.bdist_dir) + + def _ensure_relative(self, path): + # copied from dir_util, deleted + drive, path = os.path.splitdrive(path) + if path[0:1] == os.sep: + path = drive + path[1:] + return path diff --git a/Lib/packaging/command/bdist_msi.py b/Lib/packaging/command/bdist_msi.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/bdist_msi.py @@ -0,0 +1,740 @@ +"""Create a Microsoft Installer (.msi) binary distribution.""" + +# Copyright (C) 2005, 2006 Martin von L?wis +# Licensed to PSF under a Contributor Agreement. + +import sys +import os +import msilib + + +from sysconfig import get_python_version +from shutil import rmtree +from packaging.command.cmd import Command +from packaging.version import NormalizedVersion +from packaging.errors import PackagingOptionError +from packaging import logger as log +from packaging.util import get_platform +from msilib import schema, sequence, text +from msilib import Directory, Feature, Dialog, add_data + +class MSIVersion(NormalizedVersion): + """ + MSI ProductVersion must be strictly numeric. + MSIVersion disallows prerelease and postrelease versions. + """ + def __init__(self, *args, **kwargs): + super(MSIVersion, self).__init__(*args, **kwargs) + if not self.is_final: + raise ValueError("ProductVersion must be strictly numeric") + +class PyDialog(Dialog): + """Dialog class with a fixed layout: controls at the top, then a ruler, + then a list of buttons: back, next, cancel. Optionally a bitmap at the + left.""" + def __init__(self, *args, **kw): + """Dialog(database, name, x, y, w, h, attributes, title, first, + default, cancel, bitmap=true)""" + Dialog.__init__(self, *args) + ruler = self.h - 36 + #if kw.get("bitmap", True): + # self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin") + self.line("BottomLine", 0, ruler, self.w, 0) + + def title(self, title): + "Set the title text of the dialog at the top." + # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix, + # text, in VerdanaBold10 + self.text("Title", 15, 10, 320, 60, 0x30003, + r"{\VerdanaBold10}%s" % title) + + def back(self, title, next, name = "Back", active = 1): + """Add a back button with a given title, the tab-next button, + its name in the Control table, possibly initially disabled. + + Return the button, so that events can be associated""" + if active: + flags = 3 # Visible|Enabled + else: + flags = 1 # Visible + return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next) + + def cancel(self, title, next, name = "Cancel", active = 1): + """Add a cancel button with a given title, the tab-next button, + its name in the Control table, possibly initially disabled. + + Return the button, so that events can be associated""" + if active: + flags = 3 # Visible|Enabled + else: + flags = 1 # Visible + return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next) + + def next(self, title, next, name = "Next", active = 1): + """Add a Next button with a given title, the tab-next button, + its name in the Control table, possibly initially disabled. + + Return the button, so that events can be associated""" + if active: + flags = 3 # Visible|Enabled + else: + flags = 1 # Visible + return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next) + + def xbutton(self, name, title, next, xpos): + """Add a button with a given title, the tab-next button, + its name in the Control table, giving its x position; the + y-position is aligned with the other buttons. + + Return the button, so that events can be associated""" + return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next) + +class bdist_msi(Command): + + description = "create a Microsoft Installer (.msi) binary distribution" + + user_options = [('bdist-dir=', None, + "temporary directory for creating the distribution"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform()), + ('keep-temp', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('target-version=', None, + "require a specific python version" + + " on the target system"), + ('no-target-compile', 'c', + "do not compile .py to .pyc on the target system"), + ('no-target-optimize', 'o', + "do not compile .py to .pyo (optimized)" + "on the target system"), + ('dist-dir=', 'd', + "directory to put final built distributions in"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ('install-script=', None, + "basename of installation script to be run after" + "installation or before deinstallation"), + ('pre-install-script=', None, + "Fully qualified filename of a script to be run before " + "any files are installed. This script need not be in the " + "distribution"), + ] + + boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize', + 'skip-build'] + + all_versions = ['2.0', '2.1', '2.2', '2.3', '2.4', + '2.5', '2.6', '2.7', '2.8', '2.9', + '3.0', '3.1', '3.2', '3.3', '3.4', + '3.5', '3.6', '3.7', '3.8', '3.9'] + other_version = 'X' + + def initialize_options(self): + self.bdist_dir = None + self.plat_name = None + self.keep_temp = False + self.no_target_compile = False + self.no_target_optimize = False + self.target_version = None + self.dist_dir = None + self.skip_build = False + self.install_script = None + self.pre_install_script = None + self.versions = None + + def finalize_options(self): + if self.bdist_dir is None: + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'msi') + short_version = get_python_version() + if (not self.target_version) and self.distribution.has_ext_modules(): + self.target_version = short_version + if self.target_version: + self.versions = [self.target_version] + if not self.skip_build and self.distribution.has_ext_modules()\ + and self.target_version != short_version: + raise PackagingOptionError("target version can only be %s, or the '--skip-build'" \ + " option must be specified" % (short_version,)) + else: + self.versions = list(self.all_versions) + + self.set_undefined_options('bdist', 'dist_dir', 'plat_name') + + if self.pre_install_script: + raise PackagingOptionError("the pre-install-script feature is not yet implemented") + + if self.install_script: + for script in self.distribution.scripts: + if self.install_script == os.path.basename(script): + break + else: + raise PackagingOptionError("install_script '%s' not found in scripts" % \ + self.install_script) + self.install_script_key = None + + + def run(self): + if not self.skip_build: + self.run_command('build') + + install = self.get_reinitialized_command('install_dist', + reinit_subcommands=True) + install.prefix = self.bdist_dir + install.skip_build = self.skip_build + install.warn_dir = False + + install_lib = self.get_reinitialized_command('install_lib') + # we do not want to include pyc or pyo files + install_lib.compile = False + install_lib.optimize = 0 + + if self.distribution.has_ext_modules(): + # If we are building an installer for a Python version other + # than the one we are currently running, then we need to ensure + # our build_lib reflects the other Python version rather than ours. + # Note that for target_version!=sys.version, we must have skipped the + # build step, so there is no issue with enforcing the build of this + # version. + target_version = self.target_version + if not target_version: + assert self.skip_build, "Should have already checked this" + target_version = sys.version[0:3] + plat_specifier = ".%s-%s" % (self.plat_name, target_version) + build = self.get_finalized_command('build') + build.build_lib = os.path.join(build.build_base, + 'lib' + plat_specifier) + + log.info("installing to %s", self.bdist_dir) + install.ensure_finalized() + + # avoid warning of 'install_lib' about installing + # into a directory not in sys.path + sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) + + install.run() + + del sys.path[0] + + self.mkpath(self.dist_dir) + fullname = self.distribution.get_fullname() + installer_name = self.get_installer_filename(fullname) + installer_name = os.path.abspath(installer_name) + if os.path.exists(installer_name): os.unlink(installer_name) + + metadata = self.distribution.metadata + author = metadata.author + if not author: + author = metadata.maintainer + if not author: + author = "UNKNOWN" + version = MSIVersion(metadata.get_version()) + # Prefix ProductName with Python x.y, so that + # it sorts together with the other Python packages + # in Add-Remove-Programs (APR) + fullname = self.distribution.get_fullname() + if self.target_version: + product_name = "Python %s %s" % (self.target_version, fullname) + else: + product_name = "Python %s" % (fullname) + self.db = msilib.init_database(installer_name, schema, + product_name, msilib.gen_uuid(), + str(version), author) + msilib.add_tables(self.db, sequence) + props = [('DistVersion', version)] + email = metadata.author_email or metadata.maintainer_email + if email: + props.append(("ARPCONTACT", email)) + if metadata.url: + props.append(("ARPURLINFOABOUT", metadata.url)) + if props: + add_data(self.db, 'Property', props) + + self.add_find_python() + self.add_files() + self.add_scripts() + self.add_ui() + self.db.Commit() + + if hasattr(self.distribution, 'dist_files'): + tup = 'bdist_msi', self.target_version or 'any', fullname + self.distribution.dist_files.append(tup) + + if not self.keep_temp: + log.info("removing temporary build directory %s", self.bdist_dir) + if not self.dry_run: + rmtree(self.bdist_dir) + + def add_files(self): + db = self.db + cab = msilib.CAB("distfiles") + rootdir = os.path.abspath(self.bdist_dir) + + root = Directory(db, cab, None, rootdir, "TARGETDIR", "SourceDir") + f = Feature(db, "Python", "Python", "Everything", + 0, 1, directory="TARGETDIR") + + items = [(f, root, '')] + for version in self.versions + [self.other_version]: + target = "TARGETDIR" + version + name = default = "Python" + version + desc = "Everything" + if version is self.other_version: + title = "Python from another location" + level = 2 + else: + title = "Python %s from registry" % version + level = 1 + f = Feature(db, name, title, desc, 1, level, directory=target) + dir = Directory(db, cab, root, rootdir, target, default) + items.append((f, dir, version)) + db.Commit() + + seen = {} + for feature, dir, version in items: + todo = [dir] + while todo: + dir = todo.pop() + for file in os.listdir(dir.absolute): + afile = os.path.join(dir.absolute, file) + if os.path.isdir(afile): + short = "%s|%s" % (dir.make_short(file), file) + default = file + version + newdir = Directory(db, cab, dir, file, default, short) + todo.append(newdir) + else: + if not dir.component: + dir.start_component(dir.logical, feature, 0) + if afile not in seen: + key = seen[afile] = dir.add_file(file) + if file==self.install_script: + if self.install_script_key: + raise PackagingOptionError( + "Multiple files with name %s" % file) + self.install_script_key = '[#%s]' % key + else: + key = seen[afile] + add_data(self.db, "DuplicateFile", + [(key + version, dir.component, key, None, dir.logical)]) + db.Commit() + cab.commit(db) + + def add_find_python(self): + """Adds code to the installer to compute the location of Python. + + Properties PYTHON.MACHINE.X.Y and PYTHON.USER.X.Y will be set from the + registry for each version of Python. + + Properties TARGETDIRX.Y will be set from PYTHON.USER.X.Y if defined, + else from PYTHON.MACHINE.X.Y. + + Properties PYTHONX.Y will be set to TARGETDIRX.Y\\python.exe""" + + start = 402 + for ver in self.versions: + install_path = r"SOFTWARE\Python\PythonCore\%s\InstallPath" % ver + machine_reg = "python.machine." + ver + user_reg = "python.user." + ver + machine_prop = "PYTHON.MACHINE." + ver + user_prop = "PYTHON.USER." + ver + machine_action = "PythonFromMachine" + ver + user_action = "PythonFromUser" + ver + exe_action = "PythonExe" + ver + target_dir_prop = "TARGETDIR" + ver + exe_prop = "PYTHON" + ver + if msilib.Win64: + # type: msidbLocatorTypeRawValue + msidbLocatorType64bit + Type = 2+16 + else: + Type = 2 + add_data(self.db, "RegLocator", + [(machine_reg, 2, install_path, None, Type), + (user_reg, 1, install_path, None, Type)]) + add_data(self.db, "AppSearch", + [(machine_prop, machine_reg), + (user_prop, user_reg)]) + add_data(self.db, "CustomAction", + [(machine_action, 51+256, target_dir_prop, "[" + machine_prop + "]"), + (user_action, 51+256, target_dir_prop, "[" + user_prop + "]"), + (exe_action, 51+256, exe_prop, "[" + target_dir_prop + "]\\python.exe"), + ]) + add_data(self.db, "InstallExecuteSequence", + [(machine_action, machine_prop, start), + (user_action, user_prop, start + 1), + (exe_action, None, start + 2), + ]) + add_data(self.db, "InstallUISequence", + [(machine_action, machine_prop, start), + (user_action, user_prop, start + 1), + (exe_action, None, start + 2), + ]) + add_data(self.db, "Condition", + [("Python" + ver, 0, "NOT TARGETDIR" + ver)]) + start += 4 + assert start < 500 + + def add_scripts(self): + if self.install_script: + start = 6800 + for ver in self.versions + [self.other_version]: + install_action = "install_script." + ver + exe_prop = "PYTHON" + ver + add_data(self.db, "CustomAction", + [(install_action, 50, exe_prop, self.install_script_key)]) + add_data(self.db, "InstallExecuteSequence", + [(install_action, "&Python%s=3" % ver, start)]) + start += 1 + # XXX pre-install scripts are currently refused in finalize_options() + # but if this feature is completed, it will also need to add + # entries for each version as the above code does + if self.pre_install_script: + scriptfn = os.path.join(self.bdist_dir, "preinstall.bat") + with open(scriptfn, "w") as f: + # The batch file will be executed with [PYTHON], so that %1 + # is the path to the Python interpreter; %0 will be the path + # of the batch file. + # rem =""" + # %1 %0 + # exit + # """ + # + f.write('rem ="""\n%1 %0\nexit\n"""\n') + with open(self.pre_install_script) as fp: + f.write(fp.read()) + add_data(self.db, "Binary", + [("PreInstall", msilib.Binary(scriptfn)), + ]) + add_data(self.db, "CustomAction", + [("PreInstall", 2, "PreInstall", None), + ]) + add_data(self.db, "InstallExecuteSequence", + [("PreInstall", "NOT Installed", 450), + ]) + + def add_ui(self): + db = self.db + x = y = 50 + w = 370 + h = 300 + title = "[ProductName] Setup" + + # see "Dialog Style Bits" + modal = 3 # visible | modal + modeless = 1 # visible + + # UI customization properties + add_data(db, "Property", + # See "DefaultUIFont Property" + [("DefaultUIFont", "DlgFont8"), + # See "ErrorDialog Style Bit" + ("ErrorDialog", "ErrorDlg"), + ("Progress1", "Install"), # modified in maintenance type dlg + ("Progress2", "installs"), + ("MaintenanceForm_Action", "Repair"), + # possible values: ALL, JUSTME + ("WhichUsers", "ALL") + ]) + + # Fonts, see "TextStyle Table" + add_data(db, "TextStyle", + [("DlgFont8", "Tahoma", 9, None, 0), + ("DlgFontBold8", "Tahoma", 8, None, 1), #bold + ("VerdanaBold10", "Verdana", 10, None, 1), + ("VerdanaRed9", "Verdana", 9, 255, 0), + ]) + + # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" + # Numbers indicate sequence; see sequence.py for how these action integrate + add_data(db, "InstallUISequence", + [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140), + ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141), + # In the user interface, assume all-users installation if privileged. + ("SelectFeaturesDlg", "Not Installed", 1230), + # XXX no support for resume installations yet + #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240), + ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250), + ("ProgressDlg", None, 1280)]) + + add_data(db, 'ActionText', text.ActionText) + add_data(db, 'UIText', text.UIText) + ##################################################################### + # Standard dialogs: FatalError, UserExit, ExitDialog + fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title, + "Finish", "Finish", "Finish") + fatal.title("[ProductName] Installer ended prematurely") + fatal.back("< Back", "Finish", active = 0) + fatal.cancel("Cancel", "Back", active = 0) + fatal.text("Description1", 15, 70, 320, 80, 0x30003, + "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.") + fatal.text("Description2", 15, 155, 320, 20, 0x30003, + "Click the Finish button to exit the Installer.") + c=fatal.next("Finish", "Cancel", name="Finish") + c.event("EndDialog", "Exit") + + user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title, + "Finish", "Finish", "Finish") + user_exit.title("[ProductName] Installer was interrupted") + user_exit.back("< Back", "Finish", active = 0) + user_exit.cancel("Cancel", "Back", active = 0) + user_exit.text("Description1", 15, 70, 320, 80, 0x30003, + "[ProductName] setup was interrupted. Your system has not been modified. " + "To install this program at a later time, please run the installation again.") + user_exit.text("Description2", 15, 155, 320, 20, 0x30003, + "Click the Finish button to exit the Installer.") + c = user_exit.next("Finish", "Cancel", name="Finish") + c.event("EndDialog", "Exit") + + exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title, + "Finish", "Finish", "Finish") + exit_dialog.title("Completing the [ProductName] Installer") + exit_dialog.back("< Back", "Finish", active = 0) + exit_dialog.cancel("Cancel", "Back", active = 0) + exit_dialog.text("Description", 15, 235, 320, 20, 0x30003, + "Click the Finish button to exit the Installer.") + c = exit_dialog.next("Finish", "Cancel", name="Finish") + c.event("EndDialog", "Return") + + ##################################################################### + # Required dialog: FilesInUse, ErrorDlg + inuse = PyDialog(db, "FilesInUse", + x, y, w, h, + 19, # KeepModeless|Modal|Visible + title, + "Retry", "Retry", "Retry", bitmap=False) + inuse.text("Title", 15, 6, 200, 15, 0x30003, + r"{\DlgFontBold8}Files in Use") + inuse.text("Description", 20, 23, 280, 20, 0x30003, + "Some files that need to be updated are currently in use.") + inuse.text("Text", 20, 55, 330, 50, 3, + "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.") + inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess", + None, None, None) + c=inuse.back("Exit", "Ignore", name="Exit") + c.event("EndDialog", "Exit") + c=inuse.next("Ignore", "Retry", name="Ignore") + c.event("EndDialog", "Ignore") + c=inuse.cancel("Retry", "Exit", name="Retry") + c.event("EndDialog","Retry") + + # See "Error Dialog". See "ICE20" for the required names of the controls. + error = Dialog(db, "ErrorDlg", + 50, 10, 330, 101, + 65543, # Error|Minimize|Modal|Visible + title, + "ErrorText", None, None) + error.text("ErrorText", 50,9,280,48,3, "") + #error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None) + error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo") + error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes") + error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort") + error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel") + error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore") + error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk") + error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry") + + ##################################################################### + # Global "Query Cancel" dialog + cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, + "No", "No", "No") + cancel.text("Text", 48, 15, 194, 30, 3, + "Are you sure you want to cancel [ProductName] installation?") + #cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, + # "py.ico", None, None) + c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No") + c.event("EndDialog", "Exit") + + c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes") + c.event("EndDialog", "Return") + + ##################################################################### + # Global "Wait for costing" dialog + costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title, + "Return", "Return", "Return") + costing.text("Text", 48, 15, 194, 30, 3, + "Please wait while the installer finishes determining your disk space requirements.") + c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None) + c.event("EndDialog", "Exit") + + ##################################################################### + # Preparation dialog: no user input except cancellation + prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title, + "Cancel", "Cancel", "Cancel") + prep.text("Description", 15, 70, 320, 40, 0x30003, + "Please wait while the Installer prepares to guide you through the installation.") + prep.title("Welcome to the [ProductName] Installer") + c=prep.text("ActionText", 15, 110, 320, 20, 0x30003, "Pondering...") + c.mapping("ActionText", "Text") + c=prep.text("ActionData", 15, 135, 320, 30, 0x30003, None) + c.mapping("ActionData", "Text") + prep.back("Back", None, active=0) + prep.next("Next", None, active=0) + c=prep.cancel("Cancel", None) + c.event("SpawnDialog", "CancelDlg") + + ##################################################################### + # Feature (Python directory) selection + seldlg = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal, title, + "Next", "Next", "Cancel") + seldlg.title("Select Python Installations") + + seldlg.text("Hint", 15, 30, 300, 20, 3, + "Select the Python locations where %s should be installed." + % self.distribution.get_fullname()) + + seldlg.back("< Back", None, active=0) + c = seldlg.next("Next >", "Cancel") + order = 1 + c.event("[TARGETDIR]", "[SourceDir]", ordering=order) + for version in self.versions + [self.other_version]: + order += 1 + c.event("[TARGETDIR]", "[TARGETDIR%s]" % version, + "FEATURE_SELECTED AND &Python%s=3" % version, + ordering=order) + c.event("SpawnWaitDialog", "WaitForCostingDlg", ordering=order + 1) + c.event("EndDialog", "Return", ordering=order + 2) + c = seldlg.cancel("Cancel", "Features") + c.event("SpawnDialog", "CancelDlg") + + c = seldlg.control("Features", "SelectionTree", 15, 60, 300, 120, 3, + "FEATURE", None, "PathEdit", None) + c.event("[FEATURE_SELECTED]", "1") + ver = self.other_version + install_other_cond = "FEATURE_SELECTED AND &Python%s=3" % ver + dont_install_other_cond = "FEATURE_SELECTED AND &Python%s<>3" % ver + + c = seldlg.text("Other", 15, 200, 300, 15, 3, + "Provide an alternate Python location") + c.condition("Enable", install_other_cond) + c.condition("Show", install_other_cond) + c.condition("Disable", dont_install_other_cond) + c.condition("Hide", dont_install_other_cond) + + c = seldlg.control("PathEdit", "PathEdit", 15, 215, 300, 16, 1, + "TARGETDIR" + ver, None, "Next", None) + c.condition("Enable", install_other_cond) + c.condition("Show", install_other_cond) + c.condition("Disable", dont_install_other_cond) + c.condition("Hide", dont_install_other_cond) + + ##################################################################### + # Disk cost + cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title, + "OK", "OK", "OK", bitmap=False) + cost.text("Title", 15, 6, 200, 15, 0x30003, + "{\DlgFontBold8}Disk Space Requirements") + cost.text("Description", 20, 20, 280, 20, 0x30003, + "The disk space required for the installation of the selected features.") + cost.text("Text", 20, 53, 330, 60, 3, + "The highlighted volumes (if any) do not have enough disk space " + "available for the currently selected features. You can either " + "remove some files from the highlighted volumes, or choose to " + "install less features onto local drive(s), or select different " + "destination drive(s).") + cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223, + None, "{120}{70}{70}{70}{70}", None, None) + cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return") + + ##################################################################### + # WhichUsers Dialog. Only available on NT, and for privileged users. + # This must be run before FindRelatedProducts, because that will + # take into account whether the previous installation was per-user + # or per-machine. We currently don't support going back to this + # dialog after "Next" was selected; to support this, we would need to + # find how to reset the ALLUSERS property, and how to re-run + # FindRelatedProducts. + # On Windows9x, the ALLUSERS property is ignored on the command line + # and in the Property table, but installer fails according to the documentation + # if a dialog attempts to set ALLUSERS. + whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title, + "AdminInstall", "Next", "Cancel") + whichusers.title("Select whether to install [ProductName] for all users of this computer.") + # A radio group with two options: allusers, justme + g = whichusers.radiogroup("AdminInstall", 15, 60, 260, 50, 3, + "WhichUsers", "", "Next") + g.add("ALL", 0, 5, 150, 20, "Install for all users") + g.add("JUSTME", 0, 25, 150, 20, "Install just for me") + + whichusers.back("Back", None, active=0) + + c = whichusers.next("Next >", "Cancel") + c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1) + c.event("EndDialog", "Return", ordering = 2) + + c = whichusers.cancel("Cancel", "AdminInstall") + c.event("SpawnDialog", "CancelDlg") + + ##################################################################### + # Installation Progress dialog (modeless) + progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title, + "Cancel", "Cancel", "Cancel", bitmap=False) + progress.text("Title", 20, 15, 200, 15, 0x30003, + "{\DlgFontBold8}[Progress1] [ProductName]") + progress.text("Text", 35, 65, 300, 30, 3, + "Please wait while the Installer [Progress2] [ProductName]. " + "This may take several minutes.") + progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:") + + c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...") + c.mapping("ActionText", "Text") + + #c=progress.text("ActionData", 35, 140, 300, 20, 3, None) + #c.mapping("ActionData", "Text") + + c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537, + None, "Progress done", None, None) + c.mapping("SetProgress", "Progress") + + progress.back("< Back", "Next", active=False) + progress.next("Next >", "Cancel", active=False) + progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg") + + ################################################################### + # Maintenance type: repair/uninstall + maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title, + "Next", "Next", "Cancel") + maint.title("Welcome to the [ProductName] Setup Wizard") + maint.text("BodyText", 15, 63, 330, 42, 3, + "Select whether you want to repair or remove [ProductName].") + g=maint.radiogroup("RepairRadioGroup", 15, 108, 330, 60, 3, + "MaintenanceForm_Action", "", "Next") + #g.add("Change", 0, 0, 200, 17, "&Change [ProductName]") + g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]") + g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]") + + maint.back("< Back", None, active=False) + c=maint.next("Finish", "Cancel") + # Change installation: Change progress dialog to "Change", then ask + # for feature selection + #c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1) + #c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2) + + # Reinstall: Change progress dialog to "Repair", then invoke reinstall + # Also set list of reinstalled features to "ALL" + c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5) + c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6) + c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7) + c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8) + + # Uninstall: Change progress to "Remove", then invoke uninstall + # Also set list of removed features to "ALL" + c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11) + c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12) + c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13) + c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14) + + # Close dialog when maintenance action scheduled + c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20) + #c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21) + + maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg") + + def get_installer_filename(self, fullname): + # Factored out to allow overriding in subclasses + if self.target_version: + base_name = "%s.%s-py%s.msi" % (fullname, self.plat_name, + self.target_version) + else: + base_name = "%s.%s.msi" % (fullname, self.plat_name) + installer_name = os.path.join(self.dist_dir, base_name) + return installer_name diff --git a/Lib/packaging/command/bdist_wininst.py b/Lib/packaging/command/bdist_wininst.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/bdist_wininst.py @@ -0,0 +1,342 @@ +"""Create an executable installer for Windows.""" + +# FIXME synchronize bytes/str use with same file in distutils + +import sys +import os + +from shutil import rmtree +from sysconfig import get_python_version +from packaging.command.cmd import Command +from packaging.errors import PackagingOptionError, PackagingPlatformError +from packaging import logger +from packaging.util import get_platform + + +class bdist_wininst(Command): + + description = "create an executable installer for Windows" + + user_options = [('bdist-dir=', None, + "temporary directory for creating the distribution"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform()), + ('keep-temp', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('target-version=', None, + "require a specific python version" + + " on the target system"), + ('no-target-compile', 'c', + "do not compile .py to .pyc on the target system"), + ('no-target-optimize', 'o', + "do not compile .py to .pyo (optimized)" + "on the target system"), + ('dist-dir=', 'd', + "directory to put final built distributions in"), + ('bitmap=', 'b', + "bitmap to use for the installer instead of python-powered logo"), + ('title=', 't', + "title to display on the installer background instead of default"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ('install-script=', None, + "basename of installation script to be run after" + "installation or before deinstallation"), + ('pre-install-script=', None, + "Fully qualified filename of a script to be run before " + "any files are installed. This script need not be in the " + "distribution"), + ('user-access-control=', None, + "specify Vista's UAC handling - 'none'/default=no " + "handling, 'auto'=use UAC if target Python installed for " + "all users, 'force'=always use UAC"), + ] + + boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize', + 'skip-build'] + + def initialize_options(self): + self.bdist_dir = None + self.plat_name = None + self.keep_temp = False + self.no_target_compile = False + self.no_target_optimize = False + self.target_version = None + self.dist_dir = None + self.bitmap = None + self.title = None + self.skip_build = False + self.install_script = None + self.pre_install_script = None + self.user_access_control = None + + + def finalize_options(self): + if self.bdist_dir is None: + if self.skip_build and self.plat_name: + # If build is skipped and plat_name is overridden, bdist will + # not see the correct 'plat_name' - so set that up manually. + bdist = self.distribution.get_command_obj('bdist') + bdist.plat_name = self.plat_name + # next the command will be initialized using that name + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'wininst') + if not self.target_version: + self.target_version = "" + if not self.skip_build and self.distribution.has_ext_modules(): + short_version = get_python_version() + if self.target_version and self.target_version != short_version: + raise PackagingOptionError("target version can only be %s, or the '--skip-build'" \ + " option must be specified" % (short_version,)) + self.target_version = short_version + + self.set_undefined_options('bdist', 'dist_dir', 'plat_name') + + if self.install_script: + for script in self.distribution.scripts: + if self.install_script == os.path.basename(script): + break + else: + raise PackagingOptionError("install_script '%s' not found in scripts" % \ + self.install_script) + + def run(self): + if (sys.platform != "win32" and + (self.distribution.has_ext_modules() or + self.distribution.has_c_libraries())): + raise PackagingPlatformError \ + ("distribution contains extensions and/or C libraries; " + "must be compiled on a Windows 32 platform") + + if not self.skip_build: + self.run_command('build') + + install = self.get_reinitialized_command('install', + reinit_subcommands=True) + install.root = self.bdist_dir + install.skip_build = self.skip_build + install.warn_dir = False + install.plat_name = self.plat_name + + install_lib = self.get_reinitialized_command('install_lib') + # we do not want to include pyc or pyo files + install_lib.compile = False + install_lib.optimize = 0 + + if self.distribution.has_ext_modules(): + # If we are building an installer for a Python version other + # than the one we are currently running, then we need to ensure + # our build_lib reflects the other Python version rather than ours. + # Note that for target_version!=sys.version, we must have skipped the + # build step, so there is no issue with enforcing the build of this + # version. + target_version = self.target_version + if not target_version: + assert self.skip_build, "Should have already checked this" + target_version = sys.version[0:3] + plat_specifier = ".%s-%s" % (self.plat_name, target_version) + build = self.get_finalized_command('build') + build.build_lib = os.path.join(build.build_base, + 'lib' + plat_specifier) + + # Use a custom scheme for the zip-file, because we have to decide + # at installation time which scheme to use. + for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): + value = key.upper() + if key == 'headers': + value = value + '/Include/$dist_name' + setattr(install, + 'install_' + key, + value) + + logger.info("installing to %s", self.bdist_dir) + install.ensure_finalized() + + # avoid warning of 'install_lib' about installing + # into a directory not in sys.path + sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) + + install.run() + + del sys.path[0] + + # And make an archive relative to the root of the + # pseudo-installation tree. + from tempfile import NamedTemporaryFile + archive_basename = NamedTemporaryFile().name + fullname = self.distribution.get_fullname() + arcname = self.make_archive(archive_basename, "zip", + root_dir=self.bdist_dir) + # create an exe containing the zip-file + self.create_exe(arcname, fullname, self.bitmap) + if self.distribution.has_ext_modules(): + pyversion = get_python_version() + else: + pyversion = 'any' + self.distribution.dist_files.append(('bdist_wininst', pyversion, + self.get_installer_filename(fullname))) + # remove the zip-file again + logger.debug("removing temporary file '%s'", arcname) + os.remove(arcname) + + if not self.keep_temp: + if self.dry_run: + logger.info('removing %s', self.bdist_dir) + else: + rmtree(self.bdist_dir) + + def get_inidata(self): + # Return data describing the installation. + + lines = [] + metadata = self.distribution.metadata + + # Write the [metadata] section. + lines.append("[metadata]") + + # 'info' will be displayed in the installer's dialog box, + # describing the items to be installed. + info = (metadata.long_description or '') + '\n' + + # Escape newline characters + def escape(s): + return s.replace("\n", "\\n") + + for name in ["author", "author_email", "description", "maintainer", + "maintainer_email", "name", "url", "version"]: + data = getattr(metadata, name, "") + if data: + info = info + ("\n %s: %s" % \ + (name.capitalize(), escape(data))) + lines.append("%s=%s" % (name, escape(data))) + + # The [setup] section contains entries controlling + # the installer runtime. + lines.append("\n[Setup]") + if self.install_script: + lines.append("install_script=%s" % self.install_script) + lines.append("info=%s" % escape(info)) + lines.append("target_compile=%d" % (not self.no_target_compile)) + lines.append("target_optimize=%d" % (not self.no_target_optimize)) + if self.target_version: + lines.append("target_version=%s" % self.target_version) + if self.user_access_control: + lines.append("user_access_control=%s" % self.user_access_control) + + title = self.title or self.distribution.get_fullname() + lines.append("title=%s" % escape(title)) + import time + import packaging + build_info = "Built %s with packaging-%s" % \ + (time.ctime(time.time()), packaging.__version__) + lines.append("build_info=%s" % build_info) + return "\n".join(lines) + + def create_exe(self, arcname, fullname, bitmap=None): + import struct + + self.mkpath(self.dist_dir) + + cfgdata = self.get_inidata() + + installer_name = self.get_installer_filename(fullname) + logger.info("creating %s", installer_name) + + if bitmap: + with open(bitmap, "rb") as fp: + bitmapdata = fp.read() + bitmaplen = len(bitmapdata) + else: + bitmaplen = 0 + + with open(installer_name, "wb") as file: + file.write(self.get_exe_bytes()) + if bitmap: + file.write(bitmapdata) + + # Convert cfgdata from unicode to ascii, mbcs encoded + if isinstance(cfgdata, str): + cfgdata = cfgdata.encode("mbcs") + + # Append the pre-install script + cfgdata = cfgdata + "\0" + if self.pre_install_script: + with open(self.pre_install_script) as fp: + script_data = fp.read() + cfgdata = cfgdata + script_data + "\n\0" + else: + # empty pre-install script + cfgdata = cfgdata + "\0" + file.write(cfgdata) + + # The 'magic number' 0x1234567B is used to make sure that the + # binary layout of 'cfgdata' is what the wininst.exe binary + # expects. If the layout changes, increment that number, make + # the corresponding changes to the wininst.exe sources, and + # recompile them. + header = struct.pack(" cur_version: + bv = get_build_version() + else: + if self.target_version < "2.4": + bv = 6.0 + else: + bv = 7.1 + else: + # for current version - use authoritative check. + bv = get_build_version() + + # wininst-x.y.exe is in the same directory as this file + directory = os.path.dirname(__file__) + # we must use a wininst-x.y.exe built with the same C compiler + # used for python. XXX What about mingw, borland, and so on? + + # if plat_name starts with "win" but is not "win32" + # we want to strip "win" and leave the rest (e.g. -amd64) + # for all other cases, we don't want any suffix + if self.plat_name != 'win32' and self.plat_name[:3] == 'win': + sfix = self.plat_name[3:] + else: + sfix = '' + + filename = os.path.join(directory, "wininst-%.1f%s.exe" % (bv, sfix)) + with open(filename, "rb") as fp: + return fp.read() diff --git a/Lib/packaging/command/build.py b/Lib/packaging/command/build.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/build.py @@ -0,0 +1,151 @@ +"""Main build command, which calls the other build_* commands.""" + +import sys +import os + +from packaging.util import get_platform +from packaging.command.cmd import Command +from packaging.errors import PackagingOptionError +from packaging.compiler import show_compilers + + +class build(Command): + + description = "build everything needed to install" + + user_options = [ + ('build-base=', 'b', + "base directory for build library"), + ('build-purelib=', None, + "build directory for platform-neutral distributions"), + ('build-platlib=', None, + "build directory for platform-specific distributions"), + ('build-lib=', None, + "build directory for all distribution (defaults to either " + + "build-purelib or build-platlib"), + ('build-scripts=', None, + "build directory for scripts"), + ('build-temp=', 't', + "temporary build directory"), + ('plat-name=', 'p', + "platform name to build for, if supported " + "(default: %s)" % get_platform()), + ('compiler=', 'c', + "specify the compiler type"), + ('debug', 'g', + "compile extensions and libraries with debugging information"), + ('force', 'f', + "forcibly build everything (ignore file timestamps)"), + ('executable=', 'e', + "specify final destination interpreter path (build.py)"), + ('use-2to3', None, + "use 2to3 to make source python 3.x compatible"), + ('convert-2to3-doctests', None, + "use 2to3 to convert doctests in seperate text files"), + ('use-2to3-fixers', None, + "list additional fixers opted for during 2to3 conversion"), + ] + + boolean_options = ['debug', 'force'] + + help_options = [ + ('help-compiler', None, + "list available compilers", show_compilers), + ] + + def initialize_options(self): + self.build_base = 'build' + # these are decided only after 'build_base' has its final value + # (unless overridden by the user or client) + self.build_purelib = None + self.build_platlib = None + self.build_lib = None + self.build_temp = None + self.build_scripts = None + self.compiler = None + self.plat_name = None + self.debug = None + self.force = False + self.executable = None + self.use_2to3 = False + self.convert_2to3_doctests = None + self.use_2to3_fixers = None + + def finalize_options(self): + if self.plat_name is None: + self.plat_name = get_platform() + else: + # plat-name only supported for windows (other platforms are + # supported via ./configure flags, if at all). Avoid misleading + # other platforms. + if os.name != 'nt': + raise PackagingOptionError( + "--plat-name only supported on Windows (try " + "using './configure --help' on your platform)") + + plat_specifier = ".%s-%s" % (self.plat_name, sys.version[0:3]) + + # Make it so Python 2.x and Python 2.x with --with-pydebug don't + # share the same build directories. Doing so confuses the build + # process for C modules + if hasattr(sys, 'gettotalrefcount'): + plat_specifier += '-pydebug' + + # 'build_purelib' and 'build_platlib' just default to 'lib' and + # 'lib.' under the base build directory. We only use one of + # them for a given distribution, though -- + if self.build_purelib is None: + self.build_purelib = os.path.join(self.build_base, 'lib') + if self.build_platlib is None: + self.build_platlib = os.path.join(self.build_base, + 'lib' + plat_specifier) + + # 'build_lib' is the actual directory that we will use for this + # particular module distribution -- if user didn't supply it, pick + # one of 'build_purelib' or 'build_platlib'. + if self.build_lib is None: + if self.distribution.ext_modules: + self.build_lib = self.build_platlib + else: + self.build_lib = self.build_purelib + + # 'build_temp' -- temporary directory for compiler turds, + # "build/temp." + if self.build_temp is None: + self.build_temp = os.path.join(self.build_base, + 'temp' + plat_specifier) + if self.build_scripts is None: + self.build_scripts = os.path.join(self.build_base, + 'scripts-' + sys.version[0:3]) + + if self.executable is None: + self.executable = os.path.normpath(sys.executable) + + def run(self): + # Run all relevant sub-commands. This will be some subset of: + # - build_py - pure Python modules + # - build_clib - standalone C libraries + # - build_ext - Python extension modules + # - build_scripts - Python scripts + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + # -- Predicates for the sub-command list --------------------------- + + def has_pure_modules(self): + return self.distribution.has_pure_modules() + + def has_c_libraries(self): + return self.distribution.has_c_libraries() + + def has_ext_modules(self): + return self.distribution.has_ext_modules() + + def has_scripts(self): + return self.distribution.has_scripts() + + sub_commands = [('build_py', has_pure_modules), + ('build_clib', has_c_libraries), + ('build_ext', has_ext_modules), + ('build_scripts', has_scripts), + ] diff --git a/Lib/packaging/command/build_clib.py b/Lib/packaging/command/build_clib.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/build_clib.py @@ -0,0 +1,198 @@ +"""Build C/C++ libraries. + +This command is useful to build libraries that are included in the +distribution and needed by extension modules. +""" + +# XXX this module has *lots* of code ripped-off quite transparently from +# build_ext.py -- not surprisingly really, as the work required to build +# a static library from a collection of C source files is not really all +# that different from what's required to build a shared object file from +# a collection of C source files. Nevertheless, I haven't done the +# necessary refactoring to account for the overlap in code between the +# two modules, mainly because a number of subtle details changed in the +# cut 'n paste. Sigh. + +import os +from packaging.command.cmd import Command +from packaging.errors import PackagingSetupError +from packaging.compiler import customize_compiler +from packaging import logger + + +def show_compilers(): + from packaging.compiler import show_compilers + show_compilers() + + +class build_clib(Command): + + description = "build C/C++ libraries used by extension modules" + + user_options = [ + ('build-clib=', 'b', + "directory to build C/C++ libraries to"), + ('build-temp=', 't', + "directory to put temporary build by-products"), + ('debug', 'g', + "compile with debugging information"), + ('force', 'f', + "forcibly build everything (ignore file timestamps)"), + ('compiler=', 'c', + "specify the compiler type"), + ] + + boolean_options = ['debug', 'force'] + + help_options = [ + ('help-compiler', None, + "list available compilers", show_compilers), + ] + + def initialize_options(self): + self.build_clib = None + self.build_temp = None + + # List of libraries to build + self.libraries = None + + # Compilation options for all libraries + self.include_dirs = None + self.define = None + self.undef = None + self.debug = None + self.force = False + self.compiler = None + + + def finalize_options(self): + # This might be confusing: both build-clib and build-temp default + # to build-temp as defined by the "build" command. This is because + # I think that C libraries are really just temporary build + # by-products, at least from the point of view of building Python + # extensions -- but I want to keep my options open. + self.set_undefined_options('build', + ('build_temp', 'build_clib'), + ('build_temp', 'build_temp'), + 'compiler', 'debug', 'force') + + self.libraries = self.distribution.libraries + if self.libraries: + self.check_library_list(self.libraries) + + if self.include_dirs is None: + self.include_dirs = self.distribution.include_dirs or [] + if isinstance(self.include_dirs, str): + self.include_dirs = self.include_dirs.split(os.pathsep) + + # XXX same as for build_ext -- what about 'self.define' and + # 'self.undef' ? + + def run(self): + if not self.libraries: + return + + # Yech -- this is cut 'n pasted from build_ext.py! + from packaging.compiler import new_compiler + self.compiler = new_compiler(compiler=self.compiler, + dry_run=self.dry_run, + force=self.force) + customize_compiler(self.compiler) + + if self.include_dirs is not None: + self.compiler.set_include_dirs(self.include_dirs) + if self.define is not None: + # 'define' option is a list of (name,value) tuples + for name, value in self.define: + self.compiler.define_macro(name, value) + if self.undef is not None: + for macro in self.undef: + self.compiler.undefine_macro(macro) + + self.build_libraries(self.libraries) + + + def check_library_list(self, libraries): + """Ensure that the list of libraries is valid. + + `library` is presumably provided as a command option 'libraries'. + This method checks that it is a list of 2-tuples, where the tuples + are (library_name, build_info_dict). + + Raise PackagingSetupError if the structure is invalid anywhere; + just returns otherwise. + """ + if not isinstance(libraries, list): + raise PackagingSetupError("'libraries' option must be a list of tuples") + + for lib in libraries: + if not isinstance(lib, tuple) and len(lib) != 2: + raise PackagingSetupError("each element of 'libraries' must a 2-tuple") + + name, build_info = lib + + if not isinstance(name, str): + raise PackagingSetupError("first element of each tuple in 'libraries' " + \ + "must be a string (the library name)") + if '/' in name or (os.sep != '/' and os.sep in name): + raise PackagingSetupError(("bad library name '%s': " + + "may not contain directory separators") % \ + lib[0]) + + if not isinstance(build_info, dict): + raise PackagingSetupError("second element of each tuple in 'libraries' " + \ + "must be a dictionary (build info)") + + def get_library_names(self): + # Assume the library list is valid -- 'check_library_list()' is + # called from 'finalize_options()', so it should be! + if not self.libraries: + return None + + lib_names = [] + for lib_name, build_info in self.libraries: + lib_names.append(lib_name) + return lib_names + + + def get_source_files(self): + self.check_library_list(self.libraries) + filenames = [] + for lib_name, build_info in self.libraries: + sources = build_info.get('sources') + if sources is None or not isinstance(sources, (list, tuple)): + raise PackagingSetupError(("in 'libraries' option (library '%s'), " + "'sources' must be present and must be " + "a list of source filenames") % lib_name) + + filenames.extend(sources) + return filenames + + def build_libraries(self, libraries): + for lib_name, build_info in libraries: + sources = build_info.get('sources') + if sources is None or not isinstance(sources, (list, tuple)): + raise PackagingSetupError(("in 'libraries' option (library '%s'), " + + "'sources' must be present and must be " + + "a list of source filenames") % lib_name) + sources = list(sources) + + logger.info("building '%s' library", lib_name) + + # First, compile the source code to object files in the library + # directory. (This should probably change to putting object + # files in a temporary build directory.) + macros = build_info.get('macros') + include_dirs = build_info.get('include_dirs') + objects = self.compiler.compile(sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug) + + # Now "link" the object files together into a static library. + # (On Unix at least, this isn't really linking -- it just + # builds an archive. Whatever.) + self.compiler.create_static_lib(objects, lib_name, + output_dir=self.build_clib, + debug=self.debug) diff --git a/Lib/packaging/command/build_ext.py b/Lib/packaging/command/build_ext.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/build_ext.py @@ -0,0 +1,666 @@ +"""Build extension modules.""" + +# FIXME Is this module limited to C extensions or do C++ extensions work too? +# The docstring of this module said that C++ was not supported, but other +# comments contradict that. + +import os +import re +import sys +import logging +import sysconfig + +from packaging.util import get_platform +from packaging.command.cmd import Command +from packaging.errors import (CCompilerError, CompileError, PackagingError, + PackagingPlatformError, PackagingSetupError) +from packaging.compiler import customize_compiler, show_compilers +from packaging.util import newer_group +from packaging.compiler.extension import Extension +from packaging import logger + +import site +HAS_USER_SITE = True + +if os.name == 'nt': + from packaging.compiler.msvccompiler import get_build_version + MSVC_VERSION = int(get_build_version()) + +# An extension name is just a dot-separated list of Python NAMEs (ie. +# the same as a fully-qualified module name). +extension_name_re = re.compile \ + (r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$') + + +class build_ext(Command): + + description = "build C/C++ extension modules (compile/link to build directory)" + + # XXX thoughts on how to deal with complex command-line options like + # these, i.e. how to make it so fancy_getopt can suck them off the + # command line and make it look like setup.py defined the appropriate + # lists of tuples of what-have-you. + # - each command needs a callback to process its command-line options + # - Command.__init__() needs access to its share of the whole + # command line (must ultimately come from + # Distribution.parse_command_line()) + # - it then calls the current command class' option-parsing + # callback to deal with weird options like -D, which have to + # parse the option text and churn out some custom data + # structure + # - that data structure (in this case, a list of 2-tuples) + # will then be present in the command object by the time + # we get to finalize_options() (i.e. the constructor + # takes care of both command-line and client options + # in between initialize_options() and finalize_options()) + + sep_by = " (separated by '%s')" % os.pathsep + user_options = [ + ('build-lib=', 'b', + "directory for compiled extension modules"), + ('build-temp=', 't', + "directory for temporary files (build by-products)"), + ('plat-name=', 'p', + "platform name to cross-compile for, if supported " + "(default: %s)" % get_platform()), + ('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" + sep_by), + ('define=', 'D', + "C preprocessor macros to define"), + ('undef=', 'U', + "C preprocessor macros to undefine"), + ('libraries=', 'l', + "external C libraries to link with"), + ('library-dirs=', 'L', + "directories to search for external C libraries" + sep_by), + ('rpath=', 'R', + "directories to search for shared C libraries at runtime"), + ('link-objects=', 'O', + "extra explicit link objects to include in the link"), + ('debug', 'g', + "compile/link with debugging information"), + ('force', 'f', + "forcibly build everything (ignore file timestamps)"), + ('compiler=', 'c', + "specify the compiler type"), + ('swig-opts=', None, + "list of SWIG command-line options"), + ('swig=', None, + "path to the SWIG executable"), + ] + + boolean_options = ['inplace', 'debug', 'force'] + + if HAS_USER_SITE: + user_options.append(('user', None, + "add user include, library and rpath")) + boolean_options.append('user') + + help_options = [ + ('help-compiler', None, + "list available compilers", show_compilers), + ] + + def initialize_options(self): + self.extensions = None + self.build_lib = None + self.plat_name = None + self.build_temp = None + self.inplace = False + self.package = None + + self.include_dirs = None + self.define = None + self.undef = None + self.libraries = None + self.library_dirs = None + self.rpath = None + self.link_objects = None + self.debug = None + self.force = None + self.compiler = None + self.swig = None + self.swig_opts = None + if HAS_USER_SITE: + self.user = None + + def finalize_options(self): + self.set_undefined_options('build', + 'build_lib', 'build_temp', 'compiler', + 'debug', 'force', 'plat_name') + + if self.package is None: + self.package = self.distribution.ext_package + + # Ensure that the list of extensions is valid, i.e. it is a list of + # Extension objects. + self.extensions = self.distribution.ext_modules + if self.extensions: + if not isinstance(self.extensions, (list, tuple)): + type_name = (self.extensions is None and 'None' + or type(self.extensions).__name__) + raise PackagingSetupError( + "'ext_modules' must be a sequence of Extension instances," + " not %s" % (type_name,)) + for i, ext in enumerate(self.extensions): + if isinstance(ext, Extension): + continue # OK! (assume type-checking done + # by Extension constructor) + type_name = (ext is None and 'None' or type(ext).__name__) + raise PackagingSetupError( + "'ext_modules' item %d must be an Extension instance," + " not %s" % (i, type_name)) + + # Make sure Python's include directories (for Python.h, pyconfig.h, + # etc.) are in the include search path. + py_include = sysconfig.get_path('include') + plat_py_include = sysconfig.get_path('platinclude') + if self.include_dirs is None: + self.include_dirs = self.distribution.include_dirs or [] + if isinstance(self.include_dirs, str): + self.include_dirs = self.include_dirs.split(os.pathsep) + + # Put the Python "system" include dir at the end, so that + # any local include dirs take precedence. + self.include_dirs.append(py_include) + if plat_py_include != py_include: + self.include_dirs.append(plat_py_include) + + if isinstance(self.libraries, str): + self.libraries = [self.libraries] + + # Life is easier if we're not forever checking for None, so + # simplify these options to empty lists if unset + if self.libraries is None: + self.libraries = [] + if self.library_dirs is None: + self.library_dirs = [] + elif isinstance(self.library_dirs, str): + self.library_dirs = self.library_dirs.split(os.pathsep) + + if self.rpath is None: + self.rpath = [] + elif isinstance(self.rpath, str): + self.rpath = self.rpath.split(os.pathsep) + + # for extensions under windows use different directories + # for Release and Debug builds. + # also Python's library directory must be appended to library_dirs + if os.name == 'nt': + # the 'libs' directory is for binary installs - we assume that + # must be the *native* platform. But we don't really support + # cross-compiling via a binary install anyway, so we let it go. + self.library_dirs.append(os.path.join(sys.exec_prefix, 'libs')) + if self.debug: + self.build_temp = os.path.join(self.build_temp, "Debug") + else: + self.build_temp = os.path.join(self.build_temp, "Release") + + # Append the source distribution include and library directories, + # this allows distutils on windows to work in the source tree + self.include_dirs.append(os.path.join(sys.exec_prefix, 'PC')) + if MSVC_VERSION == 9: + # Use the .lib files for the correct architecture + if self.plat_name == 'win32': + suffix = '' + else: + # win-amd64 or win-ia64 + suffix = self.plat_name[4:] + new_lib = os.path.join(sys.exec_prefix, 'PCbuild') + if suffix: + new_lib = os.path.join(new_lib, suffix) + self.library_dirs.append(new_lib) + + elif MSVC_VERSION == 8: + self.library_dirs.append(os.path.join(sys.exec_prefix, + 'PC', 'VS8.0')) + elif MSVC_VERSION == 7: + self.library_dirs.append(os.path.join(sys.exec_prefix, + 'PC', 'VS7.1')) + else: + self.library_dirs.append(os.path.join(sys.exec_prefix, + 'PC', 'VC6')) + + # OS/2 (EMX) doesn't support Debug vs Release builds, but has the + # import libraries in its "Config" subdirectory + if os.name == 'os2': + self.library_dirs.append(os.path.join(sys.exec_prefix, 'Config')) + + # for extensions under Cygwin and AtheOS Python's library directory must be + # appended to library_dirs + if sys.platform[:6] == 'cygwin' or sys.platform[:6] == 'atheos': + if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")): + # building third party extensions + self.library_dirs.append(os.path.join(sys.prefix, "lib", + "python" + sysconfig.get_python_version(), + "config")) + else: + # building python standard extensions + self.library_dirs.append(os.curdir) + + # for extensions under Linux or Solaris with a shared Python library, + # Python's library directory must be appended to library_dirs + sysconfig.get_config_var('Py_ENABLE_SHARED') + if ((sys.platform.startswith('linux') or sys.platform.startswith('gnu') + or sys.platform.startswith('sunos')) + and sysconfig.get_config_var('Py_ENABLE_SHARED')): + if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")): + # building third party extensions + self.library_dirs.append(sysconfig.get_config_var('LIBDIR')) + else: + # building python standard extensions + self.library_dirs.append(os.curdir) + + # The argument parsing will result in self.define being a string, but + # it has to be a list of 2-tuples. All the preprocessor symbols + # specified by the 'define' option will be set to '1'. Multiple + # symbols can be separated with commas. + + if self.define: + defines = self.define.split(',') + self.define = [(symbol, '1') for symbol in defines] + + # The option for macros to undefine is also a string from the + # option parsing, but has to be a list. Multiple symbols can also + # be separated with commas here. + if self.undef: + self.undef = self.undef.split(',') + + if self.swig_opts is None: + self.swig_opts = [] + else: + self.swig_opts = self.swig_opts.split(' ') + + # Finally add the user include and library directories if requested + if HAS_USER_SITE and self.user: + user_include = os.path.join(site.USER_BASE, "include") + user_lib = os.path.join(site.USER_BASE, "lib") + if os.path.isdir(user_include): + self.include_dirs.append(user_include) + if os.path.isdir(user_lib): + self.library_dirs.append(user_lib) + self.rpath.append(user_lib) + + def run(self): + from packaging.compiler import new_compiler + + # 'self.extensions', as supplied by setup.py, is a list of + # Extension instances. See the documentation for Extension (in + # distutils.extension) for details. + if not self.extensions: + return + + # If we were asked to build any C/C++ libraries, make sure that the + # directory where we put them is in the library search path for + # linking extensions. + if self.distribution.has_c_libraries(): + build_clib = self.get_finalized_command('build_clib') + self.libraries.extend(build_clib.get_library_names() or []) + self.library_dirs.append(build_clib.build_clib) + + # Temporary kludge until we remove the verbose arguments and use + # logging everywhere + verbose = logger.getEffectiveLevel() >= logging.DEBUG + + # Setup the CCompiler object that we'll use to do all the + # compiling and linking + self.compiler_obj = new_compiler(compiler=self.compiler, + verbose=verbose, + dry_run=self.dry_run, + force=self.force) + + customize_compiler(self.compiler_obj) + # If we are cross-compiling, init the compiler now (if we are not + # cross-compiling, init would not hurt, but people may rely on + # late initialization of compiler even if they shouldn't...) + if os.name == 'nt' and self.plat_name != get_platform(): + self.compiler_obj.initialize(self.plat_name) + + # And make sure that any compile/link-related options (which might + # come from the command line or from the setup script) are set in + # that CCompiler object -- that way, they automatically apply to + # all compiling and linking done here. + if self.include_dirs is not None: + self.compiler_obj.set_include_dirs(self.include_dirs) + if self.define is not None: + # 'define' option is a list of (name,value) tuples + for name, value in self.define: + self.compiler_obj.define_macro(name, value) + if self.undef is not None: + for macro in self.undef: + self.compiler_obj.undefine_macro(macro) + if self.libraries is not None: + self.compiler_obj.set_libraries(self.libraries) + if self.library_dirs is not None: + self.compiler_obj.set_library_dirs(self.library_dirs) + if self.rpath is not None: + self.compiler_obj.set_runtime_library_dirs(self.rpath) + if self.link_objects is not None: + self.compiler_obj.set_link_objects(self.link_objects) + + # Now actually compile and link everything. + self.build_extensions() + + def get_source_files(self): + filenames = [] + + # Wouldn't it be neat if we knew the names of header files too... + for ext in self.extensions: + filenames.extend(ext.sources) + + return filenames + + def get_outputs(self): + # And build the list of output (built) filenames. Note that this + # ignores the 'inplace' flag, and assumes everything goes in the + # "build" tree. + outputs = [] + for ext in self.extensions: + outputs.append(self.get_ext_fullpath(ext.name)) + return outputs + + def build_extensions(self): + for ext in self.extensions: + try: + self.build_extension(ext) + except (CCompilerError, PackagingError, CompileError) as e: + if not ext.optional: + raise + logger.warning('%s: building extension %r failed: %s', + self.get_command_name(), ext.name, e) + + def build_extension(self, ext): + sources = ext.sources + if sources is None or not isinstance(sources, (list, tuple)): + raise PackagingSetupError(("in 'ext_modules' option (extension '%s'), " + + "'sources' must be present and must be " + + "a list of source filenames") % ext.name) + sources = list(sources) + + ext_path = self.get_ext_fullpath(ext.name) + depends = sources + ext.depends + if not (self.force or newer_group(depends, ext_path, 'newer')): + logger.debug("skipping '%s' extension (up-to-date)", ext.name) + return + else: + logger.info("building '%s' extension", ext.name) + + # First, scan the sources for SWIG definition files (.i), run + # SWIG on 'em to create .c files, and modify the sources list + # accordingly. + sources = self.swig_sources(sources, ext) + + # Next, compile the source code to object files. + + # XXX not honouring 'define_macros' or 'undef_macros' -- the + # CCompiler API needs to change to accommodate this, and I + # want to do one thing at a time! + + # Two possible sources for extra compiler arguments: + # - 'extra_compile_args' in Extension object + # - CFLAGS environment variable (not particularly + # elegant, but people seem to expect it and I + # guess it's useful) + # The environment variable should take precedence, and + # any sensible compiler will give precedence to later + # command-line args. Hence we combine them in order: + extra_args = ext.extra_compile_args or [] + + macros = ext.define_macros[:] + for undef in ext.undef_macros: + macros.append((undef,)) + + objects = self.compiler_obj.compile(sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=ext.include_dirs, + debug=self.debug, + extra_postargs=extra_args, + depends=ext.depends) + + # XXX -- this is a Vile HACK! + # + # The setup.py script for Python on Unix needs to be able to + # get this list so it can perform all the clean up needed to + # avoid keeping object files around when cleaning out a failed + # build of an extension module. Since Packaging does not + # track dependencies, we have to get rid of intermediates to + # ensure all the intermediates will be properly re-built. + # + self._built_objects = objects[:] + + # Now link the object files together into a "shared object" -- + # of course, first we have to figure out all the other things + # that go into the mix. + if ext.extra_objects: + objects.extend(ext.extra_objects) + extra_args = ext.extra_link_args or [] + + # Detect target language, if not provided + language = ext.language or self.compiler_obj.detect_language(sources) + + self.compiler_obj.link_shared_object( + objects, ext_path, + libraries=self.get_libraries(ext), + library_dirs=ext.library_dirs, + runtime_library_dirs=ext.runtime_library_dirs, + extra_postargs=extra_args, + export_symbols=self.get_export_symbols(ext), + debug=self.debug, + build_temp=self.build_temp, + target_lang=language) + + + def swig_sources(self, sources, extension): + """Walk the list of source files in 'sources', looking for SWIG + interface (.i) files. Run SWIG on all that are found, and + return a modified 'sources' list with SWIG source files replaced + by the generated C (or C++) files. + """ + new_sources = [] + swig_sources = [] + swig_targets = {} + + # XXX this drops generated C/C++ files into the source tree, which + # is fine for developers who want to distribute the generated + # source -- but there should be an option to put SWIG output in + # the temp dir. + + if ('-c++' in self.swig_opts or '-c++' in extension.swig_opts): + target_ext = '.cpp' + else: + target_ext = '.c' + + for source in sources: + base, ext = os.path.splitext(source) + if ext == ".i": # SWIG interface file + new_sources.append(base + '_wrap' + target_ext) + swig_sources.append(source) + swig_targets[source] = new_sources[-1] + else: + new_sources.append(source) + + if not swig_sources: + return new_sources + + swig = self.swig or self.find_swig() + swig_cmd = [swig, "-python"] + swig_cmd.extend(self.swig_opts) + + # Do not override commandline arguments + if not self.swig_opts: + for o in extension.swig_opts: + swig_cmd.append(o) + + for source in swig_sources: + target = swig_targets[source] + logger.info("swigging %s to %s", source, target) + self.spawn(swig_cmd + ["-o", target, source]) + + return new_sources + + def find_swig(self): + """Return the name of the SWIG executable. On Unix, this is + just "swig" -- it should be in the PATH. Tries a bit harder on + Windows. + """ + + if os.name == "posix": + return "swig" + elif os.name == "nt": + + # Look for SWIG in its standard installation directory on + # Windows (or so I presume!). If we find it there, great; + # if not, act like Unix and assume it's in the PATH. + for vers in ("1.3", "1.2", "1.1"): + fn = os.path.join("c:\\swig%s" % vers, "swig.exe") + if os.path.isfile(fn): + return fn + else: + return "swig.exe" + + elif os.name == "os2": + # assume swig available in the PATH. + return "swig.exe" + + else: + raise PackagingPlatformError(("I don't know how to find (much less run) SWIG " + "on platform '%s'") % os.name) + + # -- Name generators ----------------------------------------------- + # (extension names, filenames, whatever) + def get_ext_fullpath(self, ext_name): + """Returns the path of the filename for a given extension. + + The file is located in `build_lib` or directly in the package + (inplace option). + """ + fullname = self.get_ext_fullname(ext_name) + modpath = fullname.split('.') + filename = self.get_ext_filename(modpath[-1]) + + if not self.inplace: + # no further work needed + # returning : + # build_dir/package/path/filename + filename = os.path.join(*modpath[:-1]+[filename]) + return os.path.join(self.build_lib, filename) + + # the inplace option requires to find the package directory + # using the build_py command for that + package = '.'.join(modpath[0:-1]) + build_py = self.get_finalized_command('build_py') + package_dir = os.path.abspath(build_py.get_package_dir(package)) + + # returning + # package_dir/filename + return os.path.join(package_dir, filename) + + def get_ext_fullname(self, ext_name): + """Returns the fullname of a given extension name. + + Adds the `package.` prefix""" + if self.package is None: + return ext_name + else: + return self.package + '.' + ext_name + + def get_ext_filename(self, ext_name): + r"""Convert the name of an extension (eg. "foo.bar") into the name + of the file from which it will be loaded (eg. "foo/bar.so", or + "foo\bar.pyd"). + """ + ext_path = ext_name.split('.') + # OS/2 has an 8 character module (extension) limit :-( + if os.name == "os2": + ext_path[len(ext_path) - 1] = ext_path[len(ext_path) - 1][:8] + # extensions in debug_mode are named 'module_d.pyd' under windows + so_ext = sysconfig.get_config_var('SO') + if os.name == 'nt' and self.debug: + return os.path.join(*ext_path) + '_d' + so_ext + return os.path.join(*ext_path) + so_ext + + def get_export_symbols(self, ext): + """Return the list of symbols that a shared extension has to + export. This either uses 'ext.export_symbols' or, if it's not + provided, "init" + module_name. Only relevant on Windows, where + the .pyd file (DLL) must export the module "init" function. + """ + initfunc_name = "init" + ext.name.split('.')[-1] + if initfunc_name not in ext.export_symbols: + ext.export_symbols.append(initfunc_name) + return ext.export_symbols + + def get_libraries(self, ext): + """Return the list of libraries to link against when building a + shared extension. On most platforms, this is just 'ext.libraries'; + on Windows and OS/2, we add the Python library (eg. python20.dll). + """ + # The python library is always needed on Windows. For MSVC, this + # is redundant, since the library is mentioned in a pragma in + # pyconfig.h that MSVC groks. The other Windows compilers all seem + # to need it mentioned explicitly, though, so that's what we do. + # Append '_d' to the python import library on debug builds. + if sys.platform == "win32": + from packaging.compiler.msvccompiler import MSVCCompiler + if not isinstance(self.compiler_obj, MSVCCompiler): + template = "python%d%d" + if self.debug: + template = template + '_d' + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + # don't extend ext.libraries, it may be shared with other + # extensions, it is a reference to the original list + return ext.libraries + [pythonlib] + else: + return ext.libraries + elif sys.platform == "os2emx": + # EMX/GCC requires the python library explicitly, and I + # believe VACPP does as well (though not confirmed) - AIM Apr01 + template = "python%d%d" + # debug versions of the main DLL aren't supported, at least + # not at this time - AIM Apr01 + #if self.debug: + # template = template + '_d' + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + # don't extend ext.libraries, it may be shared with other + # extensions, it is a reference to the original list + return ext.libraries + [pythonlib] + elif sys.platform[:6] == "cygwin": + template = "python%d.%d" + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + # don't extend ext.libraries, it may be shared with other + # extensions, it is a reference to the original list + return ext.libraries + [pythonlib] + elif sys.platform[:6] == "atheos": + template = "python%d.%d" + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + # Get SHLIBS from Makefile + extra = [] + for lib in sysconfig.get_config_var('SHLIBS').split(): + if lib.startswith('-l'): + extra.append(lib[2:]) + else: + extra.append(lib) + # don't extend ext.libraries, it may be shared with other + # extensions, it is a reference to the original list + return ext.libraries + [pythonlib, "m"] + extra + + elif sys.platform == 'darwin': + # Don't use the default code below + return ext.libraries + + else: + if sysconfig.get_config_var('Py_ENABLE_SHARED'): + template = "python%d.%d" + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + return ext.libraries + [pythonlib] + else: + return ext.libraries diff --git a/Lib/packaging/command/build_py.py b/Lib/packaging/command/build_py.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/build_py.py @@ -0,0 +1,410 @@ +"""Build pure Python modules (just copy to build directory).""" + +import os +import sys +from glob import glob + +from packaging import logger +from packaging.command.cmd import Command +from packaging.errors import PackagingOptionError, PackagingFileError +from packaging.util import convert_path +from packaging.compat import Mixin2to3 + +# marking public APIs +__all__ = ['build_py'] + +class build_py(Command, Mixin2to3): + + description = "build pure Python modules (copy to build directory)" + + user_options = [ + ('build-lib=', 'd', "directory to build (copy) to"), + ('compile', 'c', "compile .py to .pyc"), + ('no-compile', None, "don't compile .py files [default]"), + ('optimize=', 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + ('force', 'f', "forcibly build everything (ignore file timestamps)"), + ('use-2to3', None, + "use 2to3 to make source python 3.x compatible"), + ('convert-2to3-doctests', None, + "use 2to3 to convert doctests in seperate text files"), + ('use-2to3-fixers', None, + "list additional fixers opted for during 2to3 conversion"), + ] + + boolean_options = ['compile', 'force'] + negative_opt = {'no-compile' : 'compile'} + + def initialize_options(self): + self.build_lib = None + self.py_modules = None + self.package = None + self.package_data = None + self.package_dir = None + self.compile = False + self.optimize = 0 + self.force = None + self._updated_files = [] + self._doctests_2to3 = [] + self.use_2to3 = False + self.convert_2to3_doctests = None + self.use_2to3_fixers = None + + def finalize_options(self): + self.set_undefined_options('build', + 'use_2to3', 'use_2to3_fixers', + 'convert_2to3_doctests', 'build_lib', + 'force') + + # Get the distribution options that are aliases for build_py + # options -- list of packages and list of modules. + self.packages = self.distribution.packages + self.py_modules = self.distribution.py_modules + self.package_data = self.distribution.package_data + 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 + # type system! Hell, *everything* needs a type system!!!) + if not isinstance(self.optimize, int): + try: + self.optimize = int(self.optimize) + assert 0 <= self.optimize <= 2 + except (ValueError, AssertionError): + raise PackagingOptionError("optimize must be 0, 1, or 2") + + def run(self): + # XXX copy_file by default preserves atime and mtime. IMHO this is + # the right thing to do, but perhaps it should be an option -- in + # particular, a site administrator might want installed files to + # reflect the time of installation rather than the last + # modification time before the installed release. + + # XXX copy_file by default preserves mode, which appears to be the + # wrong thing to do: if a file is read-only in the working + # directory, we want it to be installed read/write so that the next + # installation of the same module distribution can overwrite it + # without problems. (This might be a Unix-specific issue.) Thus + # we turn off 'preserve_mode' when copying to the build directory, + # since the build directory is supposed to be exactly what the + # installation will look like (ie. we preserve mode when + # installing). + + # Two options control which modules will be installed: 'packages' + # and 'py_modules'. The former lets us work with whole packages, not + # specifying individual modules at all; the latter is for + # specifying modules one-at-a-time. + + if self.py_modules: + self.build_modules() + if self.packages: + self.build_packages() + self.build_package_data() + + if self.use_2to3 and self._updated_files: + self.run_2to3(self._updated_files, self._doctests_2to3, + self.use_2to3_fixers) + + self.byte_compile(self.get_outputs(include_bytecode=False)) + + # -- Top-level worker functions ------------------------------------ + + def get_data_files(self): + """Generate list of '(package,src_dir,build_dir,filenames)' tuples. + + Helper function for `finalize_options()`. + """ + data = [] + if not self.packages: + return data + for package in self.packages: + # Locate package source directory + src_dir = self.get_package_dir(package) + + # Compute package build directory + build_dir = os.path.join(*([self.build_lib] + package.split('.'))) + + # Length of path to strip from found files + plen = 0 + if src_dir: + plen = len(src_dir)+1 + + # Strip directory from globbed filenames + filenames = [ + file[plen:] for file in self.find_data_files(package, src_dir) + ] + data.append((package, src_dir, build_dir, filenames)) + return data + + def find_data_files(self, package, src_dir): + """Return filenames for package's data files in 'src_dir'. + + Helper function for `get_data_files()`. + """ + globs = (self.package_data.get('', []) + + self.package_data.get(package, [])) + files = [] + for pattern in globs: + # Each pattern has to be converted to a platform-specific path + filelist = glob(os.path.join(src_dir, convert_path(pattern))) + # Files that match more than one pattern are only added once + files.extend(fn for fn in filelist if fn not in files) + return files + + def build_package_data(self): + """Copy data files into build directory. + + 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(srcfile, + target, preserve_mode=False) + if copied and srcfile in self.distribution.convert_2to3.doctests: + self._doctests_2to3.append(outf) + + # XXX - this should be moved to the Distribution class as it is not + # only needed for build_py. It also has no dependencies on this class. + def get_package_dir(self, package): + """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) + + if len(path) > 0: + return os.path.join(*path) + + return '' + + def check_package(self, package, package_dir): + """Helper function for `find_package_modules()` and `find_modules()'. + """ + # Empty dir name means current directory, which we can probably + # assume exists. Also, os.path.exists and isdir don't know about + # my "empty string means current dir" convention, so we have to + # circumvent them. + if package_dir != "": + if not os.path.exists(package_dir): + raise PackagingFileError( + "package directory '%s' does not exist" % package_dir) + if not os.path.isdir(package_dir): + raise PackagingFileError( + "supposed package directory '%s' exists, " + "but is not a directory" % package_dir) + + # Require __init__.py for all but the "root package" + if package: + init_py = os.path.join(package_dir, "__init__.py") + if os.path.isfile(init_py): + return init_py + else: + logger.warning(("package init file '%s' not found " + + "(or not a regular file)"), init_py) + + # Either not in a package at all (__init__.py not expected), or + # __init__.py doesn't exist -- so don't return the filename. + return None + + def check_module(self, module, module_file): + if not os.path.isfile(module_file): + logger.warning("file %s (for module %s) not found", + module_file, module) + return False + else: + return True + + def find_package_modules(self, package, package_dir): + self.check_package(package, package_dir) + module_files = glob(os.path.join(package_dir, "*.py")) + modules = [] + if self.distribution.script_name is not None: + setup_script = os.path.abspath(self.distribution.script_name) + else: + setup_script = None + + for f in module_files: + abs_f = os.path.abspath(f) + if abs_f != setup_script: + module = os.path.splitext(os.path.basename(f))[0] + modules.append((package, module, f)) + else: + logger.debug("excluding %s", setup_script) + return modules + + def find_modules(self): + """Finds individually-specified Python modules, ie. those listed by + module name in 'self.py_modules'. Returns a list of tuples (package, + module_base, filename): 'package' is a tuple of the path through + package-space to the module; 'module_base' is the bare (no + packages, no dots) module name, and 'filename' is the path to the + ".py" file (relative to the distribution root) that implements the + module. + """ + # Map package names to tuples of useful info about the package: + # (package_dir, checked) + # package_dir - the directory where we'll find source files for + # this package + # checked - true if we have checked that the package directory + # is valid (exists, contains __init__.py, ... ?) + packages = {} + + # List of (package, module, filename) tuples to return + modules = [] + + # We treat modules-in-packages almost the same as toplevel modules, + # just the "package" for a toplevel is empty (either an empty + # string or empty list, depending on context). Differences: + # - don't check for __init__.py in directory for empty package + for module in self.py_modules: + path = module.split('.') + package = '.'.join(path[0:-1]) + module_base = path[-1] + + try: + package_dir, checked = packages[package] + except KeyError: + package_dir = self.get_package_dir(package) + checked = False + + if not checked: + init_py = self.check_package(package, package_dir) + packages[package] = (package_dir, 1) + if init_py: + modules.append((package, "__init__", init_py)) + + # XXX perhaps we should also check for just .pyc files + # (so greedy closed-source bastards can distribute Python + # modules too) + module_file = os.path.join(package_dir, module_base + ".py") + if not self.check_module(module, module_file): + continue + + modules.append((package, module_base, module_file)) + + return modules + + def find_all_modules(self): + """Compute the list of all modules that will be built, whether + they are specified one-module-at-a-time ('self.py_modules') or + by whole packages ('self.packages'). Return a list of tuples + (package, module, module_file), just like 'find_modules()' and + 'find_package_modules()' do.""" + modules = [] + if self.py_modules: + modules.extend(self.find_modules()) + if self.packages: + for package in self.packages: + package_dir = self.get_package_dir(package) + m = self.find_package_modules(package, package_dir) + modules.extend(m) + return modules + + def get_source_files(self): + sources = [module[-1] for module in self.find_all_modules()] + sources += [ + os.path.join(src_dir, filename) + for package, src_dir, build_dir, filenames in self.data_files + for filename in filenames] + return sources + + def get_module_outfile(self, build_dir, package, module): + outfile_path = [build_dir] + list(package) + [module + ".py"] + return os.path.join(*outfile_path) + + def get_outputs(self, include_bytecode=True): + modules = self.find_all_modules() + outputs = [] + for package, module, module_file in modules: + package = package.split('.') + filename = self.get_module_outfile(self.build_lib, package, module) + outputs.append(filename) + if include_bytecode: + if self.compile: + outputs.append(filename + "c") + if self.optimize > 0: + outputs.append(filename + "o") + + outputs += [ + os.path.join(build_dir, filename) + for package, src_dir, build_dir, filenames in self.data_files + for filename in filenames] + + return outputs + + def build_module(self, module, module_file, package): + if isinstance(package, str): + package = package.split('.') + elif not isinstance(package, (list, tuple)): + raise TypeError( + "'package' must be a string (dot-separated), list, or tuple") + + # Now put the module source file into the "build" area -- this is + # easy, we just copy it somewhere under self.build_lib (the build + # directory for Python source). + outfile = self.get_module_outfile(self.build_lib, package, module) + dir = os.path.dirname(outfile) + self.mkpath(dir) + return self.copy_file(module_file, outfile, preserve_mode=False) + + def build_modules(self): + modules = self.find_modules() + for package, module, module_file in modules: + + # Now "build" the module -- ie. copy the source file to + # self.build_lib (the build directory for Python source). + # (Actually, it gets copied to the directory for this package + # under self.build_lib.) + self.build_module(module, module_file, package) + + def build_packages(self): + for package in self.packages: + + # Get list of (package, module, module_file) tuples based on + # scanning the package directory. 'package' is only included + # in the tuple so that 'find_modules()' and + # 'find_package_tuples()' have a consistent interface; it's + # ignored here (apart from a sanity check). Also, 'module' is + # the *unqualified* module name (ie. no dots, no package -- we + # already know its package!), and 'module_file' is the path to + # the .py file, relative to the current directory + # (ie. including 'package_dir'). + package_dir = self.get_package_dir(package) + modules = self.find_package_modules(package, package_dir) + + # Now loop over the modules we found, "building" each one (just + # copy it to self.build_lib). + for package_, module, module_file in modules: + assert package == package_ + self.build_module(module, module_file, package) + + def byte_compile(self, files): + if hasattr(sys, 'dont_write_bytecode') and sys.dont_write_bytecode: + logger.warning('%s: byte-compiling is disabled, skipping.', + self.get_command_name()) + return + + from packaging.util import byte_compile + prefix = self.build_lib + if prefix[-1] != os.sep: + prefix = prefix + os.sep + + # XXX this code is essentially the same as the 'byte_compile() + # method of the "install_lib" command, except for the determination + # of the 'prefix' string. Hmmm. + + if self.compile: + byte_compile(files, optimize=0, + force=self.force, prefix=prefix, dry_run=self.dry_run) + if self.optimize > 0: + byte_compile(files, optimize=self.optimize, + force=self.force, prefix=prefix, dry_run=self.dry_run) diff --git a/Lib/packaging/command/build_scripts.py b/Lib/packaging/command/build_scripts.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/build_scripts.py @@ -0,0 +1,132 @@ +"""Build scripts (copy to build dir and fix up shebang line).""" + +import os +import re +import sysconfig + +from packaging.command.cmd import Command +from packaging.util import convert_path, newer +from packaging import logger +from packaging.compat import Mixin2to3 + + +# check if Python is called on the first line with this expression +first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$') + +class build_scripts(Command, Mixin2to3): + + description = "build scripts (copy and fix up shebang line)" + + user_options = [ + ('build-dir=', 'd', "directory to build (copy) to"), + ('force', 'f', "forcibly build everything (ignore file timestamps"), + ('executable=', 'e', "specify final destination interpreter path"), + ] + + boolean_options = ['force'] + + + def initialize_options(self): + self.build_dir = None + self.scripts = None + self.force = None + self.executable = None + self.outfiles = None + self.use_2to3 = False + self.convert_2to3_doctests = None + self.use_2to3_fixers = None + + def finalize_options(self): + self.set_undefined_options('build', + ('build_scripts', 'build_dir'), + 'use_2to3', 'use_2to3_fixers', + 'convert_2to3_doctests', 'force', + 'executable') + self.scripts = self.distribution.scripts + + def get_source_files(self): + return self.scripts + + def run(self): + if not self.scripts: + return + copied_files = self.copy_scripts() + if self.use_2to3 and copied_files: + self._run_2to3(copied_files, fixers=self.use_2to3_fixers) + + def copy_scripts(self): + """Copy each script listed in 'self.scripts'; if it's marked as a + Python script in the Unix way (first line matches 'first_line_re', + ie. starts with "\#!" and contains "python"), then adjust the first + line to refer to the current Python interpreter as we copy. + """ + self.mkpath(self.build_dir) + outfiles = [] + for script in self.scripts: + adjust = False + script = convert_path(script) + outfile = os.path.join(self.build_dir, os.path.basename(script)) + outfiles.append(outfile) + + if not self.force and not newer(script, outfile): + logger.debug("not copying %s (up-to-date)", script) + continue + + # Always open the file, but ignore failures in dry-run mode -- + # that way, we'll get accurate feedback if we can read the + # script. + try: + f = open(script, "r") + except IOError: + if not self.dry_run: + raise + f = None + else: + first_line = f.readline() + if not first_line: + logger.warning('%s: %s is an empty file (skipping)', + self.get_command_name(), script) + continue + + match = first_line_re.match(first_line) + if match: + adjust = True + post_interp = match.group(1) or '' + + if adjust: + logger.info("copying and adjusting %s -> %s", script, + self.build_dir) + if not self.dry_run: + outf = open(outfile, "w") + if not sysconfig.is_python_build(): + outf.write("#!%s%s\n" % + (self.executable, + post_interp)) + else: + outf.write("#!%s%s\n" % + (os.path.join( + sysconfig.get_config_var("BINDIR"), + "python%s%s" % (sysconfig.get_config_var("VERSION"), + sysconfig.get_config_var("EXE"))), + post_interp)) + outf.writelines(f.readlines()) + outf.close() + if f: + f.close() + else: + if f: + f.close() + self.copy_file(script, outfile) + + if os.name == 'posix': + for file in outfiles: + if self.dry_run: + logger.info("changing mode of %s", file) + else: + oldmode = os.stat(file).st_mode & 0o7777 + newmode = (oldmode | 0o555) & 0o7777 + if newmode != oldmode: + logger.info("changing mode of %s from %o to %o", + file, oldmode, newmode) + os.chmod(file, newmode) + return outfiles diff --git a/Lib/packaging/command/check.py b/Lib/packaging/command/check.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/check.py @@ -0,0 +1,88 @@ +"""Check PEP compliance of metadata.""" + +from packaging import logger +from packaging.command.cmd import Command +from packaging.errors import PackagingSetupError +from packaging.util import resolve_name + +class check(Command): + + description = "check PEP compliance of metadata" + + user_options = [('metadata', 'm', 'Verify metadata'), + ('all', 'a', + ('runs extended set of checks')), + ('strict', 's', + 'Will exit with an error if a check fails')] + + boolean_options = ['metadata', 'all', 'strict'] + + def initialize_options(self): + """Sets default values for options.""" + self.all = False + self.metadata = True + self.strict = False + self._warnings = [] + + def finalize_options(self): + pass + + def warn(self, msg, *args): + """Wrapper around logging that also remembers messages.""" + # XXX we could use a special handler for this, but would need to test + # if it works even if the logger has a too high level + self._warnings.append((msg, args)) + return logger.warning(self.get_command_name() + msg, *args) + + def run(self): + """Runs the command.""" + # perform the various tests + if self.metadata: + self.check_metadata() + if self.all: + self.check_restructuredtext() + self.check_hooks_resolvable() + + # let's raise an error in strict mode, if we have at least + # one warning + if self.strict and len(self._warnings) > 0: + msg = '\n'.join(msg % args for msg, args in self._warnings) + raise PackagingSetupError(msg) + + def check_metadata(self): + """Ensures that all required elements of metadata are supplied. + + name, version, URL, author + + Warns if any are missing. + """ + missing, warnings = self.distribution.metadata.check(strict=True) + if missing != []: + self.warn('missing required metadata: %s', ', '.join(missing)) + for warning in warnings: + self.warn(warning) + + def check_restructuredtext(self): + """Checks if the long string fields are reST-compliant.""" + missing, warnings = self.distribution.metadata.check(restructuredtext=True) + if self.distribution.metadata.docutils_support: + for warning in warnings: + line = warning[-1].get('line') + if line is None: + warning = warning[1] + else: + warning = '%s (line %s)' % (warning[1], line) + self.warn(warning) + elif self.strict: + raise PackagingSetupError('The docutils package is needed.') + + def check_hooks_resolvable(self): + for options in self.distribution.command_options.values(): + for hook_kind in ("pre_hook", "post_hook"): + if hook_kind not in options: + break + for hook_name in options[hook_kind][1].values(): + try: + resolve_name(hook_name) + except ImportError: + self.warn('name %r cannot be resolved', hook_name) diff --git a/Lib/packaging/command/clean.py b/Lib/packaging/command/clean.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/clean.py @@ -0,0 +1,76 @@ +"""Clean up temporary files created by the build command.""" + +# Contributed by Bastian Kleineidam + +import os +from shutil import rmtree +from packaging.command.cmd import Command +from packaging import logger + +class clean(Command): + + description = "clean up temporary files from 'build' command" + user_options = [ + ('build-base=', 'b', + "base build directory (default: 'build.build-base')"), + ('build-lib=', None, + "build directory for all modules (default: 'build.build-lib')"), + ('build-temp=', 't', + "temporary build directory (default: 'build.build-temp')"), + ('build-scripts=', None, + "build directory for scripts (default: 'build.build-scripts')"), + ('bdist-base=', None, + "temporary directory for built distributions"), + ('all', 'a', + "remove all build output, not just temporary by-products") + ] + + boolean_options = ['all'] + + def initialize_options(self): + self.build_base = None + self.build_lib = None + self.build_temp = None + self.build_scripts = None + self.bdist_base = None + self.all = None + + def finalize_options(self): + self.set_undefined_options('build', 'build_base', 'build_lib', + 'build_scripts', 'build_temp') + self.set_undefined_options('bdist', 'bdist_base') + + def run(self): + # remove the build/temp. directory (unless it's already + # gone) + if os.path.exists(self.build_temp): + if self.dry_run: + logger.info('removing %s', self.build_temp) + else: + rmtree(self.build_temp) + else: + logger.debug("'%s' does not exist -- can't clean it", + self.build_temp) + + if self.all: + # remove build directories + for directory in (self.build_lib, + self.bdist_base, + self.build_scripts): + if os.path.exists(directory): + if self.dry_run: + logger.info('removing %s', directory) + else: + rmtree(directory) + else: + logger.warning("'%s' does not exist -- can't clean it", + directory) + + # just for the heck of it, try to remove the base build directory: + # we might have emptied it right now, but if not we don't care + if not self.dry_run: + try: + os.rmdir(self.build_base) + logger.info("removing '%s'", self.build_base) + except OSError: + pass diff --git a/Lib/packaging/command/cmd.py b/Lib/packaging/command/cmd.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/cmd.py @@ -0,0 +1,440 @@ +"""Base class for commands.""" + +import os +import re +from shutil import copyfile, move, make_archive +from packaging import util +from packaging import logger +from packaging.errors import PackagingOptionError + + +class Command: + """Abstract base class for defining command classes, the "worker bees" + of the Packaging. A useful analogy for command classes is to think of + them as subroutines with local variables called "options". The options + are "declared" in 'initialize_options()' and "defined" (given their + final values, aka "finalized") in 'finalize_options()', both of which + must be defined by every command class. The distinction between the + two is necessary because option values might come from the outside + world (command line, config file, ...), and any options dependent on + other options must be computed *after* these outside influences have + been processed -- hence 'finalize_options()'. The "body" of the + subroutine, where it does all its work based on the values of its + options, is the 'run()' method, which must also be implemented by every + command class. + """ + + # 'sub_commands' formalizes the notion of a "family" of commands, + # eg. "install_dist" as the parent with sub-commands "install_lib", + # "install_headers", etc. The parent of a family of commands + # defines 'sub_commands' as a class attribute; it's a list of + # (command_name : string, predicate : unbound_method | string | None) + # tuples, where 'predicate' is a method of the parent command that + # determines whether the corresponding command is applicable in the + # current situation. (Eg. we "install_headers" is only applicable if + # we have any C header files to install.) If 'predicate' is None, + # that command is always applicable. + # + # 'sub_commands' is usually defined at the *end* of a class, because + # predicates can be unbound methods, so they must already have been + # defined. The canonical example is the "install_dist" command. + sub_commands = [] + + # Pre and post command hooks are run just before or just after the command + # itself. They are simple functions that receive the command instance. They + # are specified as callable objects or dotted strings (for lazy loading). + pre_hook = None + post_hook = None + + # -- Creation/initialization methods ------------------------------- + + def __init__(self, dist): + """Create and initialize a new Command object. Most importantly, + invokes the 'initialize_options()' method, which is the real + initializer and depends on the actual command being instantiated. + """ + # late import because of mutual dependence between these classes + from packaging.dist import Distribution + + if not isinstance(dist, Distribution): + raise TypeError("dist must be a Distribution instance") + if self.__class__ is Command: + raise RuntimeError("Command is an abstract class") + + self.distribution = dist + self.initialize_options() + + # Per-command versions of the global flags, so that the user can + # customize Packaging' behaviour command-by-command and let some + # commands fall back on the Distribution's behaviour. None means + # "not defined, check self.distribution's copy", while 0 or 1 mean + # false and true (duh). Note that this means figuring out the real + # value of each flag is a touch complicated -- hence "self._dry_run" + # will be handled by a property, below. + # XXX This needs to be fixed. [I changed it to a property--does that + # "fix" it?] + self._dry_run = None + + # Some commands define a 'self.force' option to ignore file + # timestamps, but methods defined *here* assume that + # 'self.force' exists for all commands. So define it here + # just to be safe. + self.force = None + + # The 'help' flag is just used for command line parsing, so + # none of that complicated bureaucracy is needed. + self.help = False + + # 'finalized' records whether or not 'finalize_options()' has been + # called. 'finalize_options()' itself should not pay attention to + # this flag: it is the business of 'ensure_finalized()', which + # always calls 'finalize_options()', to respect/update it. + self.finalized = False + + # XXX A more explicit way to customize dry_run would be better. + @property + def dry_run(self): + if self._dry_run is None: + return getattr(self.distribution, 'dry_run') + else: + return self._dry_run + + def ensure_finalized(self): + if not self.finalized: + self.finalize_options() + self.finalized = True + + # Subclasses must define: + # initialize_options() + # provide default values for all options; may be customized by + # setup script, by options from config file(s), or by command-line + # options + # finalize_options() + # decide on the final values for all options; this is called + # after all possible intervention from the outside world + # (command line, option file, etc.) has been processed + # run() + # run the command: do whatever it is we're here to do, + # controlled by the command's various option values + + def initialize_options(self): + """Set default values for all the options that this command + supports. Note that these defaults may be overridden by other + commands, by the setup script, by config files, or by the + command line. Thus, this is not the place to code dependencies + between options; generally, 'initialize_options()' implementations + are just a bunch of "self.foo = None" assignments. + + This method must be implemented by all command classes. + """ + raise RuntimeError( + "abstract method -- subclass %s must override" % self.__class__) + + def finalize_options(self): + """Set final values for all the options that this command supports. + This is always called as late as possible, ie. after any option + assignments from the command line or from other commands have been + done. Thus, this is the place to code option dependencies: if + 'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as + long as 'foo' still has the same value it was assigned in + 'initialize_options()'. + + This method must be implemented by all command classes. + """ + raise RuntimeError( + "abstract method -- subclass %s must override" % self.__class__) + + def dump_options(self, header=None, indent=""): + if header is None: + header = "command options for '%s':" % self.get_command_name() + logger.info(indent + header) + 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] + value = getattr(self, option) + logger.info(indent + "%s = %s", option, value) + + def run(self): + """A command's raison d'etre: carry out the action it exists to + perform, controlled by the options initialized in + 'initialize_options()', customized by other commands, the setup + script, the command line and config files, and finalized in + 'finalize_options()'. All terminal output and filesystem + interaction should be done by 'run()'. + + This method must be implemented by all command classes. + """ + raise RuntimeError( + "abstract method -- subclass %s must override" % self.__class__) + + # -- External interface -------------------------------------------- + # (called by outsiders) + + def get_source_files(self): + """Return the list of files that are used as inputs to this command, + i.e. the files used to generate the output files. The result is used + by the `sdist` command in determining the set of default files. + + Command classes should implement this method if they operate on files + from the source tree. + """ + return [] + + def get_outputs(self): + """Return the list of files that would be produced if this command + were actually run. Not affected by the "dry-run" flag or whether + any other commands have been run. + + Command classes should implement this method if they produce any + output files that get consumed by another command. e.g., `build_ext` + returns the list of built extension modules, but not any temporary + files used in the compilation process. + """ + return [] + + # -- Option validation methods ------------------------------------- + # (these are very handy in writing the 'finalize_options()' method) + # + # NB. the general philosophy here is to ensure that a particular option + # value meets certain type and value constraints. If not, we try to + # force it into conformance (eg. if we expect a list but have a string, + # split the string on comma and/or whitespace). If we can't force the + # option into conformance, raise PackagingOptionError. Thus, command + # classes need do nothing more than (eg.) + # self.ensure_string_list('foo') + # and they can be guaranteed that thereafter, self.foo will be + # a list of strings. + + def _ensure_stringlike(self, option, what, default=None): + val = getattr(self, option) + if val is None: + setattr(self, option, default) + return default + elif not isinstance(val, str): + raise PackagingOptionError("'%s' must be a %s (got `%s`)" % + (option, what, val)) + return val + + def ensure_string(self, option, default=None): + """Ensure that 'option' is a string; if not defined, set it to + 'default'. + """ + self._ensure_stringlike(option, "string", default) + + def ensure_string_list(self, option): + r"""Ensure that 'option' is a list of strings. If 'option' is + currently a string, we split it either on /,\s*/ or /\s+/, so + "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become + ["foo", "bar", "baz"]. + """ + val = getattr(self, option) + if val is None: + return + elif isinstance(val, str): + setattr(self, option, re.split(r',\s*|\s+', val)) + else: + if isinstance(val, list): + # checks if all elements are str + ok = True + for element in val: + if not isinstance(element, str): + ok = False + break + else: + ok = False + + if not ok: + raise PackagingOptionError( + "'%s' must be a list of strings (got %r)" % (option, val)) + + def _ensure_tested_string(self, option, tester, + what, error_fmt, default=None): + val = self._ensure_stringlike(option, what, default) + if val is not None and not tester(val): + raise PackagingOptionError( + ("error in '%s' option: " + error_fmt) % (option, val)) + + def ensure_filename(self, option): + """Ensure that 'option' is the name of an existing file.""" + self._ensure_tested_string(option, os.path.isfile, + "filename", + "'%s' does not exist or is not a file") + + def ensure_dirname(self, option): + self._ensure_tested_string(option, os.path.isdir, + "directory name", + "'%s' does not exist or is not a directory") + + # -- Convenience methods for commands ------------------------------ + + @classmethod + def get_command_name(cls): + if hasattr(cls, 'command_name'): + return cls.command_name + else: + return cls.__name__ + + def set_undefined_options(self, src_cmd, *options): + """Set values of undefined options from another command. + + Undefined options are options set to None, which is the convention + used to indicate that an option has not been changed between + 'initialize_options()' and 'finalize_options()'. This method is + usually called from 'finalize_options()' for options that depend on + some other command rather than another option of the same command, + typically subcommands. + + The 'src_cmd' argument is the other command from which option values + will be taken (a command object will be created for it if necessary); + the remaining positional arguments are strings that give the name of + the option to set. If the name is different on the source and target + command, you can pass a tuple with '(name_on_source, name_on_dest)' so + that 'self.name_on_dest' will be set from 'src_cmd.name_on_source'. + """ + src_cmd_obj = self.distribution.get_command_obj(src_cmd) + src_cmd_obj.ensure_finalized() + for obj in options: + if isinstance(obj, tuple): + src_option, dst_option = obj + else: + src_option, dst_option = obj, obj + if getattr(self, dst_option) is None: + setattr(self, dst_option, + getattr(src_cmd_obj, src_option)) + + def get_finalized_command(self, command, create=True): + """Wrapper around Distribution's 'get_command_obj()' method: find + (create if necessary and 'create' is true) the command object for + 'command', call its 'ensure_finalized()' method, and return the + finalized command object. + """ + cmd_obj = self.distribution.get_command_obj(command, create) + cmd_obj.ensure_finalized() + return cmd_obj + + def get_reinitialized_command(self, command, reinit_subcommands=False): + return self.distribution.get_reinitialized_command( + command, reinit_subcommands) + + def run_command(self, command): + """Run some other command: uses the 'run_command()' method of + Distribution, which creates and finalizes the command object if + necessary and then invokes its 'run()' method. + """ + self.distribution.run_command(command) + + def get_sub_commands(self): + """Determine the sub-commands that are relevant in the current + distribution (ie., that need to be run). This is based on the + 'sub_commands' class attribute: each tuple in that list may include + a method that we call to determine if the subcommand needs to be + run for the current distribution. Return a list of command names. + """ + commands = [] + for sub_command in self.sub_commands: + if len(sub_command) == 2: + cmd_name, method = sub_command + if method is None or method(self): + commands.append(cmd_name) + else: + commands.append(sub_command) + return commands + + # -- External world manipulation ----------------------------------- + + def execute(self, func, args, msg=None, level=1): + util.execute(func, args, msg, dry_run=self.dry_run) + + def mkpath(self, name, mode=0o777, dry_run=None, verbose=0): + if dry_run is None: + dry_run = self.dry_run + name = os.path.normpath(name) + if os.path.isdir(name) or name == '': + return + if dry_run: + head = '' + for part in name.split(os.sep): + logger.info("created directory %s%s", head, part) + head += part + os.sep + return + os.makedirs(name, mode) + + def copy_file(self, infile, outfile, + preserve_mode=True, preserve_times=True, link=None, level=1): + """Copy a file respecting verbose, dry-run and force flags. (The + former two default to whatever is in the Distribution object, and + the latter defaults to false for commands that don't define it.)""" + if self.dry_run: + # XXX add a comment + return + if os.path.isdir(outfile): + outfile = os.path.join(outfile, os.path.split(infile)[-1]) + copyfile(infile, outfile) + return outfile, None # XXX + + def copy_tree(self, infile, outfile, preserve_mode=True, + preserve_times=True, preserve_symlinks=False, level=1): + """Copy an entire directory tree respecting verbose, dry-run, + and force flags. + """ + if self.dry_run: + return # see if we want to display something + + + return util.copy_tree(infile, outfile, preserve_mode, preserve_times, + preserve_symlinks, not self.force, dry_run=self.dry_run) + + def move_file(self, src, dst, level=1): + """Move a file respecting the dry-run flag.""" + if self.dry_run: + return # XXX log ? + return move(src, dst) + + def spawn(self, cmd, search_path=True, level=1): + """Spawn an external command respecting dry-run flag.""" + from packaging.util import spawn + spawn(cmd, search_path, dry_run=self.dry_run) + + def make_archive(self, base_name, format, root_dir=None, base_dir=None, + owner=None, group=None): + return make_archive(base_name, format, root_dir, + base_dir, dry_run=self.dry_run, + owner=owner, group=group) + + def make_file(self, infiles, outfile, func, args, + exec_msg=None, skip_msg=None, level=1): + """Special case of 'execute()' for operations that process one or + more input files and generate one output file. Works just like + 'execute()', except the operation is skipped and a different + message printed if 'outfile' already exists and is newer than all + files listed in 'infiles'. If the command defined 'self.force', + and it is true, then the command is unconditionally run -- does no + timestamp checks. + """ + if skip_msg is None: + skip_msg = "skipping %s (inputs unchanged)" % outfile + + # Allow 'infiles' to be a single string + if isinstance(infiles, str): + infiles = (infiles,) + elif not isinstance(infiles, (list, tuple)): + raise TypeError( + "'infiles' must be a string, or a list or tuple of strings") + + if exec_msg is None: + exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles)) + + # If 'outfile' must be regenerated (either because it doesn't + # exist, is out-of-date, or the 'force' flag is true) then + # perform the action that presumably regenerates it + if self.force or util.newer_group(infiles, outfile): + self.execute(func, args, exec_msg, level) + + # Otherwise, print the "skip" message + else: + logger.debug(skip_msg) diff --git a/Lib/packaging/command/command_template b/Lib/packaging/command/command_template new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/command_template @@ -0,0 +1,35 @@ +"""Do X and Y.""" + +from packaging import logger +from packaging.command.cmd import Command + + +class x(Command): + + # Brief (40-50 characters) description of the command + description = "" + + # List of option tuples: long name, short name (None if no short + # name), and help string. + user_options = [ + ('', '', # long option, short option (one letter) or None + ""), # help text + ] + + def initialize_options(self): + self. = None + self. = None + self. = None + + def finalize_options(self): + if self.x is None: + self.x = ... + + def run(self): + ... + logger.info(...) + + if not self.dry_run: + ... + + self.execute(..., dry_run=self.dry_run) diff --git a/Lib/packaging/command/config.py b/Lib/packaging/command/config.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/config.py @@ -0,0 +1,351 @@ +"""Prepare the build. + +This module provides config, a (mostly) empty command class +that exists mainly to be sub-classed by specific module distributions and +applications. The idea is that while every "config" command is different, +at least they're all named the same, and users always see "config" in the +list of standard commands. Also, this is a good place to put common +configure-like tasks: "try to compile this C code", or "figure out where +this header file lives". +""" + +import os +import re + +from packaging.command.cmd import Command +from packaging.errors import PackagingExecError +from packaging.compiler import customize_compiler +from packaging import logger + +LANG_EXT = {'c': '.c', 'c++': '.cxx'} + +class config(Command): + + description = "prepare the build" + + user_options = [ + ('compiler=', None, + "specify the compiler type"), + ('cc=', None, + "specify the compiler executable"), + ('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"), + ('libraries=', 'l', + "external C libraries to link with"), + ('library-dirs=', 'L', + "directories to search for external C libraries"), + + ('noisy', None, + "show every action (compile, link, run, ...) taken"), + ('dump-source', None, + "dump generated source files before attempting to compile them"), + ] + + + # The three standard command methods: since the "config" command + # does nothing by default, these are empty. + + def initialize_options(self): + self.compiler = None + self.cc = None + self.include_dirs = None + self.libraries = None + self.library_dirs = None + + # maximal output for now + self.noisy = True + self.dump_source = True + + # list of temporary files generated along-the-way that we have + # to clean at some point + self.temp_files = [] + + def finalize_options(self): + if self.include_dirs is None: + self.include_dirs = self.distribution.include_dirs or [] + elif isinstance(self.include_dirs, str): + self.include_dirs = self.include_dirs.split(os.pathsep) + + if self.libraries is None: + self.libraries = [] + elif isinstance(self.libraries, str): + self.libraries = [self.libraries] + + if self.library_dirs is None: + self.library_dirs = [] + elif isinstance(self.library_dirs, str): + self.library_dirs = self.library_dirs.split(os.pathsep) + + def run(self): + pass + + + # Utility methods for actual "config" commands. The interfaces are + # loosely based on Autoconf macros of similar names. Sub-classes + # may use these freely. + + def _check_compiler(self): + """Check that 'self.compiler' really is a CCompiler object; + if not, make it one. + """ + # We do this late, and only on-demand, because this is an expensive + # import. + from packaging.compiler.ccompiler import CCompiler + from packaging.compiler import new_compiler + if not isinstance(self.compiler, CCompiler): + self.compiler = new_compiler(compiler=self.compiler, + dry_run=self.dry_run, force=True) + customize_compiler(self.compiler) + if self.include_dirs: + self.compiler.set_include_dirs(self.include_dirs) + if self.libraries: + self.compiler.set_libraries(self.libraries) + if self.library_dirs: + self.compiler.set_library_dirs(self.library_dirs) + + + def _gen_temp_sourcefile(self, body, headers, lang): + filename = "_configtest" + LANG_EXT[lang] + file = open(filename, "w") + if headers: + for header in headers: + file.write("#include <%s>\n" % header) + file.write("\n") + file.write(body) + if body[-1] != "\n": + file.write("\n") + file.close() + return filename + + def _preprocess(self, body, headers, include_dirs, lang): + src = self._gen_temp_sourcefile(body, headers, lang) + out = "_configtest.i" + self.temp_files.extend((src, out)) + self.compiler.preprocess(src, out, include_dirs=include_dirs) + return src, out + + def _compile(self, body, headers, include_dirs, lang): + src = self._gen_temp_sourcefile(body, headers, lang) + if self.dump_source: + dump_file(src, "compiling '%s':" % src) + obj = self.compiler.object_filenames([src])[0] + self.temp_files.extend((src, obj)) + self.compiler.compile([src], include_dirs=include_dirs) + return src, obj + + def _link(self, body, headers, include_dirs, libraries, library_dirs, + lang): + src, obj = self._compile(body, headers, include_dirs, lang) + prog = os.path.splitext(os.path.basename(src))[0] + self.compiler.link_executable([obj], prog, + libraries=libraries, + library_dirs=library_dirs, + target_lang=lang) + + if self.compiler.exe_extension is not None: + prog = prog + self.compiler.exe_extension + self.temp_files.append(prog) + + return src, obj, prog + + def _clean(self, *filenames): + if not filenames: + filenames = self.temp_files + self.temp_files = [] + logger.info("removing: %s", ' '.join(filenames)) + for filename in filenames: + try: + os.remove(filename) + except OSError: + pass + + + # XXX these ignore the dry-run flag: what to do, what to do? even if + # you want a dry-run build, you still need some sort of configuration + # info. My inclination is to make it up to the real config command to + # consult 'dry_run', and assume a default (minimal) configuration if + # true. The problem with trying to do it here is that you'd have to + # return either true or false from all the 'try' methods, neither of + # which is correct. + + # XXX need access to the header search path and maybe default macros. + + def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"): + """Construct a source file from 'body' (a string containing lines + of C/C++ code) and 'headers' (a list of header files to include) + and run it through the preprocessor. Return true if the + preprocessor succeeded, false if there were any errors. + ('body' probably isn't of much use, but what the heck.) + """ + from packaging.compiler.ccompiler import CompileError + self._check_compiler() + ok = True + try: + self._preprocess(body, headers, include_dirs, lang) + except CompileError: + ok = False + + self._clean() + return ok + + def search_cpp(self, pattern, body=None, headers=None, include_dirs=None, + lang="c"): + """Construct a source file (just like 'try_cpp()'), run it through + the preprocessor, and return true if any line of the output matches + 'pattern'. 'pattern' should either be a compiled regex object or a + string containing a regex. If both 'body' and 'headers' are None, + preprocesses an empty file -- which can be useful to determine the + symbols the preprocessor and compiler set by default. + """ + self._check_compiler() + src, out = self._preprocess(body, headers, include_dirs, lang) + + if isinstance(pattern, str): + pattern = re.compile(pattern) + + file = open(out) + match = False + while True: + line = file.readline() + if line == '': + break + if pattern.search(line): + match = True + break + + file.close() + self._clean() + return match + + def try_compile(self, body, headers=None, include_dirs=None, lang="c"): + """Try to compile a source file built from 'body' and 'headers'. + Return true on success, false otherwise. + """ + from packaging.compiler.ccompiler import CompileError + self._check_compiler() + try: + self._compile(body, headers, include_dirs, lang) + ok = True + except CompileError: + ok = False + + logger.info(ok and "success!" or "failure.") + self._clean() + return ok + + def try_link(self, body, headers=None, include_dirs=None, libraries=None, + library_dirs=None, lang="c"): + """Try to compile and link a source file, built from 'body' and + 'headers', to executable form. Return true on success, false + otherwise. + """ + from packaging.compiler.ccompiler import CompileError, LinkError + self._check_compiler() + try: + self._link(body, headers, include_dirs, + libraries, library_dirs, lang) + ok = True + except (CompileError, LinkError): + ok = False + + logger.info(ok and "success!" or "failure.") + self._clean() + return ok + + def try_run(self, body, headers=None, include_dirs=None, libraries=None, + library_dirs=None, lang="c"): + """Try to compile, link to an executable, and run a program + built from 'body' and 'headers'. Return true on success, false + otherwise. + """ + from packaging.compiler.ccompiler import CompileError, LinkError + self._check_compiler() + try: + src, obj, exe = self._link(body, headers, include_dirs, + libraries, library_dirs, lang) + self.spawn([exe]) + ok = True + except (CompileError, LinkError, PackagingExecError): + ok = False + + logger.info(ok and "success!" or "failure.") + self._clean() + return ok + + + # -- High-level methods -------------------------------------------- + # (these are the ones that are actually likely to be useful + # when implementing a real-world config command!) + + def check_func(self, func, headers=None, include_dirs=None, + libraries=None, library_dirs=None, decl=False, call=False): + + """Determine if function 'func' is available by constructing a + source file that refers to 'func', and compiles and links it. + If everything succeeds, returns true; otherwise returns false. + + The constructed source file starts out by including the header + files listed in 'headers'. If 'decl' is true, it then declares + 'func' (as "int func()"); you probably shouldn't supply 'headers' + and set 'decl' true in the same call, or you might get errors about + a conflicting declarations for 'func'. Finally, the constructed + 'main()' function either references 'func' or (if 'call' is true) + calls it. 'libraries' and 'library_dirs' are used when + linking. + """ + + self._check_compiler() + body = [] + if decl: + body.append("int %s ();" % func) + body.append("int main () {") + if call: + body.append(" %s();" % func) + else: + body.append(" %s;" % func) + body.append("}") + body = "\n".join(body) + "\n" + + return self.try_link(body, headers, include_dirs, + libraries, library_dirs) + + def check_lib(self, library, library_dirs=None, headers=None, + include_dirs=None, other_libraries=[]): + """Determine if 'library' is available to be linked against, + without actually checking that any particular symbols are provided + by it. 'headers' will be used in constructing the source file to + be compiled, but the only effect of this is to check if all the + header files listed are available. Any libraries listed in + 'other_libraries' will be included in the link, in case 'library' + has symbols that depend on other libraries. + """ + self._check_compiler() + return self.try_link("int main (void) { }", + headers, include_dirs, + [library]+other_libraries, library_dirs) + + def check_header(self, header, include_dirs=None, library_dirs=None, + lang="c"): + """Determine if the system header file named by 'header_file' + exists and can be found by the preprocessor; return true if so, + false otherwise. + """ + return self.try_cpp(body="/* No body */", headers=[header], + include_dirs=include_dirs) + + +def dump_file(filename, head=None): + """Dumps a file content into log.info. + + If head is not None, will be dumped before the file content. + """ + if head is None: + logger.info(filename) + else: + logger.info(head) + with open(filename) as file: + logger.info(file.read()) diff --git a/Lib/packaging/command/install_data.py b/Lib/packaging/command/install_data.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/install_data.py @@ -0,0 +1,79 @@ +"""Install platform-independent data files.""" + +# Contributed by Bastian Kleineidam + +import os +from shutil import Error +from sysconfig import get_paths, format_value +from packaging import logger +from packaging.util import convert_path +from packaging.command.cmd import Command + + +class install_data(Command): + + description = "install platform-independent data files" + + user_options = [ + ('install-dir=', 'd', + "base directory for installing data files " + "(default: installation base dir)"), + ('root=', None, + "install everything relative to this alternate root directory"), + ('force', 'f', "force installation (overwrite existing files)"), + ] + + boolean_options = ['force'] + + def initialize_options(self): + self.install_dir = None + self.outfiles = [] + self.data_files_out = [] + self.root = None + self.force = False + self.data_files = self.distribution.data_files + self.warn_dir = True + + def finalize_options(self): + self.set_undefined_options('install_dist', + ('install_data', 'install_dir'), + 'root', 'force') + + def run(self): + self.mkpath(self.install_dir) + for _file in self.data_files.items(): + destination = convert_path(self.expand_categories(_file[1])) + dir_dest = os.path.abspath(os.path.dirname(destination)) + + self.mkpath(dir_dest) + try: + out = self.copy_file(_file[0], dir_dest)[0] + except Error as e: + logger.warning('%s: %s', self.get_command_name(), e) + out = destination + + self.outfiles.append(out) + self.data_files_out.append((_file[0], destination)) + + def expand_categories(self, path_with_categories): + local_vars = get_paths() + local_vars['distribution.name'] = self.distribution.metadata['Name'] + expanded_path = format_value(path_with_categories, local_vars) + expanded_path = format_value(expanded_path, local_vars) + if '{' in expanded_path and '}' in expanded_path: + logger.warning( + '%s: unable to expand %s, some categories may be missing', + self.get_command_name(), path_with_categories) + return expanded_path + + def get_source_files(self): + return list(self.data_files) + + def get_inputs(self): + return list(self.data_files) + + def get_outputs(self): + return self.outfiles + + def get_resources_out(self): + return self.data_files_out diff --git a/Lib/packaging/command/install_dist.py b/Lib/packaging/command/install_dist.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/install_dist.py @@ -0,0 +1,625 @@ +"""Main install command, which calls the other install_* commands.""" + +import sys +import os + +import sysconfig +from sysconfig import get_config_vars, get_paths, get_path, get_config_var + +from packaging import logger +from packaging.command.cmd import Command +from packaging.errors import PackagingPlatformError +from packaging.util import write_file +from packaging.util import convert_path, change_root, get_platform +from packaging.errors import PackagingOptionError + + +HAS_USER_SITE = True + + +class install_dist(Command): + + description = "install everything from build directory" + + user_options = [ + # Select installation scheme and set base director(y|ies) + ('prefix=', None, + "installation prefix"), + ('exec-prefix=', None, + "(Unix only) prefix for platform-specific files"), + ('home=', None, + "(Unix only) home directory to install under"), + + # Or just set the base director(y|ies) + ('install-base=', None, + "base installation directory (instead of --prefix or --home)"), + ('install-platbase=', None, + "base installation directory for platform-specific files " + + "(instead of --exec-prefix or --home)"), + ('root=', None, + "install everything relative to this alternate root directory"), + + # Or explicitly set the installation scheme + ('install-purelib=', None, + "installation directory for pure Python module distributions"), + ('install-platlib=', None, + "installation directory for non-pure module distributions"), + ('install-lib=', None, + "installation directory for all module distributions " + + "(overrides --install-purelib and --install-platlib)"), + + ('install-headers=', None, + "installation directory for C/C++ headers"), + ('install-scripts=', None, + "installation directory for Python scripts"), + ('install-data=', None, + "installation directory for data files"), + + # Byte-compilation options -- see install_lib.py for details, as + # these are duplicated from there (but only install_lib does + # anything with them). + ('compile', 'c', "compile .py to .pyc [default]"), + ('no-compile', None, "don't compile .py files"), + ('optimize=', 'O', + 'also compile with optimization: -O1 for "python -O", ' + '-O2 for "python -OO", and -O0 to disable [default: -O0]'), + + # Miscellaneous control options + ('force', 'f', + "force installation (overwrite any existing files)"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + + # Where to install documentation (eventually!) + #('doc-format=', None, "format of documentation to generate"), + #('install-man=', None, "directory for Unix man pages"), + #('install-html=', None, "directory for HTML documentation"), + #('install-info=', None, "directory for GNU info files"), + + # XXX use a name that makes clear this is the old format + ('record=', None, + "filename in which to record a list of installed files " + "(not PEP 376-compliant)"), + ('resources=', None, + "data files mapping"), + + # .dist-info related arguments, read by install_dist_info + ('no-distinfo', None, + "do not create a .dist-info directory"), + ('installer=', None, + "the name of the installer"), + ('requested', None, + "generate a REQUESTED file (i.e."), + ('no-requested', None, + "do not generate a REQUESTED file"), + ('no-record', None, + "do not generate a RECORD file"), + ] + + boolean_options = ['compile', 'force', 'skip-build', 'no-distinfo', + 'requested', 'no-record'] + + if HAS_USER_SITE: + user_options.append( + ('user', None, + "install in user site-packages directory [%s]" % + get_path('purelib', '%s_user' % os.name))) + + boolean_options.append('user') + + negative_opt = {'no-compile': 'compile', 'no-requested': 'requested'} + + def initialize_options(self): + # High-level options: these select both an installation base + # and scheme. + self.prefix = None + self.exec_prefix = None + self.home = None + if HAS_USER_SITE: + self.user = False + + # These select only the installation base; it's up to the user to + # specify the installation scheme (currently, that means supplying + # the --install-{platlib,purelib,scripts,data} options). + self.install_base = None + self.install_platbase = None + self.root = None + + # These options are the actual installation directories; if not + # supplied by the user, they are filled in using the installation + # scheme implied by prefix/exec-prefix/home and the contents of + # that installation scheme. + self.install_purelib = None # for pure module distributions + self.install_platlib = None # non-pure (dists w/ extensions) + self.install_headers = None # for C/C++ headers + self.install_lib = None # set to either purelib or platlib + self.install_scripts = None + self.install_data = None + if HAS_USER_SITE: + self.install_userbase = get_config_var('userbase') + self.install_usersite = get_path('purelib', '%s_user' % os.name) + + self.compile = None + self.optimize = None + + # These two are for putting non-packagized distributions into their + # own directory and creating a .pth file if it makes sense. + # 'extra_path' comes from the setup file; 'install_path_file' can + # be turned off if it makes no sense to install a .pth file. (But + # better to install it uselessly than to guess wrong and not + # install it when it's necessary and would be used!) Currently, + # 'install_path_file' is always true unless some outsider meddles + # with it. + self.extra_path = None + self.install_path_file = True + + # 'force' forces installation, even if target files are not + # out-of-date. 'skip_build' skips running the "build" command, + # handy if you know it's not necessary. 'warn_dir' (which is *not* + # a user option, it's just there so the bdist_* commands can turn + # it off) determines whether we warn about installing to a + # directory not in sys.path. + self.force = False + self.skip_build = False + self.warn_dir = True + + # These are only here as a conduit from the 'build' command to the + # 'install_*' commands that do the real work. ('build_base' isn't + # actually used anywhere, but it might be useful in future.) They + # are not user options, because if the user told the install + # command where the build directory is, that wouldn't affect the + # build command. + self.build_base = None + self.build_lib = None + + # Not defined yet because we don't know anything about + # documentation yet. + #self.install_man = None + #self.install_html = None + #self.install_info = None + + self.record = None + self.resources = None + + # .dist-info related options + self.no_distinfo = None + self.installer = None + self.requested = None + self.no_record = None + self.no_resources = None + + # -- Option finalizing methods ------------------------------------- + # (This is rather more involved than for most commands, + # because this is where the policy for installing third- + # party Python modules on various platforms given a wide + # array of user input is decided. Yes, it's quite complex!) + + def finalize_options(self): + # This method (and its pliant slaves, like 'finalize_unix()', + # 'finalize_other()', and 'select_scheme()') is where the default + # installation directories for modules, extension modules, and + # anything else we care to install from a Python module + # distribution. Thus, this code makes a pretty important policy + # statement about how third-party stuff is added to a Python + # installation! Note that the actual work of installation is done + # by the relatively simple 'install_*' commands; they just take + # their orders from the installation directory options determined + # here. + + # Check for errors/inconsistencies in the options; first, stuff + # that's wrong on any platform. + + if ((self.prefix or self.exec_prefix or self.home) and + (self.install_base or self.install_platbase)): + raise PackagingOptionError( + "must supply either prefix/exec-prefix/home or " + "install-base/install-platbase -- not both") + + if self.home and (self.prefix or self.exec_prefix): + raise PackagingOptionError( + "must supply either home or prefix/exec-prefix -- not both") + + if HAS_USER_SITE and self.user and ( + self.prefix or self.exec_prefix or self.home or + self.install_base or self.install_platbase): + raise PackagingOptionError( + "can't combine user with prefix/exec_prefix/home or " + "install_base/install_platbase") + + # Next, stuff that's wrong (or dubious) only on certain platforms. + if os.name != "posix": + if self.exec_prefix: + logger.warning( + '%s: exec-prefix option ignored on this platform', + self.get_command_name()) + self.exec_prefix = None + + # Now the interesting logic -- so interesting that we farm it out + # to other methods. The goal of these methods is to set the final + # values for the install_{lib,scripts,data,...} options, using as + # input a heady brew of prefix, exec_prefix, home, install_base, + # install_platbase, user-supplied versions of + # install_{purelib,platlib,lib,scripts,data,...}, and the + # INSTALL_SCHEME dictionary above. Phew! + + self.dump_dirs("pre-finalize_{unix,other}") + + if os.name == 'posix': + self.finalize_unix() + else: + self.finalize_other() + + self.dump_dirs("post-finalize_{unix,other}()") + + # Expand configuration variables, tilde, etc. in self.install_base + # and self.install_platbase -- that way, we can use $base or + # $platbase in the other installation directories and not worry + # about needing recursive variable expansion (shudder). + + py_version = sys.version.split()[0] + prefix, exec_prefix, srcdir, projectbase = get_config_vars( + 'prefix', 'exec_prefix', 'srcdir', 'projectbase') + + metadata = self.distribution.metadata + self.config_vars = { + 'dist_name': metadata['Name'], + 'dist_version': metadata['Version'], + 'dist_fullname': metadata.get_fullname(), + 'py_version': py_version, + 'py_version_short': py_version[:3], + 'py_version_nodot': py_version[:3:2], + 'sys_prefix': prefix, + 'prefix': prefix, + 'sys_exec_prefix': exec_prefix, + 'exec_prefix': exec_prefix, + 'srcdir': srcdir, + 'projectbase': projectbase, + } + + if HAS_USER_SITE: + self.config_vars['userbase'] = self.install_userbase + self.config_vars['usersite'] = self.install_usersite + + self.expand_basedirs() + + self.dump_dirs("post-expand_basedirs()") + + # Now define config vars for the base directories so we can expand + # everything else. + self.config_vars['base'] = self.install_base + self.config_vars['platbase'] = self.install_platbase + + # Expand "~" and configuration variables in the installation + # directories. + self.expand_dirs() + + self.dump_dirs("post-expand_dirs()") + + # Create directories in the home dir: + if HAS_USER_SITE and self.user: + self.create_home_path() + + # Pick the actual directory to install all modules to: either + # install_purelib or install_platlib, depending on whether this + # module distribution is pure or not. Of course, if the user + # already specified install_lib, use their selection. + if self.install_lib is None: + if self.distribution.ext_modules: # has extensions: non-pure + self.install_lib = self.install_platlib + else: + self.install_lib = self.install_purelib + + # Convert directories from Unix /-separated syntax to the local + # convention. + self.convert_paths('lib', 'purelib', 'platlib', + 'scripts', 'data', 'headers') + if HAS_USER_SITE: + self.convert_paths('userbase', 'usersite') + + # Well, we're not actually fully completely finalized yet: we still + # have to deal with 'extra_path', which is the hack for allowing + # non-packagized module distributions (hello, Numerical Python!) to + # get their own directories. + self.handle_extra_path() + self.install_libbase = self.install_lib # needed for .pth file + self.install_lib = os.path.join(self.install_lib, self.extra_dirs) + + # If a new root directory was supplied, make all the installation + # dirs relative to it. + if self.root is not None: + self.change_roots('libbase', 'lib', 'purelib', 'platlib', + 'scripts', 'data', 'headers') + + self.dump_dirs("after prepending root") + + # Find out the build directories, ie. where to install from. + self.set_undefined_options('build', 'build_base', 'build_lib') + + # Punt on doc directories for now -- after all, we're punting on + # documentation completely! + + if self.no_distinfo is None: + self.no_distinfo = False + + def finalize_unix(self): + """Finalize options for posix platforms.""" + if self.install_base is not None or self.install_platbase is not None: + if ((self.install_lib is None and + self.install_purelib is None and + self.install_platlib is None) or + self.install_headers is None or + self.install_scripts is None or + self.install_data is None): + raise PackagingOptionError( + "install-base or install-platbase supplied, but " + "installation scheme is incomplete") + return + + if HAS_USER_SITE and self.user: + if self.install_userbase is None: + raise PackagingPlatformError( + "user base directory is not specified") + self.install_base = self.install_platbase = self.install_userbase + self.select_scheme("posix_user") + elif self.home is not None: + self.install_base = self.install_platbase = self.home + self.select_scheme("posix_home") + else: + if self.prefix is None: + if self.exec_prefix is not None: + raise PackagingOptionError( + "must not supply exec-prefix without prefix") + + self.prefix = os.path.normpath(sys.prefix) + self.exec_prefix = os.path.normpath(sys.exec_prefix) + + else: + if self.exec_prefix is None: + self.exec_prefix = self.prefix + + self.install_base = self.prefix + self.install_platbase = self.exec_prefix + self.select_scheme("posix_prefix") + + def finalize_other(self): + """Finalize options for non-posix platforms""" + if HAS_USER_SITE and self.user: + if self.install_userbase is None: + raise PackagingPlatformError( + "user base directory is not specified") + self.install_base = self.install_platbase = self.install_userbase + self.select_scheme(os.name + "_user") + elif self.home is not None: + self.install_base = self.install_platbase = self.home + self.select_scheme("posix_home") + else: + if self.prefix is None: + self.prefix = os.path.normpath(sys.prefix) + + self.install_base = self.install_platbase = self.prefix + try: + self.select_scheme(os.name) + except KeyError: + raise PackagingPlatformError( + "no support for installation on '%s'" % os.name) + + def dump_dirs(self, msg): + """Dump the list of user options.""" + logger.debug(msg + ":") + for opt in self.user_options: + opt_name = opt[0] + if opt_name[-1] == "=": + opt_name = opt_name[0:-1] + if opt_name in self.negative_opt: + opt_name = self.negative_opt[opt_name] + opt_name = opt_name.replace('-', '_') + val = not getattr(self, opt_name) + else: + opt_name = opt_name.replace('-', '_') + val = getattr(self, opt_name) + logger.debug(" %s: %s", opt_name, val) + + def select_scheme(self, name): + """Set the install directories by applying the install schemes.""" + # it's the caller's problem if they supply a bad name! + scheme = get_paths(name, expand=False) + for key, value in scheme.items(): + if key == 'platinclude': + key = 'headers' + value = os.path.join(value, self.distribution.metadata['Name']) + attrname = 'install_' + key + if hasattr(self, attrname): + if getattr(self, attrname) is None: + setattr(self, attrname, value) + + def _expand_attrs(self, attrs): + for attr in attrs: + val = getattr(self, attr) + if val is not None: + if os.name == 'posix' or os.name == 'nt': + val = os.path.expanduser(val) + # see if we want to push this work in sysconfig XXX + val = sysconfig._subst_vars(val, self.config_vars) + setattr(self, attr, val) + + def expand_basedirs(self): + """Call `os.path.expanduser` on install_{base,platbase} and root.""" + self._expand_attrs(['install_base', 'install_platbase', 'root']) + + def expand_dirs(self): + """Call `os.path.expanduser` on install dirs.""" + self._expand_attrs(['install_purelib', 'install_platlib', + 'install_lib', 'install_headers', + 'install_scripts', 'install_data']) + + def convert_paths(self, *names): + """Call `convert_path` over `names`.""" + for name in names: + attr = "install_" + name + setattr(self, attr, convert_path(getattr(self, attr))) + + def handle_extra_path(self): + """Set `path_file` and `extra_dirs` using `extra_path`.""" + if self.extra_path is None: + self.extra_path = self.distribution.extra_path + + if self.extra_path is not None: + if isinstance(self.extra_path, str): + self.extra_path = self.extra_path.split(',') + + if len(self.extra_path) == 1: + path_file = extra_dirs = self.extra_path[0] + elif len(self.extra_path) == 2: + path_file, extra_dirs = self.extra_path + else: + raise PackagingOptionError( + "'extra_path' option must be a list, tuple, or " + "comma-separated string with 1 or 2 elements") + + # convert to local form in case Unix notation used (as it + # should be in setup scripts) + extra_dirs = convert_path(extra_dirs) + else: + path_file = None + extra_dirs = '' + + # XXX should we warn if path_file and not extra_dirs? (in which + # case the path file would be harmless but pointless) + self.path_file = path_file + self.extra_dirs = extra_dirs + + def change_roots(self, *names): + """Change the install direcories pointed by name using root.""" + for name in names: + attr = "install_" + name + setattr(self, attr, change_root(self.root, getattr(self, attr))) + + def create_home_path(self): + """Create directories under ~.""" + if HAS_USER_SITE and not self.user: + return + home = convert_path(os.path.expanduser("~")) + for name, path in self.config_vars.items(): + if path.startswith(home) and not os.path.isdir(path): + os.makedirs(path, 0o700) + + # -- Command execution methods ------------------------------------- + + def run(self): + """Runs the command.""" + # Obviously have to build before we can install + if not self.skip_build: + self.run_command('build') + # If we built for any other platform, we can't install. + build_plat = self.distribution.get_command_obj('build').plat_name + # check warn_dir - it is a clue that the 'install_dist' is happening + # internally, and not to sys.path, so we don't check the platform + # matches what we are running. + if self.warn_dir and build_plat != get_platform(): + raise PackagingPlatformError("Can't install when " + "cross-compiling") + + # Run all sub-commands (at least those that need to be run) + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + if self.path_file: + self.create_path_file() + + # write list of installed files, if requested. + if self.record: + outputs = self.get_outputs() + if self.root: # strip any package prefix + root_len = len(self.root) + for counter in range(len(outputs)): + outputs[counter] = outputs[counter][root_len:] + self.execute(write_file, + (self.record, outputs), + "writing list of installed files to '%s'" % + self.record) + + normpath, normcase = os.path.normpath, os.path.normcase + sys_path = [normcase(normpath(p)) for p in sys.path] + install_lib = normcase(normpath(self.install_lib)) + if (self.warn_dir and + not (self.path_file and self.install_path_file) and + install_lib not in sys_path): + logger.debug(("modules installed to '%s', which is not in " + "Python's module search path (sys.path) -- " + "you'll have to change the search path yourself"), + self.install_lib) + + def create_path_file(self): + """Creates the .pth file""" + filename = os.path.join(self.install_libbase, + self.path_file + ".pth") + if self.install_path_file: + self.execute(write_file, + (filename, [self.extra_dirs]), + "creating %s" % filename) + else: + logger.warning('%s: path file %r not created', + self.get_command_name(), filename) + + # -- Reporting methods --------------------------------------------- + + def get_outputs(self): + """Assembles the outputs of all the sub-commands.""" + outputs = [] + for cmd_name in self.get_sub_commands(): + cmd = self.get_finalized_command(cmd_name) + # Add the contents of cmd.get_outputs(), ensuring + # that outputs doesn't contain duplicate entries + for filename in cmd.get_outputs(): + if filename not in outputs: + outputs.append(filename) + + if self.path_file and self.install_path_file: + outputs.append(os.path.join(self.install_libbase, + self.path_file + ".pth")) + + return outputs + + def get_inputs(self): + """Returns the inputs of all the sub-commands""" + # XXX gee, this looks familiar ;-( + inputs = [] + for cmd_name in self.get_sub_commands(): + cmd = self.get_finalized_command(cmd_name) + inputs.extend(cmd.get_inputs()) + + return inputs + + # -- Predicates for sub-command list ------------------------------- + + def has_lib(self): + """Returns true if the current distribution has any Python + modules to install.""" + return (self.distribution.has_pure_modules() or + self.distribution.has_ext_modules()) + + def has_headers(self): + """Returns true if the current distribution has any headers to + install.""" + return self.distribution.has_headers() + + def has_scripts(self): + """Returns true if the current distribution has any scripts to. + install.""" + return self.distribution.has_scripts() + + def has_data(self): + """Returns true if the current distribution has any data to. + install.""" + return self.distribution.has_data_files() + + # 'sub_commands': a list of commands this command might have to run to + # get its work done. See cmd.py for more info. + sub_commands = [('install_lib', has_lib), + ('install_headers', has_headers), + ('install_scripts', has_scripts), + ('install_data', has_data), + # keep install_distinfo last, as it needs the record + # with files to be completely generated + ('install_distinfo', lambda self: not self.no_distinfo), + ] diff --git a/Lib/packaging/command/install_distinfo.py b/Lib/packaging/command/install_distinfo.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/install_distinfo.py @@ -0,0 +1,175 @@ +"""Create the PEP 376-compliant .dist-info directory.""" + +# Forked from the former install_egg_info command by Josip Djolonga + +import csv +import os +import re +import hashlib + +from packaging.command.cmd import Command +from packaging import logger +from shutil import rmtree + + +class install_distinfo(Command): + + description = 'create a .dist-info directory for the distribution' + + user_options = [ + ('distinfo-dir=', None, + "directory where the the .dist-info directory will be installed"), + ('installer=', None, + "the name of the installer"), + ('requested', None, + "generate a REQUESTED file"), + ('no-requested', None, + "do not generate a REQUESTED file"), + ('no-record', None, + "do not generate a RECORD file"), + ('no-resources', None, + "do not generate a RESSOURCES list installed file") + ] + + boolean_options = ['requested', 'no-record', 'no-resources'] + + negative_opt = {'no-requested': 'requested'} + + def initialize_options(self): + self.distinfo_dir = None + self.installer = None + self.requested = None + self.no_record = None + self.no_resources = None + + def finalize_options(self): + self.set_undefined_options('install_dist', + 'installer', 'requested', 'no_record') + + self.set_undefined_options('install_lib', + ('install_dir', 'distinfo_dir')) + + if self.installer is None: + # FIXME distutils or packaging? + # + document default in the option help text above and in install + self.installer = 'distutils' + if self.requested is None: + self.requested = True + if self.no_record is None: + self.no_record = False + if self.no_resources is None: + self.no_resources = False + + metadata = self.distribution.metadata + + basename = "%s-%s.dist-info" % ( + to_filename(safe_name(metadata['Name'])), + to_filename(safe_version(metadata['Version']))) + + self.distinfo_dir = os.path.join(self.distinfo_dir, basename) + self.outputs = [] + + def run(self): + # FIXME dry-run should be used at a finer level, so that people get + # useful logging output and can have an idea of what the command would + # have done + if not self.dry_run: + target = self.distinfo_dir + + if os.path.isdir(target) and not os.path.islink(target): + rmtree(target) + elif os.path.exists(target): + self.execute(os.unlink, (self.distinfo_dir,), + "removing " + target) + + self.execute(os.makedirs, (target,), "creating " + target) + + metadata_path = os.path.join(self.distinfo_dir, 'METADATA') + logger.info('creating %s', metadata_path) + self.distribution.metadata.write(metadata_path) + self.outputs.append(metadata_path) + + installer_path = os.path.join(self.distinfo_dir, 'INSTALLER') + logger.info('creating %s', installer_path) + with open(installer_path, 'w') as f: + f.write(self.installer) + self.outputs.append(installer_path) + + if self.requested: + requested_path = os.path.join(self.distinfo_dir, 'REQUESTED') + logger.info('creating %s', requested_path) + open(requested_path, 'w').close() + self.outputs.append(requested_path) + + + if not self.no_resources: + install_data = self.get_finalized_command('install_data') + if install_data.get_resources_out() != []: + resources_path = os.path.join(self.distinfo_dir, + 'RESOURCES') + logger.info('creating %s', resources_path) + with open(resources_path, 'wb') as f: + writer = csv.writer(f, delimiter=',', + lineterminator=os.linesep, + quotechar='"') + for tuple in install_data.get_resources_out(): + writer.writerow(tuple) + + self.outputs.append(resources_path) + + if not self.no_record: + record_path = os.path.join(self.distinfo_dir, 'RECORD') + logger.info('creating %s', record_path) + with open(record_path, 'w', encoding='utf-8') as f: + writer = csv.writer(f, delimiter=',', + lineterminator=os.linesep, + quotechar='"') + + install = self.get_finalized_command('install_dist') + + for fpath in install.get_outputs(): + if fpath.endswith('.pyc') or fpath.endswith('.pyo'): + # do not put size and md5 hash, as in PEP-376 + writer.writerow((fpath, '', '')) + else: + size = os.path.getsize(fpath) + with open(fpath, 'r') as fp: + hash = hashlib.md5() + hash.update(fp.read().encode()) + md5sum = hash.hexdigest() + writer.writerow((fpath, md5sum, size)) + + # add the RECORD file itself + writer.writerow((record_path, '', '')) + self.outputs.append(record_path) + + def get_outputs(self): + return self.outputs + + +# The following functions are taken from setuptools' pkg_resources module. + +def safe_name(name): + """Convert an arbitrary string to a standard distribution name + + Any runs of non-alphanumeric/. characters are replaced with a single '-'. + """ + return re.sub('[^A-Za-z0-9.]+', '-', name) + + +def safe_version(version): + """Convert an arbitrary string to a standard version string + + Spaces become dots, and all other non-alphanumeric characters become + dashes, with runs of multiple dashes condensed to a single dash. + """ + version = version.replace(' ', '.') + return re.sub('[^A-Za-z0-9.]+', '-', version) + + +def to_filename(name): + """Convert a project or version name to its filename-escaped form + + Any '-' characters are currently replaced with '_'. + """ + return name.replace('-', '_') diff --git a/Lib/packaging/command/install_headers.py b/Lib/packaging/command/install_headers.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/install_headers.py @@ -0,0 +1,43 @@ +"""Install C/C++ header files to the Python include directory.""" + +from packaging.command.cmd import Command + + +# XXX force is never used +class install_headers(Command): + + description = "install C/C++ header files" + + user_options = [('install-dir=', 'd', + "directory to install header files to"), + ('force', 'f', + "force installation (overwrite existing files)"), + ] + + boolean_options = ['force'] + + def initialize_options(self): + self.install_dir = None + self.force = False + self.outfiles = [] + + def finalize_options(self): + self.set_undefined_options('install_dist', + ('install_headers', 'install_dir'), + 'force') + + def run(self): + headers = self.distribution.headers + if not headers: + return + + self.mkpath(self.install_dir) + for header in headers: + out = self.copy_file(header, self.install_dir)[0] + self.outfiles.append(out) + + def get_inputs(self): + return self.distribution.headers or [] + + def get_outputs(self): + return self.outfiles diff --git a/Lib/packaging/command/install_lib.py b/Lib/packaging/command/install_lib.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/install_lib.py @@ -0,0 +1,222 @@ +"""Install all modules (extensions and pure Python).""" + +import os +import sys +import logging + +from packaging import logger +from packaging.command.cmd import Command +from packaging.errors import PackagingOptionError + + +# Extension for Python source files. +if hasattr(os, 'extsep'): + PYTHON_SOURCE_EXTENSION = os.extsep + "py" +else: + PYTHON_SOURCE_EXTENSION = ".py" + +class install_lib(Command): + + description = "install all modules (extensions and pure Python)" + + # The byte-compilation options are a tad confusing. Here are the + # possible scenarios: + # 1) no compilation at all (--no-compile --no-optimize) + # 2) compile .pyc only (--compile --no-optimize; default) + # 3) compile .pyc and "level 1" .pyo (--compile --optimize) + # 4) compile "level 1" .pyo only (--no-compile --optimize) + # 5) compile .pyc and "level 2" .pyo (--compile --optimize-more) + # 6) compile "level 2" .pyo only (--no-compile --optimize-more) + # + # The UI for this is two option, 'compile' and 'optimize'. + # 'compile' is strictly boolean, and only decides whether to + # generate .pyc files. 'optimize' is three-way (0, 1, or 2), and + # decides both whether to generate .pyo files and what level of + # optimization to use. + + user_options = [ + ('install-dir=', 'd', "directory to install to"), + ('build-dir=','b', "build directory (where to install from)"), + ('force', 'f', "force installation (overwrite existing files)"), + ('compile', 'c', "compile .py to .pyc [default]"), + ('no-compile', None, "don't compile .py files"), + ('optimize=', 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + ('skip-build', None, "skip the build steps"), + ] + + boolean_options = ['force', 'compile', 'skip-build'] + negative_opt = {'no-compile' : 'compile'} + + def initialize_options(self): + # let the 'install_dist' command dictate our installation directory + self.install_dir = None + self.build_dir = None + self.force = False + self.compile = None + self.optimize = None + self.skip_build = None + + def finalize_options(self): + # Get all the information we need to install pure Python modules + # from the umbrella 'install_dist' command -- build (source) directory, + # install (target) directory, and whether to compile .py files. + self.set_undefined_options('install_dist', + ('build_lib', 'build_dir'), + ('install_lib', 'install_dir'), + 'force', 'compile', 'optimize', 'skip_build') + + if self.compile is None: + self.compile = True + if self.optimize is None: + self.optimize = 0 + + if not isinstance(self.optimize, int): + try: + self.optimize = int(self.optimize) + if self.optimize not in (0, 1, 2): + raise AssertionError + except (ValueError, AssertionError): + raise PackagingOptionError("optimize must be 0, 1, or 2") + + def run(self): + # Make sure we have built everything we need first + self.build() + + # Install everything: simply dump the entire contents of the build + # directory to the installation directory (that's the beauty of + # having a build directory!) + outfiles = self.install() + + # (Optionally) compile .py to .pyc + if outfiles is not None and self.distribution.has_pure_modules(): + self.byte_compile(outfiles) + + # -- Top-level worker functions ------------------------------------ + # (called from 'run()') + + def build(self): + if not self.skip_build: + if self.distribution.has_pure_modules(): + self.run_command('build_py') + if self.distribution.has_ext_modules(): + self.run_command('build_ext') + + def install(self): + if os.path.isdir(self.build_dir): + outfiles = self.copy_tree(self.build_dir, self.install_dir) + else: + logger.warning( + '%s: %r does not exist -- no Python modules to install', + self.get_command_name(), self.build_dir) + return + return outfiles + + def byte_compile(self, files): + if getattr(sys, 'dont_write_bytecode'): + # XXX do we want this? because a Python runs without bytecode + # doesn't mean that the *dists should not contain bytecode + #--or does it? + logger.warning('%s: byte-compiling is disabled, skipping.', + self.get_command_name()) + return + + from packaging.util import byte_compile + + # Get the "--root" directory supplied to the "install_dist" command, + # and use it as a prefix to strip off the purported filename + # encoded in bytecode files. This is far from complete, but it + # should at least generate usable bytecode in RPM distributions. + install_root = self.get_finalized_command('install_dist').root + + # Temporary kludge until we remove the verbose arguments and use + # logging everywhere + verbose = logger.getEffectiveLevel() >= logging.DEBUG + + if self.compile: + byte_compile(files, optimize=0, + force=self.force, prefix=install_root, + dry_run=self.dry_run) + if self.optimize > 0: + byte_compile(files, optimize=self.optimize, + force=self.force, prefix=install_root, + verbose=verbose, + dry_run=self.dry_run) + + + # -- Utility methods ----------------------------------------------- + + def _mutate_outputs(self, has_any, build_cmd, cmd_option, output_dir): + if not has_any: + return [] + + build_cmd = self.get_finalized_command(build_cmd) + build_files = build_cmd.get_outputs() + build_dir = getattr(build_cmd, cmd_option) + + prefix_len = len(build_dir) + len(os.sep) + outputs = [] + for file in build_files: + outputs.append(os.path.join(output_dir, file[prefix_len:])) + + return outputs + + def _bytecode_filenames(self, py_filenames): + bytecode_files = [] + for py_file in py_filenames: + # Since build_py handles package data installation, the + # list of outputs can contain more than just .py files. + # Make sure we only report bytecode for the .py files. + ext = os.path.splitext(os.path.normcase(py_file))[1] + if ext != PYTHON_SOURCE_EXTENSION: + continue + if self.compile: + bytecode_files.append(py_file + "c") + if self.optimize > 0: + bytecode_files.append(py_file + "o") + + return bytecode_files + + + # -- External interface -------------------------------------------- + # (called by outsiders) + + def get_outputs(self): + """Return the list of files that would be installed if this command + were actually run. Not affected by the "dry-run" flag or whether + modules have actually been built yet. + """ + pure_outputs = \ + self._mutate_outputs(self.distribution.has_pure_modules(), + 'build_py', 'build_lib', + self.install_dir) + if self.compile: + bytecode_outputs = self._bytecode_filenames(pure_outputs) + else: + bytecode_outputs = [] + + ext_outputs = \ + self._mutate_outputs(self.distribution.has_ext_modules(), + 'build_ext', 'build_lib', + self.install_dir) + + return pure_outputs + bytecode_outputs + ext_outputs + + def get_inputs(self): + """Get the list of files that are input to this command, ie. the + files that get installed as they are named in the build tree. + The files in this list correspond one-to-one to the output + filenames returned by 'get_outputs()'. + """ + inputs = [] + + if self.distribution.has_pure_modules(): + build_py = self.get_finalized_command('build_py') + inputs.extend(build_py.get_outputs()) + + if self.distribution.has_ext_modules(): + build_ext = self.get_finalized_command('build_ext') + inputs.extend(build_ext.get_outputs()) + + return inputs diff --git a/Lib/packaging/command/install_scripts.py b/Lib/packaging/command/install_scripts.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/install_scripts.py @@ -0,0 +1,59 @@ +"""Install scripts.""" + +# Contributed by Bastian Kleineidam + +import os +from packaging.command.cmd import Command +from packaging import logger + +class install_scripts(Command): + + description = "install scripts (Python or otherwise)" + + user_options = [ + ('install-dir=', 'd', "directory to install scripts to"), + ('build-dir=','b', "build directory (where to install from)"), + ('force', 'f', "force installation (overwrite existing files)"), + ('skip-build', None, "skip the build steps"), + ] + + boolean_options = ['force', 'skip-build'] + + + def initialize_options(self): + self.install_dir = None + self.force = False + self.build_dir = None + self.skip_build = None + + def finalize_options(self): + self.set_undefined_options('build', ('build_scripts', 'build_dir')) + self.set_undefined_options('install_dist', + ('install_scripts', 'install_dir'), + 'force', 'skip_build') + + def run(self): + if not self.skip_build: + self.run_command('build_scripts') + + if not os.path.exists(self.build_dir): + self.outfiles = [] + return + + self.outfiles = self.copy_tree(self.build_dir, self.install_dir) + if os.name == 'posix': + # Set the executable bits (owner, group, and world) on + # all the scripts we just installed. + for file in self.get_outputs(): + if self.dry_run: + logger.info("changing mode of %s", file) + else: + mode = (os.stat(file).st_mode | 0o555) & 0o7777 + logger.info("changing mode of %s to %o", file, mode) + os.chmod(file, mode) + + def get_inputs(self): + return self.distribution.scripts or [] + + def get_outputs(self): + return self.outfiles or [] diff --git a/Lib/packaging/command/register.py b/Lib/packaging/command/register.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/register.py @@ -0,0 +1,282 @@ +"""Register a release with a project index.""" + +# Contributed by Richard Jones + +import io +import getpass +import urllib.error +import urllib.parse +import urllib.request + +from packaging import logger +from packaging.util import (read_pypirc, generate_pypirc, DEFAULT_REPOSITORY, + DEFAULT_REALM, get_pypirc_path) +from packaging.command.cmd import Command + +class register(Command): + + description = "register a release with PyPI" + user_options = [ + ('repository=', 'r', + "repository URL [default: %s]" % DEFAULT_REPOSITORY), + ('show-response', None, + "display full response text from server"), + ('list-classifiers', None, + "list valid Trove classifiers"), + ('strict', None , + "stop the registration if the metadata is not fully compliant") + ] + + boolean_options = ['show-response', 'list-classifiers', 'strict'] + + def initialize_options(self): + self.repository = None + self.realm = None + self.show_response = False + self.list_classifiers = False + self.strict = False + + def finalize_options(self): + if self.repository is None: + self.repository = DEFAULT_REPOSITORY + if self.realm is None: + self.realm = DEFAULT_REALM + + def run(self): + self._set_config() + + # Check the package metadata + check = self.distribution.get_command_obj('check') + if check.strict != self.strict and not check.all: + # If check was already run but with different options, + # re-run it + check.strict = self.strict + check.all = True + self.distribution.have_run.pop('check', None) + self.run_command('check') + + if self.dry_run: + self.verify_metadata() + elif self.list_classifiers: + self.classifiers() + else: + self.send_metadata() + + def _set_config(self): + ''' Reads the configuration file and set attributes. + ''' + config = read_pypirc(self.repository, self.realm) + if config != {}: + self.username = config['username'] + self.password = config['password'] + self.repository = config['repository'] + self.realm = config['realm'] + self.has_config = True + else: + if self.repository not in ('pypi', DEFAULT_REPOSITORY): + raise ValueError('%s not found in .pypirc' % self.repository) + if self.repository == 'pypi': + self.repository = DEFAULT_REPOSITORY + self.has_config = False + + def classifiers(self): + ''' Fetch the list of classifiers from the server. + ''' + response = urllib.request.urlopen(self.repository+'?:action=list_classifiers') + logger.info(response.read()) + + def verify_metadata(self): + ''' Send the metadata to the package index server to be checked. + ''' + # send the info to the server and report the result + code, result = self.post_to_server(self.build_post_data('verify')) + logger.info('server response (%s): %s', code, result) + + + def send_metadata(self): + ''' Send the metadata to the package index server. + + Well, do the following: + 1. figure who the user is, and then + 2. send the data as a Basic auth'ed POST. + + First we try to read the username/password from $HOME/.pypirc, + which is a ConfigParser-formatted file with a section + [distutils] containing username and password entries (both + in clear text). Eg: + + [distutils] + index-servers = + pypi + + [pypi] + username: fred + password: sekrit + + Otherwise, to figure who the user is, we offer the user three + choices: + + 1. use existing login, + 2. register as a new user, or + 3. set the password to a random string and email the user. + + ''' + # TODO factor registration out into another method + # TODO use print to print, not logging + + # see if we can short-cut and get the username/password from the + # config + if self.has_config: + choice = '1' + username = self.username + password = self.password + else: + choice = 'x' + username = password = '' + + # get the user's login info + choices = '1 2 3 4'.split() + while choice not in choices: + logger.info('''\ +We need to know who you are, so please choose either: + 1. use your existing login, + 2. register as a new user, + 3. have the server generate a new password for you (and email it to you), or + 4. quit +Your selection [default 1]: ''') + + choice = input() + if not choice: + choice = '1' + elif choice not in choices: + print('Please choose one of the four options!') + + if choice == '1': + # get the username and password + while not username: + username = input('Username: ') + while not password: + password = getpass.getpass('Password: ') + + # set up the authentication + auth = urllib.request.HTTPPasswordMgr() + host = urllib.parse.urlparse(self.repository)[1] + auth.add_password(self.realm, host, username, password) + # send the info to the server and report the result + code, result = self.post_to_server(self.build_post_data('submit'), + auth) + logger.info('Server response (%s): %s', code, result) + + # possibly save the login + if code == 200: + if self.has_config: + # sharing the password in the distribution instance + # so the upload command can reuse it + self.distribution.password = password + else: + logger.info( + 'I can store your PyPI login so future submissions ' + 'will be faster.\n(the login will be stored in %s)', + get_pypirc_path()) + choice = 'X' + while choice.lower() not in 'yn': + choice = input('Save your login (y/N)?') + if not choice: + choice = 'n' + if choice.lower() == 'y': + generate_pypirc(username, password) + + elif choice == '2': + data = {':action': 'user'} + data['name'] = data['password'] = data['email'] = '' + data['confirm'] = None + while not data['name']: + data['name'] = input('Username: ') + while data['password'] != data['confirm']: + while not data['password']: + data['password'] = getpass.getpass('Password: ') + while not data['confirm']: + data['confirm'] = getpass.getpass(' Confirm: ') + if data['password'] != data['confirm']: + data['password'] = '' + data['confirm'] = None + print("Password and confirm don't match!") + while not data['email']: + data['email'] = input(' EMail: ') + code, result = self.post_to_server(data) + if code != 200: + logger.info('server response (%s): %s', code, result) + else: + logger.info('you will receive an email shortly; follow the ' + 'instructions in it to complete registration.') + elif choice == '3': + data = {':action': 'password_reset'} + data['email'] = '' + while not data['email']: + data['email'] = input('Your email address: ') + code, result = self.post_to_server(data) + logger.info('server response (%s): %s', code, result) + + def build_post_data(self, action): + # figure the data to send - the metadata plus some additional + # information used by the package server + data = self.distribution.metadata.todict() + data[':action'] = action + return data + + # XXX to be refactored with upload.upload_file + def post_to_server(self, data, auth=None): + ''' Post a query to the server, and return a string response. + ''' + if 'name' in data: + logger.info('Registering %s to %s', data['name'], self.repository) + # Build up the MIME payload for the urllib2 POST data + boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = '\n--' + boundary + end_boundary = sep_boundary + '--' + body = io.StringIO() + for key, value in data.items(): + # handle multiple entries for the same name + if not isinstance(value, (tuple, list)): + value = [value] + + for value in value: + body.write(sep_boundary) + body.write('\nContent-Disposition: form-data; name="%s"'%key) + body.write("\n\n") + body.write(value) + if value and value[-1] == '\r': + body.write('\n') # write an extra newline (lurve Macs) + body.write(end_boundary) + body.write("\n") + body = body.getvalue() + + # build the Request + headers = { + 'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary, + 'Content-length': str(len(body)) + } + req = urllib.request.Request(self.repository, body, headers) + + # handle HTTP and include the Basic Auth handler + opener = urllib.request.build_opener( + urllib.request.HTTPBasicAuthHandler(password_mgr=auth) + ) + data = '' + try: + result = opener.open(req) + except urllib.error.HTTPError as e: + if self.show_response: + data = e.fp.read() + result = e.code, e.msg + except urllib.error.URLError as e: + result = 500, str(e) + else: + if self.show_response: + data = result.read() + result = 200, 'OK' + if self.show_response: + dashes = '-' * 75 + logger.info('%s%s%s', dashes, data, dashes) + + return result diff --git a/Lib/packaging/command/sdist.py b/Lib/packaging/command/sdist.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/sdist.py @@ -0,0 +1,375 @@ +"""Create a source distribution.""" + +import os +import sys +import re +from io import StringIO +from glob import glob +from shutil import get_archive_formats, rmtree + +from packaging import logger +from packaging.util import resolve_name +from packaging.errors import (PackagingPlatformError, PackagingOptionError, + PackagingModuleError, PackagingFileError) +from packaging.command import get_command_names +from packaging.command.cmd import Command +from packaging.manifest import Manifest + + +def show_formats(): + """Print all possible values for the 'formats' option (used by + the "--help-formats" command-line option). + """ + from packaging.fancy_getopt import FancyGetopt + formats = sorted(('formats=' + name, None, desc) + for name, desc in get_archive_formats()) + FancyGetopt(formats).print_help( + "List of available source distribution formats:") + +# a \ followed by some spaces + EOL +_COLLAPSE_PATTERN = re.compile('\\\w\n', re.M) +_COMMENTED_LINE = re.compile('^#.*\n$|^\w*\n$', re.M) + + +class sdist(Command): + + description = "create a source distribution (tarball, zip file, etc.)" + + user_options = [ + ('manifest=', 'm', + "name of manifest file [default: MANIFEST]"), + ('use-defaults', None, + "include the default file set in the manifest " + "[default; disable with --no-defaults]"), + ('no-defaults', None, + "don't include the default file set"), + ('prune', None, + "specifically exclude files/directories that should not be " + "distributed (build tree, RCS/CVS dirs, etc.) " + "[default; disable with --no-prune]"), + ('no-prune', None, + "don't automatically exclude anything"), + ('manifest-only', 'o', + "just regenerate the manifest and then stop "), + ('formats=', None, + "formats for source distribution (comma-separated list)"), + ('keep-temp', 'k', + "keep the distribution tree around after creating " + + "archive file(s)"), + ('dist-dir=', 'd', + "directory to put the source distribution archive(s) in " + "[default: dist]"), + ('check-metadata', None, + "Ensure that all required elements of metadata " + "are supplied. Warn if any missing. [default]"), + ('owner=', 'u', + "Owner name used when creating a tar file [default: current user]"), + ('group=', 'g', + "Group name used when creating a tar file [default: current group]"), + ('manifest-builders=', None, + "manifest builders (comma-separated list)"), + ] + + boolean_options = ['use-defaults', 'prune', + 'manifest-only', 'keep-temp', 'check-metadata'] + + help_options = [ + ('help-formats', None, + "list available distribution formats", show_formats), + ] + + negative_opt = {'no-defaults': 'use-defaults', + 'no-prune': 'prune'} + + default_format = {'posix': 'gztar', + 'nt': 'zip'} + + def initialize_options(self): + self.manifest = None + # 'use_defaults': if true, we will include the default file set + # in the manifest + self.use_defaults = True + self.prune = True + self.manifest_only = False + self.formats = None + self.keep_temp = False + self.dist_dir = None + + self.archive_files = None + self.metadata_check = True + self.owner = None + self.group = None + self.filelist = None + self.manifest_builders = None + + def _check_archive_formats(self, formats): + supported_formats = [name for name, desc in get_archive_formats()] + for format in formats: + if format not in supported_formats: + return format + return None + + def finalize_options(self): + if self.manifest is None: + self.manifest = "MANIFEST" + + self.ensure_string_list('formats') + if self.formats is None: + try: + self.formats = [self.default_format[os.name]] + except KeyError: + raise PackagingPlatformError("don't know how to create source " + "distributions on platform %s" % os.name) + + bad_format = self._check_archive_formats(self.formats) + if bad_format: + raise PackagingOptionError("unknown archive format '%s'" \ + % bad_format) + + if self.dist_dir is None: + self.dist_dir = "dist" + + if self.filelist is None: + self.filelist = Manifest() + + if self.manifest_builders is None: + self.manifest_builders = [] + else: + if isinstance(self.manifest_builders, str): + self.manifest_builders = self.manifest_builders.split(',') + builders = [] + for builder in self.manifest_builders: + builder = builder.strip() + if builder == '': + continue + try: + builder = resolve_name(builder) + except ImportError as e: + raise PackagingModuleError(e) + + builders.append(builder) + + self.manifest_builders = builders + + def run(self): + # 'filelist' contains the list of files that will make up the + # manifest + self.filelist.clear() + + # Check the package metadata + if self.metadata_check: + self.run_command('check') + + # Do whatever it takes to get the list of files to process + # (process the manifest template, read an existing manifest, + # whatever). File list is accumulated in 'self.filelist'. + self.get_file_list() + + # If user just wanted us to regenerate the manifest, stop now. + if self.manifest_only: + return + + # Otherwise, go ahead and create the source distribution tarball, + # or zipfile, or whatever. + self.make_distribution() + + def get_file_list(self): + """Figure out the list of files to include in the source + distribution, and put it in 'self.filelist'. This might involve + reading the manifest template (and writing the manifest), or just + reading the manifest, or just using the default file set -- it all + depends on the user's options. + """ + template_exists = len(self.distribution.extra_files) > 0 + if not template_exists: + logger.warning('%s: using default file list', + self.get_command_name()) + self.filelist.findall() + + if self.use_defaults: + self.add_defaults() + if template_exists: + template = '\n'.join(self.distribution.extra_files) + self.filelist.read_template(StringIO(template)) + + # call manifest builders, if any. + for builder in self.manifest_builders: + builder(self.distribution, self.filelist) + + if self.prune: + self.prune_file_list() + + self.filelist.write(self.manifest) + + 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. + - all files defined as scripts. + - all C sources listed as part of extensions or C libraries + in the setup script (doesn't catch C headers!) + 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 = False + for fn in alts: + if os.path.exists(fn): + got_it = True + self.filelist.append(fn) + break + + if not got_it: + logger.warning( + '%s: standard file not found: should have one of %s', + self.get_command_name(), ', '.join(alts)) + else: + if os.path.exists(fn): + self.filelist.append(fn) + else: + logger.warning('%s: standard file %r not found', + self.get_command_name(), fn) + + optional = ['test/test*.py', 'setup.cfg'] + for pattern in optional: + files = [f for f in glob(pattern) if os.path.isfile(f)] + if files: + self.filelist.extend(files) + + for cmd_name in get_command_names(): + try: + cmd_obj = self.get_finalized_command(cmd_name) + except PackagingOptionError: + pass + else: + self.filelist.extend(cmd_obj.get_source_files()) + + def prune_file_list(self): + """Prune off branches that might slip into the file list as created + by 'read_template()', but really don't belong there: + * the build tree (typically "build") + * the release tree itself (only an issue if we ran "sdist" + previously with --keep-temp, or it aborted) + * any RCS, CVS, .svn, .hg, .git, .bzr, _darcs directories + """ + build = self.get_finalized_command('build') + base_dir = self.distribution.get_fullname() + + self.filelist.exclude_pattern(None, prefix=build.build_base) + self.filelist.exclude_pattern(None, prefix=base_dir) + + # pruning out vcs directories + # both separators are used under win32 + if sys.platform == 'win32': + seps = r'/|\\' + else: + seps = '/' + + vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr', + '_darcs'] + vcs_ptrn = r'(^|%s)(%s)(%s).*' % (seps, '|'.join(vcs_dirs), seps) + self.filelist.exclude_pattern(vcs_ptrn, is_regex=True) + + def make_release_tree(self, base_dir, files): + """Create the directory tree that will become the source + distribution archive. All directories implied by the filenames in + 'files' are created under 'base_dir', and then we hard link or copy + (if hard linking is unavailable) those files into place. + Essentially, this duplicates the developer's source tree, but in a + directory named after the distribution, containing only the files + to be distributed. + """ + # Create all the directories under 'base_dir' necessary to + # put 'files' there; the 'mkpath()' is just so we don't die + # if the manifest happens to be empty. + self.mkpath(base_dir) + self.create_tree(base_dir, files, dry_run=self.dry_run) + + # And walk over the list of files, either making a hard link (if + # os.link exists) to each one that doesn't already exist in its + # corresponding location under 'base_dir', or copying each file + # that's out-of-date in 'base_dir'. (Usually, all files will be + # out-of-date, because by default we blow away 'base_dir' when + # we're done making the distribution archives.) + + if hasattr(os, 'link'): # can make hard links on this system + link = 'hard' + msg = "making hard links in %s..." % base_dir + else: # nope, have to copy + link = None + msg = "copying files to %s..." % base_dir + + if not files: + logger.warning("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 PackagingFileError(msg) + + for file in files: + if not os.path.isfile(file): + logger.warning("'%s' not a regular file -- skipping", file) + else: + dest = os.path.join(base_dir, file) + self.copy_file(file, dest, link=link) + + self.distribution.metadata.write(os.path.join(base_dir, 'PKG-INFO')) + + def make_distribution(self): + """Create the source distribution(s). First, we create the release + tree with 'make_release_tree()'; then, we create all required + archive files (according to 'self.formats') from the release tree. + Finally, we clean up by blowing away the release tree (unless + 'self.keep_temp' is true). The list of archive files created is + stored so it can be retrieved later by 'get_archive_files()'. + """ + # Don't warn about missing metadata here -- should be (and is!) + # done elsewhere. + base_dir = self.distribution.get_fullname() + base_name = os.path.join(self.dist_dir, base_dir) + + self.make_release_tree(base_dir, self.filelist.files) + archive_files = [] # remember names of files we create + # tar archive must be created last to avoid overwrite and remove + if 'tar' in self.formats: + self.formats.append(self.formats.pop(self.formats.index('tar'))) + + for fmt in self.formats: + file = self.make_archive(base_name, fmt, base_dir=base_dir, + owner=self.owner, group=self.group) + archive_files.append(file) + self.distribution.dist_files.append(('sdist', '', file)) + + self.archive_files = archive_files + + if not self.keep_temp: + if self.dry_run: + logger.info('removing %s', base_dir) + else: + rmtree(base_dir) + + def get_archive_files(self): + """Return the list of archive files created when the command + was run, or None if the command hasn't run yet. + """ + return self.archive_files + + def create_tree(self, base_dir, files, mode=0o777, verbose=1, + dry_run=False): + need_dir = set() + for file in files: + need_dir.add(os.path.join(base_dir, os.path.dirname(file))) + + # Now create them + for dir in sorted(need_dir): + self.mkpath(dir, mode, verbose=verbose, dry_run=dry_run) diff --git a/Lib/packaging/command/test.py b/Lib/packaging/command/test.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/test.py @@ -0,0 +1,81 @@ +"""Run the project's test suite.""" + +import os +import sys +import logging +import unittest + +from packaging import logger +from packaging.command.cmd import Command +from packaging.database import get_distribution +from packaging.errors import PackagingOptionError +from packaging.util import resolve_name + + +class test(Command): + + description = "run the project's test suite" + + user_options = [ + ('suite=', 's', + "test suite to run (for example: 'some_module.test_suite')"), + ('runner=', None, + "test runner to be called."), + ('tests-require=', None, + "list of distributions required to run the test suite."), + ] + + def initialize_options(self): + self.suite = None + self.runner = None + self.tests_require = [] + + def finalize_options(self): + self.build_lib = self.get_finalized_command("build").build_lib + for requirement in self.tests_require: + if get_distribution(requirement) is None: + logger.warning("test dependency %s is not installed, " + "tests may fail", requirement) + if (not self.suite and not self.runner and + self.get_ut_with_discovery() is None): + raise PackagingOptionError( + "no test discovery available, please give a 'suite' or " + "'runner' option or install unittest2") + + def get_ut_with_discovery(self): + if hasattr(unittest.TestLoader, "discover"): + return unittest + else: + try: + import unittest2 + return unittest2 + except ImportError: + return None + + def run(self): + prev_syspath = sys.path[:] + try: + # build release + build = self.get_reinitialized_command('build') + self.run_command('build') + sys.path.insert(0, build.build_lib) + + # Temporary kludge until we remove the verbose arguments and use + # logging everywhere + logger = logging.getLogger('packaging') + verbose = logger.getEffectiveLevel() >= logging.DEBUG + verbosity = verbose + 1 + + # run the tests + if self.runner: + resolve_name(self.runner)() + elif self.suite: + runner = unittest.TextTestRunner(verbosity=verbosity) + runner.run(resolve_name(self.suite)()) + elif self.get_ut_with_discovery(): + ut = self.get_ut_with_discovery() + test_suite = ut.TestLoader().discover(os.curdir) + runner = ut.TextTestRunner(verbosity=verbosity) + runner.run(test_suite) + finally: + sys.path[:] = prev_syspath diff --git a/Lib/packaging/command/upload.py b/Lib/packaging/command/upload.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/upload.py @@ -0,0 +1,201 @@ +"""Upload a distribution to a project index.""" + +import os +import socket +import logging +import platform +import urllib.parse +from io import BytesIO +from base64 import standard_b64encode +from hashlib import md5 +from urllib.error import HTTPError +from urllib.request import urlopen, Request + +from packaging import logger +from packaging.errors import PackagingOptionError +from packaging.util import (spawn, read_pypirc, DEFAULT_REPOSITORY, + DEFAULT_REALM) +from packaging.command.cmd import Command + + +class upload(Command): + + description = "upload distribution to PyPI" + + user_options = [ + ('repository=', 'r', + "repository URL [default: %s]" % DEFAULT_REPOSITORY), + ('show-response', None, + "display full response text from server"), + ('sign', 's', + "sign files to upload using gpg"), + ('identity=', 'i', + "GPG identity used to sign files"), + ('upload-docs', None, + "upload documentation too"), + ] + + boolean_options = ['show-response', 'sign'] + + def initialize_options(self): + self.repository = None + self.realm = None + self.show_response = False + self.username = '' + self.password = '' + self.show_response = False + self.sign = False + self.identity = None + self.upload_docs = False + + def finalize_options(self): + if self.repository is None: + self.repository = DEFAULT_REPOSITORY + if self.realm is None: + self.realm = DEFAULT_REALM + if self.identity and not self.sign: + raise PackagingOptionError( + "Must use --sign for --identity to have meaning") + config = read_pypirc(self.repository, self.realm) + if config != {}: + self.username = config['username'] + self.password = config['password'] + self.repository = config['repository'] + self.realm = config['realm'] + + # getting the password from the distribution + # if previously set by the register command + if not self.password and self.distribution.password: + self.password = self.distribution.password + + def run(self): + if not self.distribution.dist_files: + raise PackagingOptionError( + "No dist file created in earlier command") + for command, pyversion, filename in self.distribution.dist_files: + self.upload_file(command, pyversion, filename) + if self.upload_docs: + upload_docs = self.get_finalized_command("upload_docs") + upload_docs.repository = self.repository + upload_docs.username = self.username + upload_docs.password = self.password + upload_docs.run() + + # XXX to be refactored with register.post_to_server + def upload_file(self, command, pyversion, filename): + # Makes sure the repository URL is compliant + scheme, netloc, url, params, query, fragments = \ + urllib.parse.urlparse(self.repository) + if params or query or fragments: + raise AssertionError("Incompatible url %s" % self.repository) + + if scheme not in ('http', 'https'): + raise AssertionError("unsupported scheme " + scheme) + + # Sign if requested + if self.sign: + gpg_args = ["gpg", "--detach-sign", "-a", filename] + if self.identity: + gpg_args[2:2] = ["--local-user", self.identity] + spawn(gpg_args, + dry_run=self.dry_run) + + # Fill in the data - send all the metadata in case we need to + # register a new release + with open(filename, 'rb') as f: + content = f.read() + + data = self.distribution.metadata.todict() + + # extra upload infos + data[':action'] = 'file_upload' + data['protcol_version'] = '1' + data['content'] = (os.path.basename(filename), content) + data['filetype'] = command + data['pyversion'] = pyversion + data['md5_digest'] = md5(content).hexdigest() + + if command == 'bdist_dumb': + data['comment'] = 'built for %s' % platform.platform(terse=True) + + if self.sign: + with open(filename + '.asc') as fp: + sig = fp.read() + data['gpg_signature'] = [ + (os.path.basename(filename) + ".asc", sig)] + + # set up the authentication + # The exact encoding of the authentication string is debated. + # Anyway PyPI only accepts ascii for both username or password. + user_pass = (self.username + ":" + self.password).encode('ascii') + auth = b"Basic " + standard_b64encode(user_pass) + + # Build up the MIME payload for the POST data + boundary = b'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = b'\n--' + boundary + end_boundary = sep_boundary + b'--' + body = BytesIO() + + file_fields = ('content', 'gpg_signature') + + for key, value in data.items(): + # handle multiple entries for the same name + if not isinstance(value, tuple): + value = [value] + + content_dispo = '\nContent-Disposition: form-data; name="%s"' % key + + if key in file_fields: + filename_, content = value + filename_ = ';filename="%s"' % filename_ + body.write(sep_boundary) + body.write(content_dispo.encode('utf-8')) + body.write(filename_.encode('utf-8')) + body.write(b"\n\n") + body.write(content) + else: + for value in value: + value = str(value).encode('utf-8') + body.write(sep_boundary) + body.write(content_dispo.encode('utf-8')) + body.write(b"\n\n") + body.write(value) + if value and value.endswith(b'\r'): + # write an extra newline (lurve Macs) + body.write(b'\n') + + body.write(end_boundary) + body.write(b"\n") + body = body.getvalue() + + logger.info("Submitting %s to %s", filename, self.repository) + + # build the Request + headers = {'Content-type': + 'multipart/form-data; boundary=%s' % + boundary.decode('ascii'), + 'Content-length': str(len(body)), + 'Authorization': auth} + + request = Request(self.repository, data=body, + headers=headers) + # send the data + try: + result = urlopen(request) + status = result.code + reason = result.msg + except socket.error as e: + logger.error(e) + return + except HTTPError as e: + status = e.code + reason = e.msg + + if status == 200: + logger.info('Server response (%s): %s', status, reason) + else: + logger.error('Upload failed (%s): %s', status, reason) + + if self.show_response and logger.isEnabledFor(logging.INFO): + sep = '-' * 75 + logger.info('%s\n%s\n%s', sep, result.read().decode(), sep) diff --git a/Lib/packaging/command/upload_docs.py b/Lib/packaging/command/upload_docs.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/command/upload_docs.py @@ -0,0 +1,173 @@ +"""Upload HTML documentation to a project index.""" + +import os +import base64 +import socket +import zipfile +import logging +import http.client +import urllib.parse +from io import BytesIO + +from packaging import logger +from packaging.util import read_pypirc, DEFAULT_REPOSITORY, DEFAULT_REALM +from packaging.errors import PackagingFileError +from packaging.command.cmd import Command + + +def zip_dir(directory): + """Compresses recursively contents of directory into a BytesIO object""" + destination = BytesIO() + zip_file = zipfile.ZipFile(destination, "w") + for root, dirs, files in os.walk(directory): + for name in files: + full = os.path.join(root, name) + relative = root[len(directory):].lstrip(os.path.sep) + dest = os.path.join(relative, name) + zip_file.write(full, dest) + zip_file.close() + return destination + + +# grabbed from +# http://code.activestate.com/recipes/ +# 146306-http-client-to-post-using-multipartform-data/ +# TODO factor this out for use by install and command/upload + +def encode_multipart(fields, files, boundary=None): + """ + *fields* is a sequence of (name: str, value: str) elements for regular + form fields, *files* is a sequence of (name: str, filename: str, value: + bytes) elements for data to be uploaded as files. + + Returns (content_type: bytes, body: bytes) ready for http.client.HTTP. + """ + if boundary is None: + boundary = b'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + elif not isinstance(boundary, bytes): + raise TypeError('boundary is not bytes but %r' % type(boundary)) + + l = [] + for key, value in fields: + l.extend(( + b'--' + boundary, + ('Content-Disposition: form-data; name="%s"' % + key).encode('utf-8'), + b'', + value.encode('utf-8'))) + + for key, filename, value in files: + l.extend(( + b'--' + boundary, + ('Content-Disposition: form-data; name="%s"; filename="%s"' % + (key, filename)).encode('utf-8'), + b'', + value)) + l.append(b'--' + boundary + b'--') + l.append(b'') + + body = b'\r\n'.join(l) + + content_type = b'multipart/form-data; boundary=' + boundary + return content_type, body + + +class upload_docs(Command): + + description = "upload HTML documentation to PyPI" + + user_options = [ + ('repository=', 'r', + "repository URL [default: %s]" % DEFAULT_REPOSITORY), + ('show-response', None, + "display full response text from server"), + ('upload-dir=', None, + "directory to upload"), + ] + + def initialize_options(self): + self.repository = None + self.realm = None + self.show_response = False + self.upload_dir = None + self.username = '' + self.password = '' + + def finalize_options(self): + if self.repository is None: + self.repository = DEFAULT_REPOSITORY + if self.realm is None: + self.realm = DEFAULT_REALM + if self.upload_dir is None: + build = self.get_finalized_command('build') + self.upload_dir = os.path.join(build.build_base, "docs") + if not os.path.isdir(self.upload_dir): + self.upload_dir = os.path.join(build.build_base, "doc") + logger.info('Using upload directory %s', self.upload_dir) + self.verify_upload_dir(self.upload_dir) + config = read_pypirc(self.repository, self.realm) + if config != {}: + self.username = config['username'] + self.password = config['password'] + self.repository = config['repository'] + self.realm = config['realm'] + + def verify_upload_dir(self, upload_dir): + self.ensure_dirname('upload_dir') + index_location = os.path.join(upload_dir, "index.html") + if not os.path.exists(index_location): + mesg = "No 'index.html found in docs directory (%s)" + raise PackagingFileError(mesg % upload_dir) + + def run(self): + name = self.distribution.metadata['Name'] + version = self.distribution.metadata['Version'] + zip_file = zip_dir(self.upload_dir) + + fields = [(':action', 'doc_upload'), + ('name', name), ('version', version)] + files = [('content', name, zip_file.getvalue())] + content_type, body = encode_multipart(fields, files) + + credentials = self.username + ':' + self.password + auth = b"Basic " + base64.encodebytes(credentials.encode()).strip() + + logger.info("Submitting documentation to %s", self.repository) + + scheme, netloc, url, params, query, fragments = urllib.parse.urlparse( + self.repository) + if scheme == "http": + conn = http.client.HTTPConnection(netloc) + elif scheme == "https": + conn = http.client.HTTPSConnection(netloc) + else: + raise AssertionError("unsupported scheme %r" % scheme) + + try: + conn.connect() + conn.putrequest("POST", url) + conn.putheader('Content-type', content_type) + conn.putheader('Content-length', str(len(body))) + conn.putheader('Authorization', auth) + conn.endheaders() + conn.send(body) + + except socket.error as e: + logger.error(e) + return + + r = conn.getresponse() + + if r.status == 200: + logger.info('Server response (%s): %s', r.status, r.reason) + elif r.status == 301: + location = r.getheader('Location') + if location is None: + location = 'http://packages.python.org/%s/' % name + logger.info('Upload successful. Visit %s', location) + else: + logger.error('Upload failed (%s): %s', r.status, r.reason) + + if self.show_response and logger.isEnabledFor(logging.INFO): + sep = '-' * 75 + logger.info('%s\n%s\n%s', sep, r.read().decode('utf-8'), sep) diff --git a/Lib/packaging/command/wininst-10.0-amd64.exe b/Lib/packaging/command/wininst-10.0-amd64.exe new file mode 100644 index 0000000000000000000000000000000000000000..11f98cd2adf1075b7ff7be7f02ebc8e743bb6b9e GIT binary patch literal 222208 zc%1CLd3Y36);L_fkp>d0SsEg1kVXT|5(sKSK)axtR6{oe*`mS_jYb?m8R!-r5rdUz znrkcbj(TP-ouneZN1x z=lOWZ?W$XMIrp4%&vtL!3f#3>un2-+g+E;vgi3+`^9cXOKa(I_H+=hb!ryxC8BuBS z?-{XR`GadSRV3a5u#gctFm$|AJ(gWne|!sfx( z!d-R0Ss3!I#JTEUky-HAzWMR^;QfyV;n(jqbAWK{*6w98pq24!?z<;=k02~Lz}plK z!tX3|w{jl%Kb{v8%9daT;3OS>hghyIS2cb$FGypAvC^O>UsKLAe$Co7#c)kH0o(}v z;kV%0a{meq|Np=4|CI8E;Goi6A?Oshm`ZaeY)5*Da&?7C(W9Y%o~zltd$$r^;<78@ zl`e-84!Y78E9&VCAL~%qF@=4hlphq!eh8IH^8~SM6I at Ue3fraqbUpqyE9F(ekiz!X zf`oBSzQZgqP3_P_6S5CNrtTaAIptNM0ZO?Z?4v}Svlg0#h+^}zTK!18m%?(!r ztCL-srSJ%v%Fvxd5iZuMzyQVaUlOQ&AxrJBg!=ngjgP$tRkS}{(RCQ|AL8rOj)Gt> zRI<-0Lkr6SC{h8E_YW38BqIXtNJ`Ba&6-Sed{}DooRzgYjCutcRS?yI8gc$rN#x z&o>LP0=$L>GK}F$k$Gl??a`g>bFuy&7 at +Pvj@RXFM)ho7eLPn0Llm#|N0zt>eC%#u z(G{6Kwl>ShPD)FqCCh3$X}(z5cp4EXvGc^mF-h&Pi{wor9UsX)PDM4gikeB5dh+U0h at _v*K{EZqh2ug_ zyW0T>NQc2MtMLM}9rYJ;z_nZ$6^$ld$LF?V;UeOHX_2&8iM;A6LPTyn{h|p6Vf+4g zi=brhP{QTJ6YS5Z_I<3`%T7p49&*9!zHdmImz|g0Eq+$5gcrCTmDJM%q>bx`pDLJb z>!F1GE at gV8e}*4WQxr at A-rE99>&-rc+~Fzl=B*t5r5O1o`L)=-uB?wky at dc0CxtyqAhva3LRcjholJ)}b{`+e{;$Z|l5 zq~-x6GTbg2qCj@>4#m=_L>87R5!pV>$Lf9V{aAVRCR2sA7s$G at s?e8;+MvUvjyzF% z_BAT2H!AH1O4s+%m*BVxgHC*grOv)4ZnY^eXG_BQz<_~L-PtPu+)!K(?WdJu%gYre zyA(yu5rVh-p+A1#=IiSfKn& z at OqhnaDWQ(@Gn7_NP2Wz51d>2AFP{t3~c@&r+mU0EB?E;q) zu$=L!jruG$_0$|DpR#9H`B)^^VbF+{%M}*n z$gH at zqBq?GsYB1AcJ$Q33^;!E&f;wu~D$p59 z*tQa%L$$kMz#uG^Qt_%#iW0Fk0A{(&U2L?s4Gl|e8*fNq9om(>Cb&$Spl|@Pl<>5X zcpaV#ayrETXSbid?+f2;_k~wDeBrf(JkaW203CttM*uJTM$FI at cIE7AUtXE0tD!=~d1($lxNV6=i0wrBMVtrcpwa`=;5S%0Y`buqg*0*oJo_s>+od~g zPyy%S56H5ab_mJ{!9Swjm^S7nMCt;Zv!WJy(1aRfuwJ96bq at 7nuQi__-d9rJ1<+bN zA1*$>5$=m?K>I3|s_X`tS*wYsbmtSdVL!qCbPMB{NZ>yFkVS|OhK7FiFg5gf01Xa8 zV(@N at fcDX|91SpEra#8#OA((hh_8elwh*q)Y{zzK=vuGEj{pPP` zuqI?yV^sMI at zrCg(9vzsQEVC6D}Gl2Qnd(jvwnjRn{q89;G zdO;SnlFw_hw3(}juTuPI at 4!?TcBjRt0V1gf_3GdNbl&UELYOeI;wv00MO{l71#VS{ zKXGFZ zA*nCcyV7Zb6z~c12A?1&U5N?8?X;s{kcuk^U8 at nC2q`M`5D??K^X{3+Ozq)~0v8{* z$s~xx^4~zV%+hZ8E>0HPxd*77j at jJ4h50{pCiej{{5Tm%2-HQPU9fvDNXXW~k=Hyn z)8pg(F{0#ll-P|rDRe{o+K>{g5fyO4e#vgwWCaBkt&l}j?`OGn^}-A+7Jj;(x#(19f zdZH9$4dz+TCQ3m?JI}f&QA#7T59mIf@^ceKTXg3KJnOnd7C1tUkOhJoZBVf5#j-kb z$lAoRciJ^cvRZNa;tr?Od`B at ZJ% z(DgphA-9!S1k4)u`w__WUqRN%2T|tl0<{@EVN)!7By45?6!)_#Nk5DVqc%gm*kjEx z)P7{tf(#rN1P=9wN0l!`ZEdT)AEmuNJnjj&kJ}7WX$ed|P~qLIBG1D4U5K;s^iK)? zm8hj`4rKo9ol4kSgkD+1sRQ5vb|O&Rfq{l_0ND5ii4b{c7WXK_UT{52dEOs+9wB!X z&wAP at 26zd3LEygnWGiH+>(1LTn+5RETl5I%?e5Gg#k{Z=1jm5R%)5DJrtUOB zCa9m>fL$#6vB{uI1Q``+S7tJ(`MAlT?;53_LE6a at G#6|#l-PdS zf)Zc^u&ch%j__-TE}`F?_S!8#w}Vop05+pGVg>Yc+*_`1$nr;S{vkXHxc}*kSl^$; zQnOINrf6&0bUkhc!#r&L5Nt?a-bd>{^s`X9KQgKq%1dmYkG%(mKW}D$kEOoPjmMi& z`SS{=K-6cky>DX7LHofIs9Qn-nR#U?;<1qfC5cL2bX_l{vQ?*lqN296YB!Wa6YdtE zW at J6G%Ms0LN71suq5KrswWQ9P(+kFz!J2_>*IjgGXZ`FvDl#AYBEYn_u}STrQDz|-q>U1UiXa*-CDgi$OP2&7B>M?dgclrsB z&JSi%2P89cdDa~~3kak;Z{%5X6Imei`|+$75?N4DppmtrFPw)VwOcSwGZ6%Ka4e$Z zCZN}$A`rYyFf*WzRtR+SvAy6QH^XBy2-zdRs1~(ezuL%W#m?*_8Ji5y|*y`N7p3vVMwuswt&HU$TJ z*ie)q<8F`c{O%Ou%oTHhGpDx`hog at Jc93H#p{&8n&4~gs$9GLL?zG4kx(;KHohF!x zfhUpiwhQ~~Jp~bc$Y4?%-5oYqv^^ID00`S(@wgoZC7+#wY*~rSs)FQ at fkVe3hsvR3 zEcyY!g$Dt$BS7xzO}#2oF`iJ?5c;x{bD=GJ9!FdT6rMkpLZHO8 at aU^4$go7LU6NWe zR;slQ7POjH0$a-m>m&}QaN3W-zS90oxlk!1&*0{F5y+kB9PKxP38PkWdj=^93=Yh_ zf|%QoPFyynqrxn*60JWOl%#b5hnd5NdHMR}Ff$;> z7g?Lm&SRL7LZ~=iKZyEYgO{%F6U&?+kk!x4V%dKQJfnhsgR9`r1^4Csxo&JPqM(LY z_9yOYzXX~w_8%CS0v{snkIT>^+F+N(t at RjmH$g8_^aQB?BYB92XI+H^Tv{m<1hi~7 zTS>mb!x(k!9G=T at kpZkc16Vos3(9UmG)8RWW*AR_)1_@$^k@$}ia!QzF5#e|r%iUG zpOsN}+TibFpSD^p0s{7GX#8)lsN7jEq|(f^6pFrR~OU$s79RZxo_ zxs at BZD6-##>+pC5j3Stx1qy{pL6$BDG3rUg8+Zgsoz^ysLNn)s^Wf%- at 4!tcAK=PG zwA+rsL%y29lwQ6_!F2$1z)~+&S_Ljj!V7RF&A*w{GqCV>x>BO_~0lM=qH2}k5^;%W8t^7sJ5!)>}X>Fn-LTqd*uYDZdxbiREn#Rhi)WtZ0wU4f#_T>Z{- zCMjA)IWhHu80 at V(3!zf%Mia;3YTa1?_uKf40~I<8?w}*Kzw&{Sk`m~z{S>RtJ{avV zv-)UkxFrgDWW(*~Z1`Qvvl}2Sg1b0^8bdDxGMjir?qPAZ$dMF~=ZS%;WIGWu?L8u~>O?-_8S^|oE2=Htd zK%apy3x_D$_o(iC6c}q82s8BaDs<=fCZhNrH~luw9Yy}|su!X3PvPliE(c10HHLw# zeQ6P?L_3vqo|r}i)}7j9x{s3O6L!WkkblK9R&AFJbj at wrBHBf7;1!sZ$1V6?Y#uJkb*2W%JPevmNihx-$ z6$4>8Bu`~)olF79aSIq&TdWSrT_3V5dKIow$H68m-(~DPz=-&Bc{EjE#J`wmPUb2+_YK|o z^hCogR3Z!C=nA(%w?*SfTtB`IX|8!5B*7@#Oi5p05swQ)!|1e9l%L!Gy#95(K1{Iy zHoU!*mcBt!?ZJ-OuI)eL8UA8WbicDxp!Kg4Ije%*{Q6jK;p7GHye^XzEmIiP&0lo at Ob0r-t*!R11*PYOoIv z$r>I&-dGGjvJMztZ^P~vuzy{Ap at thzN@9^Ku^wpK*Bdyet_I`2N?uKHwlWPH4E5EX z(rH7>6eT?LPf#X45mT<-VzUC|H6ie!Y!~3EdcphzE-5|-*Iji02FDE_zp?h0ifVmy-_U3;MhA?ASsdaYQ^#o;K~=(91>XnI=Be8!f0dlG;MAB z7SQTu at cOId1jpzI7#%f)p6g-V*>eKvi|qx7v}!^BBVR|1lmToIByU zi9gq7z(Z(Ws$^&l9;QX8_1Jv%cx1U2=zatk)4?GTMVBg{rb7PWhR$+7gL0c}GW1$j z6`Twdc#OOez7Pj}f&GCkMfd_`rSgJesL53G5 z%9U z0gIrmr5NH7KPci&sgrQKg}?s<7?iQ>jzQQg+?;_6q_{`MbY)2}9qmZSPwtSpaXjB# z;bR5%ZuM}Hr&pIn9d)-Zpf?SdcdKT{F$Xrt# zu7Bx9ZZx=#h)U+>bMA!RM45o{^wqn#>4Vav)AV^fCmDRHN%+3WnBqbZH;a|X%Y}SB zZZltxo8L2Ga+dP-IIshM-2>5Y%fdOd at jOX@$h2NGU&ft8b`j+c#fV1XYAY>0ciHa; zCLJxA!Z1i@=+4lMq=xg=4qNC(7|$4zv5Rl*oO|`;ggr3^2O7(z!2j|wG$*d-j)sDJ zkq+t3yC`>BUM{i7C%14DW_18permLiXUV(UnaI|jp$tEo%(ks_fkDPBH8Qm3C5fxO zOK4-`YfTv^5J4dZgqEVBG{`!I6JTfux$8Vy6PtCq+;45xQ at MMxa9h10M4K1a80#GLh z{(1>88-O1vH9`naFXB>Sv-w&nu}oTuw%5kfh1|TJW$V5Jh<0#ZzB6(4r{vXd?xe{w z#$bS~eoLEj?sF-~$>`_7Kyu-S zn-hHD>Mu9a0#d~GC@}mctC_a!^`8skKAzYJupT3HxW|v#;^bL1DxfVuage_kac+R# zK!2ogrYN{pZva-t%;s20M^m~0;E3H!6YD8xLi-13)a_<+>~-hMql~D-1EctEhAdP& zIT+=NB!b=B%?UA~ojD0+S_kgC)gCD!hCx2W6#!g8WA`C8QQ6_9Tnq!BPH3-6YTmYS zlDUg{^*ic(pXOd7 at bJmUFjuvmmvuc}2*VG~`Zm+D7RsvA7SF^8^ z{88rQ4)KI9`8!u4L^issLs{lBcku|422aSv6(cT>?$&-XpR at aFQ(||;+6-X#Oxj^V zaWjw=Y4>E}_L++#%zVcm(sV~=4emFXWZ?Nzd=|D9X7I6nfCUu21$gmg9x at wdPR8ctr at b`%icl8+v4 z?hJ4zc5nXe4w^9tM@?r4?>STV5FXA`45ht5?n~8h406Cg2CC~_F59}Ep;WlYG_A4m zkVmv@ouMG@>(yGnd9It&`Kd;=HTm1;C8o2l^8t6{+fp&B;FPPF^!;!v|^Cu z&t)`u+Oj&crtqvIS;Q#di)&Nw5fXL(Lb-?H at bCmaguz*AN$VWDXeJCQN at TG~+SbFEaa=HcH8`Pn zEg8gye;b=HG8OcJzk)%=Z>L~}5}9w(ov-o=;KG`NLv-h!;Z*CNB0Ui at u$eAtyveC+6kkI(Wu@$pLH$ut8W2l55JOJ_6B z0G!lb_!gX;7?i-t=QJT~FS@&p?!>UGaI$$&H=JzawN8!eR_jm0k~k?G#BtKH at SAbM zV>a8T;OHF5(S>^OI19cZ^-gbXWCiWM`2rnG%vbbLt|4ZjYu)!|enZ_)pSh-P3&O=| zVZ0{hA at pm{&lD0mBKAQy#D|j22Twx7O62C=eJmWwO$wM`?!(^{CoFs3kd8d8R)~hk zz;Rr!7t%gyuFARZY#5n?-p4pq(5e0YJ0wB2j5YSdyuE~L^Fq|-BQRD8gvc67gm|nA zOCJIIe<)Yv_b$Lt)45H(D^iC6=;-e!_q`D at ii{=4&b8Bo|CoH&=H*9m at uCQW*E5O| zk*l6K;Yh?5h_oXs`-~SI;7=6(dW|AS*7iavrJlD0hr=kAk58z7l)_I9G1Oh`9TM4V z>|jAlP=ws!bAJf-gepVfKE6v~iUapSz>W6O1}u#0eIYFHKANr|%y#FIzk1eurky`*Z|90GYp`G1qOc~r)+UfWg at D)A1K`D-+ha6dNog265 zyA*w&_>QQ(P);oMxl&xiwk8ch1G at 5i;gOeJ0&`4Tjpkf&4QS(!J23FEKk*&~ z--e|vc$SRy-xI?)7mY3n_1xg{?NbTbj}4QUwrNd zK$cl-YCEpJxGw@{i(C5VxEn($z}MvmL!Z$Qk+<)nfLDx4z*J!H8)3kVuzo|3P#JM{sX2PZBu8rPjG&+RVRCZyz zeYA at gX_|ar((7XTgsW-{f*RVHd%6_g%!|*K^qsL6uP)v+28zFvEFL`2?ddP^>5H9> z4bg_52a9;A?mRvak!lX!p>|k;0ZHExSGv`ljWtU;Yo=&lVa<`<3SEbVq^ROP z0IN^0_2&hFAkRKbk at oet-D<8wciuFRZ)Jvo#3#Z0zdjLG;kGg~xD=fK*iSF%Isl|Q zZykupTkK%<+LHH?mG*hTg+u_n<)6?Njy+%_%i;S_EgVaS8I=ZkKOnn#S2_uom6^$H zGaiGTqVPmp-^Q1*BL&79okig`c at bZu%i`PL9#^_-fg{@-*L_eIX5iWnhNrmK_qR54 z!s_JlDckn`79m?_$8eFJortF>%ww1IDxBb7f{OdyREr>qTdTImVRlDb9CBp(0Aq;+ z{q1xLBW!>|$_Q|osTA&ij7%S>I|tI!afR4J8*N<1jeYIM2On2Yruvx|r%==A#F|;H z?tEvUaU<#P(U!P6EG0)~7emS4BuhGfJkT(5NtS6f$B}$#9eEbRP9`w?#d|pzn+Ia- z$cum;f+EH?*g*u`Dm%he{xEKAt3x9>;p+c|*NGGqDB6?*s+ zft7<<3143wUmqT_e4S@`&Z3AAYv$fxB5%?aLd-^A%3CY0u!v4l` zj+}gmjjf=@stDXsKgdDKG?LhA^s!5%?5CHmA8}<#u%8drEPv;t&j7wC&{-~9$C4FL z5=C_6ByNx0t(9wBdzIiKi1X*S;?l&O0HxM^lBWH{Q5NAHjvx&KKqEalxxrz8q$2RA zjrFy01b12wD5^!@)AihG{h$T0tS{+7+px}(mi`#qNqad1qnEZ{-imSDq4yp^P~HP$ zn?eiP-fCLs#I2ogjsk)oti>j)CS#NDVjOr{71R%6?BelJ$);cKM?lP at Hf^&;C3oaM z-;dU1a)1Fead&b*R6pDYSFioxBIfMTop#X-E#C#b1ed}u_OK8dI^jz8Fq8N2`7P9g z=1TT3j`wi*2I%3>yAqpng9D6RK=s;K>ICCO*Im7(;0KbB*iz7C&y*1tSm|oTpn&mm z0&WU*$uJY{(~eI`1TC_wMtI+lBc3HnB=9#}QkVHFmRUT!_SY!_k8^mI^9 at TfzJ;JW z at 3@XHny;p50xptm$cNm5^YAS at P_$qLaq9DFMqnsWn8HlW_$fr(vE z?{C3PL{$oZe>3og5?)$a=lxp-#TJ at rM`73tl7DBanfv>Ec^~oH#ossHOW*>p?}CKD zYyQmKeYcBk7_BXgyOos2(AHsmFqstd1W|L`W$fqo<1XY~T-Hqjh~J^@8pb=GzZr_l z6}6hT23f?}c(a8EP0a?D`?sHT(?elDWTZq at 5(OH}J zEB#k0-lyFMB_kXDg70s-%*IOsy7M{yFrP19PBuV-x>>`pc-n&$5pv!&k^tn;IeF>Y$uy2nhjfl( zgGYb?%Er0`y*5ws*REC%ysC6sY&gCn zd^6N+8BR4PQkW2`;=0$=>qyTyZ{T*y2y=4XYs_^dO4wi!C66>CS?iUs?X3xL`zZ;L zwB?hK7JUg-X+O{AVfh}qb3dUY?FXGX1A1L8Y+Td0+2!Hpt#Nh*hMi9?Gxloc06=E| z^PK_52YL~dk51^CxrS$cG>C}#7F5t~Z^9RBZ1ofQ%jx}f=M#i?=WT?v7`{KioPXvu zjtwKK9mi;Fm|khLeU48+SZ2RRXzU60M^3B+7s%CVf1QL8>%lDT>7EurJ#X6J0LpLZ zNk$6zTdice+yYS0u{fGAp9j}Qfy);}K6o8aELHX}#PKx#Ue`k-_--q>%o{@sWcvtzQj^?($OIV82i6dEgTF>m`q7X;a|zfu%*UCukO#sW89OQW3E zAU;)Y#%J}hCs6r=(`k=PH^sh>HiX*YSUb}T-S(BlEf$|%!)r-;edsgZBs68`jY8w! zD@`et+D}AJi7O6 at QpDN^oCK+Nb!1 zotKw7FE4jqUg^Bl`6Z-iGJ4T*h)V4rvnXKT!Gjzt2RT9#w~ZLsD8CM)3^r=BNv&%A{}>JwM1qHp?CTijU*iT}sqpr0lyKPuc-in>fu|2jtXXD9 zrD)t?Fj)(*codw`MyT&)^-}bd!y75Hx8iwqSYjJC`QSn1Q8!G7*LNklBCd5G+m63p z%Q4w~d`6_~dd|z$YkJF;DE`9qh)(-hHwkNOwqe2*9kR at pC^|uQ;^``Yjo#MBvpg2_ zU$6^C3`?AEfohq*s4cStUNEun?bVx2 at LXy?hzJ_lR$~bc6Swr1a6@&Cl3gFw?BbRK zGVA|iIeWjP?+Se&sTVWEr$*pRWEYj_=QcUJ9~O^l4spwVxRP1fk7;?2>egdUcG+`e zkVLg~IotX)kOA|a7E)n=*)yz&D^`_kq3W6zqF>WOv`Y*2|8Wbc|Kk=M|Kk?=LnUaW zvjwb~Xyw`#6tyNJ(Tb$jv~+2y<9`gxrK_sH(7k$iw}g=23N$CjSIi9azP> zW}%nu@ubn;V*UX;&30we$hLASmGsy8R{GWae zy{~O0+NG7Rp9BBhR=$27{C8XF|G&~o`Zvy~^lme%f7cn+*-~;=@zyT=Z@^@^c4DPp z!}-Y;UP!dSx!++-uG+-py3?3kIID1W!6f_I$@Smr0w>sOG*4lY-H3W0nY-rOnEP0A zvZdo>%ixm@>W$n9>eCX1E6|4NP$3$#kKBVXJIuAve9W#YKNu9-s!c(2wnA;MJcvy7*jaWI4W8%FbJ>=79VtVtJj0 at 4e^~~YzLo|>?Z{aF1%D4R z5_nO2fRT2V^I#%dva4!h{W|Er%e#DZFhGvN z9?X>4_kc#ZekM8mEKsPhP?5}5O=e3yGFvG7*$L)L_v!WS19D`Wjz9&LvuYpMfBHVf zy`OoP9A{Y(%#g<0xJWSj;4?GdW=Kb^+qK; z*%f|)_P0R8xI0o(FNkYFmgk$0&(u0|Q;QUtWw$hoTT+@@EX|Ty?Etiltd8H%R_zGo zw^e(@@?#)EStIp>23S*zUO%!%vebClkc|?n0d{WU{N5Co-3Pp7$3rzfy$XwZE7D^X zW?oJGSPZ)5yn}1|D0&_A-r1wwXq-0;jaZsx_rZS)RK9r!A+BeWpNro_ at S?~Ux0bo^ z;8E5{m}&wImFm(PM>c_`nfwD*>k+pc4*$)CF9Uah9mX7d3jmFN=0Heq;*cVUMyKBj zKLDK=f~6JazFT%V@><2G$6>H?ue&~vpK|a>n)-G#9&IZc$Mh_4rTZhZbUZY34C54c zNBx$1DQ}mkhNOUY^NJc)!5p63$G)&_wY(<3!y^5T~8He zY_d{~v(!aid~Ke at _ITYNT+`rSqw?Ud>5bI}SiRp}4|34_$gNUj_T|byz4FQ{?I#YL zip(-en<8mRE-Mk7a2!iBJ`!X~?rK`OxWxoCQ%7v!1w zy`KT!#_z;KE9w<@J(lg#uF)*ENlhX&>yBfyBd=|>f3nedPimH)=UrJlJ&;$ob{d_6 z7CQs}dRuiyuxFiD=#Bg0Mu83gqe*5V?tqIRUf?Sxv*E&rVMHi4l-#sNue&1}vq&53 zaP^c$y=dqw?hdeGS}d}=U3TwRBEY$7t<4v4^Qfw$Do}$f0;ps*2SD0N at H@&|AIdb?Zj{f`QpA&E)r$ze_VBVyZ4h)Ew^9FBoy(gz=daV3;^16R*wFww&c8++ zmgYiI&koZ%?T8$$MobR|abBCGdgK=N3Y5OTn^2RDSA9f7Ejpf4#$iKKlF zw_KR29fDM;0YVf}22XFcM+wi!(dTCwJ0NV4nU~@dAum%=i*f`!lwz0GaK+dUDpCb@ zSf3ALEY1{I9gOQj=eUB&lN5LF_Tog^&f3Jsy{2F-}!S$^ir48Vm17*3NATu5XA zG>v+}@ub_!B-tD3?*PG=v2Lg#bG+esG6+Uiuh&Z;cv>WrdfpE)cQedGEif4%F at OmFrl>=f|8yQF4vi*rIF*z8PpL}qm;RObLy zvk+0VmxtBGP#(*<#bZOMP|P1L&T9HJ{P+`xheeV5Q8Dxi7Ope!> zpxz9qIyNsViSmvxT+hhLi>|d<>cTU!FsRs_w`g at A*DjaTpjz#A{1iJ4BQNx3A7{t> z#Q9=b4e4Csez9x|q2W#ke*@m1dwr;voO`F8pX|(1WcGlEt&`P`-rG_U6XB)EP2m(T zo0A>@@B?hTmu;~7!wXyGaG=m1UZu(5CtAE<&V~a;+i_z-C7#F3MD at HVK0l);?yUYt z4?)PQ7oX4Rfp=Ric%p|`wh0&78iGamMp_51P{8jaCjPtI`2EEAJq0R}PcwB#VYd^G zyf`R4pdQq?7u1wb-w9l#?<2 at 8Eo!Yj at 9dgma`*vuC#JBI>$9LC at fSIKB9YTvB zQ07aRIUA)7o11~`4DR9%P_1fL(G~Gb(dA+u6?)M*tZJ1t%*=XUY)wVkKhjmlu6xt-CS)JsRvD)4v>Seg?3GlE8ZUzd_{c zFT3M7b{ickB(o^4`X2IG8noAk^U+{SeW0d{=T;xmDxfA*8@)_nHM0An-=aY~1W at iW zMJyj~!nw9gsY~f$V8ageAES|2a3t(FzR3X~d&Mo8I at +fSou17KGEhm0Y_5{0WUft- zE5`QG^A)hgf;K?nn%xOloC;g0ad@{)w6di|-tY#nL}ogew@?btguc9* zFWe)%PR?!vih6R_jSclvZyzK^*5f*F-gnZ)vNdqUntW`pw)Z?=g2GKlbt%J8iOs(b zW&SdIXmni)O1)U_MGOM#LH2DN^kG}R-5k6_+IVR=DDIGtUb4<^(0+NAyuN16GccAC zIedRJPEi$})TNksE{qd62>3{5UU02Ima>JdvF&(XHF4%L2N6J3JUVn_63bo^h@*FN zxfDHNx71gbJEq&)Pq3)F`haGsj%wBwRm1b at L*IuoE^(?oH~=Ku8M6LnX4Ivi?H4PA z9)P>8YV9SM+v*8XjoM-GnW0<5b2GV4#(^}oWH*HK`)d#UlZxA=_V;jJhiCdF^%JwC z?(QjvZ;IUt{GT^B^N~8}CxGVWk4fOb-A&zl{q#H^SAwaskk7h~oGmS=OR*;;mcbli z*&iT{Jq3vxvj=0S3WgdgVZQOZ(fDQb8|($w_#5P;h-6!NWN z7$vK?b$9!Ikga+3q!?}kUXM+JafatA36Tc;BB&R8h-D94Mv96FttYdG6=K+_I6v|} z_lo(Sd-G!O6Qk^$%XDt7=EWo58YT9DR*LqTX{nY#gV%l8i+)g(Jo;e;aRhkbiWZpT zn2BbcSk`*!Uk?QNWIM(wqb-h+(APO|j}m$Vxo2cG232;zkPN!krSu}(XIZLPW=b>I z0QbXwqU&8LWk`6cfldd?diA1BEV~P!BCO1V3uwn0%wu~AFLfz{ARSpx#E7-D)9ez< zMt}P-ESw$(PV0M73+G$mPHnLSr|b2>;qW(5uMbTH3YAUh%4+e^;ep@>v3=TGUmQiBoLLEgetPj+079i9Zp}}Z^IC{8z8VjVas6eqe~~K^ z%5xygcSJjSBE-^EWcfOeCpoJCof|$QP0)$I1YQxxfZN#CHax&%mBydO{tCD1`GMl| z>&cdCf;r-D3@%2N|D$0wt+eppeOCUv$M`+igMQ1ap^4ZHDF*ZW*M)Dz`gNRnqNifHSGYm1C|IpW(P0zP2*>v3K}pBDJFdP+t%mV}?p zr?b%V*Q>RcEek)8 zBh$?WHGbIfEr3hVEK-9ty3azZs7S9+G~hjO;9xq*;#N);^<#@#ZNb at vHk*u45i^wJ zdOr-!lp+NdqdV8Pb%%2foWsh?7{F~h4c(|8r$D>N2yq!&Nikaau>Id?<$RY`o>Z%Q zLn|qgyUNRUSz2LCkyJCwf7Fs6%&T8F3v8EukO$n9WHY at nbcVDOFNGXDIflnNCZr=U z$ctmTF-V+j0o$f-x$5mh6E�$ncM+W77*{oyS3lOIen^6SL7 z;b(Yg1X($MxxvQbmzFr+oh1K~vuZx|fX at OU%@CAJ?7JGA`31k}dIKwjS78=Y0|w35SW z__f$H;k>H at 3;35KceRS;`FLvQ^AwMY<-v7gmdfE at W2T=iE9^31C1z#usl>n(V at h8x3mL{R*2T`4T3~;m)e#d{`#R;IaqB z7#L7xRiWN>Dc2)Y*#KuRX9W8i2sgCd=K$)<9 at 4LShJt>59waQ_p)SRVh&&;N=N7QV z1u!}D^UkiliAHzw+&4%#1e}%?H-%ewbLE~!(3^YTbWg5~=XpLy^ zZaOj`n?#p>LV{Ym6j|Wj~|S4Qzu31MA&(j%4>t7hJyu;Ha_m;9tW88U|LV%b}rp_mC@{3`?A>yCO&Gl$5g{2{n`U@`_F zSe1_*#F%34GDk2)oBRnzpS7LMh~#dzIauW6sgV=l#h|`p;|cTyFi1y!0QUh#VV-fH zZmGw1CDFS(Z*Drx!0eGQ^jps+EZn-3!Q4TBvGgIVEpx!gP03N++4`?WCFeabL at e9O zUBtI;faaUOK-(KIHv}qg%2%WcvkyO3)R6FcxCV&*Ar2(WpPX0!NKdwSth?TQAZ~R> z*?yS6ie+&Q_21(3sklhXLsLy>6TMOqa(>GcB@*ebt&{=FgGS3l_ zQg{?5KaQRObvG3*uTnGQ&Kp`L7KG>0+h~@=9{9WyLHMOdiOx`u6+pJ+{!TiOrp4=? zW0y?d8R9j~Ni{7S0>HH7uCoUxlphbeeW0j-xcK_qewo$eu0zt^`7x39)L|lRi{US* zxAzO$)!VO=S#79?REh64uzV{!+}>P?T6b`Rdcp&$Pn7pd5v$#@-?CVi!i&HoZ3tPR zs~+kT1=dh%|n at UA~V5F3c?olQL0LkMlDrCjb{Ng%!|hND3~5 zNcw(-&CkRogT#74c2!~>gdckLb!#yaYgI57f1V!(%3QsDumEbO_N>tFS|?UaN(hycy}i6fzRyQMNc8oxe{%rG2ewbruZq&{T~79)s_B zYsWq^L}oL_D(oKTR7pK=U3-hTr59Y7 z2UoR&_^-;V57{I=8t-4$5VU!-8{)m`C=1EmAhQNZuU7PGZ{GejJG|lEi9Jclv*L`8 zP at ShRe=P+{zn4iLWY~tf=rOwxa;O_*``TVa^cWruq24w;xPUE^@uZ+0!_k^;R8OQd zm3Z6-!i!|}f_=>>HpfG|;y2CosMQ at H>!k{lPmfA^Rd|kv7g~E#iOg9~TjSLcg67o8 zI<+foAm(c}xHsjej?M?eYjG;8S4^V1VZAj$q>(b4I|Qk8^d!^^FHV)ibBEOR=uP*=)pCaJOz&E!zeMB8*?{9f(8p4{d%O#W?T_vbaQnF<;2 z4W{dLS$_9Ne)myd^rCrIr0iFGxpZbBYI4P0r?{g^w8N}K%APi!6d88>*FAii9+aO6 zIstlI{*;>jq2MRNc@`(Nh zrLqrVsd0%?E;UCC*;s)RzfR3b5A|f5(I9gdD6AB9I_NM5Ac( zglH1j{`0NG=A9JqD4z6Yx5?~8IPg+{9rcF;@A_F_ofMhlP$Ey%N#a(JBxjZI!q?%^ zR!~^K_C_|CO3wYs%LCbs;9rPaaV6heBAeEG>wNAbq0c0Cz1pBlvaZd2l#JU zp;Xy&Kv6ZbH}A;W&!oI#poNZk%MXTb^s(M`Ryy8 at SzTe1PqkPfi(h!dxgc2T at P$*h z4{AOF#+0{#x97F&Q`9PGuW=2ucT{3WBnE1B`cYPAIVf)Rd+Xc>#EJ at BVzTI}EeF`Hg3Cn4*5GaHzIP9@> zv~}*J;6QP!8TGXnl;Cbc+4sQc1;G7ak-RNZ}yzYN0;lT5>n_xy{@{K^(rjI2s$%g<3gn-L{ zuTu3|N#9{P2-$05d^~Ko;VsFQ4nRdJ^S&hGn;iJ+Mw+xyM}mmz34y<{jyXsZQQgNW zoCJ4fh3jRwM|wJ at S1fti1hWIi_`D&fN~VY9KbnbhI942KEEk3XWCY51N`N8E20hF5 zU=h*@zxU>VF$M=R?=vIofWpDF0LzmZNP}G!OI#+T8Uqq4Ks6u>Qp(tFl_1X5q$$@! zuNlLxQ=%m4+yuJo zeu1BJR(t at m#^4Dt(T^>PyINs%){-Q?zMnP5=JgQ-P#KM}O7Ly;QQtjef^-R`?;OGO z4N8AY=?j!TP3fbQewWfEl+K~lL+K<+hfsPQr2?gA4`ccXrH3i4r}P5#C{sF;1Lumn}cTl>3(nXXOQhHYx_`gGG5vBK1dLN}FlrE=~k2ly%`IHt?I_M~-sgz!! zoK{Ldru02ZYbmXy^c6~fLFsdpmQuQg()%b~M5#jQ6iUZZI*d{WrDjUMBwYQI()9N* z?M3OOCQLu0w1v`xlIi0 z(-b|r$y8PqIya>{WK~$SCL7=Nxb|O3i8#DW5J+D}eQJk&&3tjoLEko$@y{o|egLvP zYlbQ9N5Mi2_VB|*3_HLo4zPNk+H$)u8tW0th>mE?7MjN| zEa>Q1dnxpgP|}Ln0}tj`yLFvYkQlOjTdkof6d=3Gtd at DxAqd#F at _~7J%pcB-k)Er>FGzr`b{|K)$hqwiKucB&XE2D+KOUd1dWJ5iW)O_ArcV?@~lZB zB?wf|Ngy?5N1PJkOq~Qu;RF)8bn$P}NAA^uBW{J3kwEEwWNpX=#P#RhNOpg?Pv{Vl zXRUtKc!@r(y1tIn2WU~+l}wyI(Ju7y8~q`EI}pFEn5SVL62YfoUJK?mW8Qv%iztNT zo9DoMf{YUg$=v7L=(8Q@!{Y^BmQGGpgQTA9klF;$$_Ik|B<8UPiVLjm&3-V2i|hR( z5BQ2}X0iT&gBcE{*cHocdz)ktgQ?;c$)dKjDnIpG>iyY`KGs0-gILUjdQLr^8NgkR zxVh$l7S=mo7tOp at q;;Fmf!^T3y$;vNC?d+k;FC0kQ$lC)d$NAE-?vS_LjN`dER8<( ztRBcdKy!4Pzy;vOK>2}S6EX+Xmhf}xp9H7C556t|ITLtJW at pY&o-+V`ct$GEu)$A! zlj3e{t4;}y*<`M;_9?^f4(rvxQ^6F-4V{Yjom2(+$Xy^mtsp?FfhWztvi3DMc7lp% z0?;|M-63u8sa1Bd4EKvDeH(sE-njI!fB3x*js0t5Kp2 zj#!^Lzz5(Yj-AgBz>{6e1MC2OfHpwyBnI%MgQmo3;@X}9C{Jg_Eu3%ch4iTRX9?>4 zIq;VOs_p`hafJqJ_uL~0Z&KtxT?@>kUHEvo+1*QPw(I2P<5^hRM|gA=7?dz)ZWo at o zPIGtGitkY>^@lw_#D#4oH|5Eb+LpV~$q8g>3zy-sUt;-Vlobc3g5?^vlvh30Q>~f`Q)p_~ z!pr+3seOFW^EMyDS#vw^Gk(Sieta0*Zt%6oeAl!{%{7K+Tgw|B>!n7g`mnv(R;Dc3;~z^kC%1*v396}*;2$WqE&TcbKQt5Aeu at IwLtJ!uX z&)H|YSqKhbrFb4}xvlB%AXV&I>q>kMewwZNZ{Szu&amSrzCjaJP_eXEu~<*-kHyrs z9Urw(3+7ONmCBfFXQZ3rDWb!CPJGg&kfh)+mOhp)fDytZhx#Ixyi8{!Mmyi3=HK&J z*nNMt$B%LdJiS1Rm&F3CRdc{R#8a&-f$(hsa5Asgs+R~toq&=?d)+SxrB8GSu}^4o z$(dlPq+T|!e;-oUlZU;VZt^p4OSbNdEHg=JC5EX at 8`ANZS==tT9XHi!Lsp|+^tQzN z`dF!l?~UCpZnY|EiycUAmp6 at 6^qP1T3l&JEm&S!`>Rxla2VA;CJ at _-+z*e!CUiZIj z;)`I|zxezN4pb-;N at oS_(%ZO=ES^)E_h>M!G_MeI5QO-R(%ZBd8G(0%(y?@?FP5 at F zsSrR=3^sC&Ilwl1=m;M0qNVn)WLA%$dNBqgv3m7{HP}-U-`TCkvf at LejV-u4HaK32 z$gW>w_SEawS-|L0qYYBtp0xwiy>=<@{F)m=*1X0?hNye3faB00Mc?IVtF?!&hdZC> z{U}?HF98SpvgN#ihKTeQ(BnxcWDO02)D)V^YSk8V(7q8>L+QGnU>=T^@-98%(gxj) zbh-huv0%`q?$hJfc{bI$%x%qs_4bb>%OxVLFN`gjgXZ>+ke0|afmZc5#5AlfJ~%;r zPtFq^_|V&Ga8z~`o(}E#<^%HZmA&jL{#Hh=?N__a0v#E|4&bSmX+5@@g}51J|AUul zbtVVTI?Ex^08)s-}jqKbC< zQnG1^4c|JSf50}Xu(U6C;i2lfb84Llk4hV;)#15k__eK9YEAh4yNBT(=I=Ff0qR!n zGSe$F8QN1%3Bop9>(SD|THc0q(ze`=4W<2%3LWPQ;(pPKk!Rz4*Zt7LHS+MNqMmPA zx1L at ZfyO}so`+Tf$*u+_yZZB!iLPezt}=Jgw;gaeA#9p25RA>W2l|lt(;|Ub3%jC$KX%aiEP2|Ujf=S2f-_-GAsP27A-mWL= z at pxO-r1iv;Nb_peR^sB#g69&i9>GIA at cQTYrHZhZw$z95F?_V#nQgmF?-m*Y}GUX7^Yc@(oEOES#HQC_<=UuTPAS+JU6#f zVO}%WKo5SAeH;pu9~A#DYi|M{Rdqd%&q at YJc!OpnKq65FL?Rd)(S!lXgBf`PGZ+Ol zDhe7!6s!?uSZaX8muM!}r_^d|TUxE!ezn at xY6}4rvp^O=6XM3=0=T_lK%z(%mc0Kt z=f0UtLg4Gy|Bugy%zO9Ud(U0ZJ?GrBJX;05bEpk-y9x9Ec(8P29IvbH*8oDl9qS_M zB#@x~95hw;9; z at Ha3HGg;!X>q`Td*n)QT*=|4&nb6N};w73RwZ>==Hn$3*s}6VsE`JZCqwm>^VBmIY zj+xbjUY~=);cOF^&nIj`Ax6Zy3Az4-p&R;zt_`iQ!-`sATNs*e3C$lMh33N&nx78; zQ^*HxXnu0|G&B(#gyTGhyAj7#79~D;gJgi$zGryjNR07$Lvk4Ky#XqOYN>uIkJ0pa zZhy6rxEmDQ2^**PbC(933jzsAPEU?Tio8SID6iY%fy3P_U% zG>1X2${XT_x}p9`5A&ZhLt*zSr1K5#;FiCs{)RFXhdkfJz at sL2#a#n zuW73eQ^(vyi{E%tbWN(?iLkivQiNNOJ`scmZZ+TbXxWf<1tz{ujr#GjmPpe~8G at GPY`~S&g z(9aKM-PL9?Y(cFnl(|---A}{{~{| z>;>voaqRsP1IktDv*%@&8k|8Nx)YI4YJq|9w<}=v1L at SS-h|2wX!i!Sqk#V%iW-Aa z1)%e4!K)YprWnuofK~nX--t at A`PxK75&r(i9=cabQtKb#i)-)F>(GAxd3 at fp;ulEq zR7OP{QpRqn{jgMh(oBmqJVo&hwyUoLnImjooFeF;m6 at 4Q5;yH_qag-kpWKBe0;7o#?OD=Fi&iQ_$l?Mzdd-`oX;) z?>R6PvHbKs6iH+Cp3oi5 at YA50p2J;^#fEGC=9RD(Jq>lRTn9?Z+y>yOCjO63Gv$+w zGwofz<+6F`HxhQfK^jV&r#j#Gad~*asY{^8RG4%D at t55KVv<6C6G=o-Z7=!r@}Dbz zEB96Ve8e0NXz^X#+b&$&J2&sUu#e;(0O{%ntzKU06qJ0zG^xx>EHgZBXxY-=!N ziF^1m9o3)5H>0Hb^oqO`u!N$Z;;*_Aw-MD)1Vw zv?|yxX^mc2W5ALafb=$`Fr5?3LW4>DL{}>QX5-w)3+MhJp2w>)XT> zIWSRec!8L0)}davgR|Xre?ldHb#Wt}$*V}Db)m#&lG^0}b<%eTt6+>lE=VyTKaSj1 zoJ_)wra-o+ECmY3(P_!*;pwq7$#pSpi z8JhEc%oRd=`c+wS7E=d6VNLll`1c`lfYA~dhDrzyKa9ea>XL5gw_Y0+tK{L at Sb%F| z5$Q0-Xi)6$E)*6uXx{c8eXgn%TfOYGSNNAEwu>o=be(c6(9gr}cSib&?~uC2t;=3^F$`OQ3^Z=neFXT`*HSJ#=eLNazciI>ruU}7GS^x z_G{*J?O at gb1l9DNQbyQk{@zu)Y@$3XC0)umgEiDc*TN at IlSKP_%ku~xclDBayQC~hF-fwPuoOr-zfm=>!i9oCx&pt1oLOyk z=81l0`4JuEu_h^FCt%yljo7)#EBUn?)8${^{|bK1fH3Q+i2KKEER#`-w|vT+F-A3! z3Irw0ybUwMltF&ED`Dv$fc_~ia!Tmm1lCrrE>7-^3~`K$oGTG2QXGt4cSet7^>veU zFQ#TShO2P_{Dkql>KlFh+{(Q`W4uLiMU^!G{e}f<;;;A>D2$;IALV)*45Ak*#&Hbp zr!jnYMQjX%cu!SQ2W#5^qvB)Nzi{?I{00 z!)=mW2hG^yl}{%weeVCsP-gz3ub~`~dlkj_1Eu_OT{?%EChNokU{1Pty!ktc=aT+LduL at LqHV*pt}+LcN>v zJ;^;J?ons+SBlt*5ay+r)G0hoq6wa7Hmc)!LS8H(4HJ~t&DA8Meoy^6NVSoO_jPnp zQ&~k{KBn+Q^rGIn4?BC at m(k`^ewjTpR5ZT94>U6}Mj4;r)SEw2jlsApcAyvjODpCB zNhwM&&J0Z&@5it?klXwb at zepHdyt;{@fA4h^lIWQc?H+^09Q160c=-T9Wj7+>-m at I`7a`X+r9F(D8Ms`OP`fOTQW(%_c1=maR4vT zD at fBT_-J`IKq!{Yi{Vc<(4)(EnGbbA$6tDu$>n8odz9Ik1vo=Kv_WNcTqY5lNbOCG3XYiS6V2NIcY6;(L81R`!+n zQeTNrj_+%SuIw}QZcKG&16JsX6!5YRwrXv6pe4Msix+IcUU!^^y&f6juITS6ZA2G1 zCSV-gpN}}D==pMUQ zEUwM;ln=$?P!-!(*0QD_RAgLH?`0SGL#TFEVG=9)i{-}h0mLE!i?VxZ3o!v1|8gI}qpqvD~Bs-Qjh$ER95Nl?rOS zF5|LU+77AUq;i`PsQha=Fs-IfcwT0RfpnLrCP-S7wi7 at G8@*7K(crz at 7%}@V8LWGk zh2H#cv8^)Q!d75MI*IEF>r!_4bQI;o7NPW2D?RlW zN}uOXDMIN7RQhl#hM3zCxI|QDS>3MPLfO-pgGoRF3gye;S?(MXe&2*a5XGE)yYR%_ zRKrU9K;fxd;L%$kp{gL9BJ7!lX4-;2XJKTxyTar_8}ad&hZ()*kKN at 4zY)0M{!-4+ z;DNBis at It!JTVBKm6`p-94SS3%E)U?(QBR4klm}w{g!i7S;Ifn8Af5*Li%J2zi#R7 z&|fXoA>pa@@POi=vF+jAC-s?AEH_mjFl97U;!z{G8^WLQ0rU%{ZOFr+>i~DgZlQD+ zA39TD9{s&mL`VF$QJf}hGI`}-dVJex2+a4?J1iVerNVFc3TjktO4fczDjx)Iu4>__ zev~CJLXot{u;}1?kCrktGT)l1Cn=DgDm<|l-%3`dqPmUn)J~o&wJ5{Ga#KlZM{HL` zb90>9P7T|)xGKS&QRQ}37nw!#=WJ)V)4->_PH4E~R2C zx5INuCm#`X=Acz?Mz3;_;gBIwbiFS;@ek|X28-MOOE(n6r%NmTXw zQ<@fDM%P_SoGX3o9%muCKU?A)A!CvcbUgIjK&e^aeVk6L@~s zRA)%{8L#zfiB2l)V|C$g&uCg!OQbfssgg{wO@)R>ahqyRLt(Gw|EcjD%O5R;qKgL2 zePTNb!^X$$sN{xTHCCLf#)pYclk7OO58w at RCp7RbG#RfBS0M)`A1)M1_Zgyd^}0Sq ztMHGXwgqb2sI!3lR&UJ4=H=X(&UOmVR`<~iGZ6|2ycsZJv1T0R>o6Icfigf^U+v-U z<+Zrwo{Syg at x*jN7qj;F+Jn*gvcY_Xmz~D34==$VeYBo5#Elj%N;WG6vmQL7=dl(2 z5~jyCWbJ+UGmxOHy+UH^IMsvQ7{a>|$n9e!zlx0Yv0@^1*c{C3sj%TenhZp&-(2S| z?@!$wAmt1TekGDV#jo4VZ43xVI;1_^Vi%%~VXhRq1E$=X zU5Z!6+og~PR^&gPqxJsRbwtqY_p?r4$O8%A`$7-G(c`zfS&N at F00%q-C$hhn{Rzn- zG7_CF7t6 zgOMXQj)D+e2=xiO0KrFwN(Bw-uRkRRe>x*Kpx%JYIItUb6hhu3F^>&f0UcrG`J at Eq zCf72oouqltGPjbiMTUFjNlwG^p%wkSz_e&}Xq}vZ_(0Tlddl{%Js>GJw8j{HWq&k+ zA(}(_m>>QJ?LPLPjSqK)88-`Bsrd=p%%D@@l*o3HX7O>a`3KRw!)tEI?iV-?Btw-b zciba9l}}SNn(%7JWkTt1Y1ej$fs5d;6qpNt{ehA2_b#FAm)!XAl${5r{hw;0mc5d) z%o at 2(YYbcr|I^^VfUYCZ{r8(w!-xjoygR&xu<^+^9}EY`#YCV#{I{X~BqdAXJ9yoH z)a#zf>$X7M<~Iw&Q!roYj=*xsypMNuu_ at ZoS@1OJvcPO%Yl9c??xwA at dOgZ)BS!A_ z=OjCq4|iwZZWKzhAZNuuF9V{hw%q174#B~OS4cDOizQ(F!I#7Bi2cm_!pBG}xf*!r zFn8nHvzr(X_)Rg4MmKNX75<%(_vfClLQl=|;YC2~AdWn26-txop`TEC5=I%e&?rnT z8$u}56tK&k7NM*^)^uwa6%*fF6~3M(W|eK=THJ1#(Orf(Lv#Ti#Srl{43Dix>SXIc z9D)t+oO1}Uh6*#Sx7u=JYzTx3bL=gAGFE3R)k(v8_qpr*)X+zrlz_u(j33rl!swq@ z!$@O|0c#{3$7*)uo>+o_3I51zc$oqJy#QHc4eHl##{*9z;6o62px~_eq=fkSjAUY^ zUJN&j0(C!Y^0N244{h}Y?hO at Pqj^Zv>vL>sAPKiv_zgS`sv>5LFTwm{q^$SU-w?aLVYpJZcYx)Iwlzv-?y?WZ&31TR&`#i|38o2YYV>FRBObl0te%18KE zg9nx~S5X`O4wqR1T7KgINv)CS=ox at GlhYa^S#pKbw3t4CmsR=L4*mMZp}sY~TPg1O zi%HYQDU#b43EiJHs)ulZLuPWY3N1-cOP~ZZ#Qd?$aoXcAzV)4zC&~9V^NTrBK=ALu zn>jVSJ$fbQ8Xp_LF&FbIxtVk&r?1auQdIe*-m?d<tzh}JT0Q_%Ohpqyo<=?~h z;2pOgm2K&cyE&^-y}4Y!*>2K2e+N4E!(zr*FiW>vh~)Lk(4~Ux-G8X z=gYUNcfQ_wH at PY5x}T6|eOw+|d%04Eh)f%k+{@Um$S zUJjB`fm_&^nlF}oiJyy$oY}g(JX1#;A~&(Ry*3I*o_y?2NWK*84PF35bym5_AZ)bc zkHYeiTd4_IE$WZ&owpI<&uv7nzAEPcgGd#??7NPGvG)KYe`)*)FyzSz(SAa4>&(Y_ zKjj0)$j#AS4mv;h+kY1L-hF&^SKmNP97x;bzJZv2QXfaIkL%-ok45`v>h9y%^MhaU zv%vT61F>)*7n}o#iZJQckj!2=WoQTuAkY6UVS~$*f$s(2Q$^x_kh}d(tJMj z`?&dhOODQ`t$RL~pC5ef#GeDccOM6z1Bjgix$_)A>_4fG?76r;Ha!~cqrJP2PdA(w z{1-Vt2Yl~7jyngC1dhgkmDBffN%+ZU$xFYBTeIJm=xa8i$64}9{dpU4BKv1HqE}zV zbAY*pgL(2CU~c)zeckxmxW1k$*86%(kG{TLciu+y|GACm)z`V_05gPxdGXr5!3_Dy zeckzNTwjG~Ux)PQYxDN=HX`lkHlkNw?>`5abiPqGT+{bPN&iXv^vh at B_UUD7qx&?y zd!HWOc3$w;{w(mjvZ_it5h)8#SJlb~*P_Zy?|wgg4!}AIwspd}NwBQOY at ai`CvZ>M z{-9MpH9u%2-?ywf+7zAlVSCm6Cs3-4ajPgFCxd#~26wk_ckOw%^~L9CU&7CBpRl1( zEj<-&VsT$hjQ#VmM#;4!kdE3ex!RY9Njvlt$@N75b-Ds0q>L}Pe;sHaH19&*ymI%2)Vjk`#u=~c^okdK zoO=x*AFI3n%a3{fJI>|iWRX~M#11r%pB;oI@=#R4OHd0eRsD8EjEgSWhMCZ!?2d4Q z0NG)TzQ7=2`y~0KNqCgVkkEQ(Cf){y{^QK1-?yE)7WCo$y3>Zg$^)7Y(ojb26aID7 zXAXO^wC?dhozv}J_P#fxPHI0PDTPK!?y{{I?PoAG+c7#%MHg!DHwoot05^*TPN&ae zub;M~B|?p~`#VYa*9ot=O=2I5+J|LTYp&snwLVu{Aj8kz_hr1_!ynAK<`*Lb;XGg! zSsb$8bs{hZs_T6#%68-D&s#D^s4nWoIONZ~7?IPu&@Q-I;mR+AMv(E_4gBcFJ9?bY-HN!y|$RoSh>q#b=A<3r>EPn at 6 zu7wo!$<%Y(3#$*O8n{*UoDiA)4NXO>>c~fGe)NNje=yJoG(+A3`0nN?0?PEVJ*dhV zMr}^svEg{7rKY6DL`2p^@{oH8;?=6M7UB0OTKl|P<1^3#B|gW2T8WJ|0nfXxZ5o*EvpSwM-rv1s#kq z0z41okCxK5V7bIy&PC5kn4h6-MuX;}#8+sAmK1=f3WFB^ZL z12$5GHO=w(<76ka3E8gj*14!N$)BH|gU>v_y83clMGdH&xM3<^P{R`V at 7-_n-=&-Q z at 2t1zm;0N#L3koAA+}` z|A%(~=xr$AR?>FjyegA-!B1pRUjrsjuKy<*z>R={Tj5E)p92$6nXXY(@=TiJZ;&3v zT5)4b_|%Qk;rP4wTn{_I_PJRntpW9)vkiuI^5jc_e>V!H7^0}&ItX9jqq}^R86E)v z=~|FUPJpC2t}ElHmF`>cs{1AWwd)`FHJ!e8kl at zG+OQRH&Z_th`1F{KV+mK+(n7WW zWd?Nr6f{M?!G!q|6Ew$xQX{Fz9vO}FN`eLySkmiMa~=Nz at 6XWt26*?mjt8wiml}8* z&M9s}&3`jvF!i=X{s2?5`)w)Jn2hEOnvdayr1KBYFm1+geizcf z7%pk5F+7t#?IJ=Ll2{EnXzkw1UtCAj_{vEX4U7C{U?u8>U3wgHvRRqD3>(Sz2CeEp zd4cJZbT1oxvmOAtyV8Ff#uBpH(={!C!OW$Cq}+50*l=b9QWp&+Ie8vHf?rh*G+|CL zCAc at MO5TJhbP)2Tq^7A~Ulz at Jx1RNR%xb55xmeZ at FzaE!Y3tP1TghB!z$OgSpgx9Xsg4DY zqJI6_^<(%G8OA!~w`n8{K^uJe zFC^|#cjAJ@%dz#&O3oDEOvG at cI=_ZrP=s&d_9kdv1k*(!yOgA(YjGQGEWvGM-BWC$ zOT&D!>YamnJw9i?T6>R?lJg|F$eCvdh!Wb08K?r?S3xE|zqiIqBe%rNUc2vgBty*s-?zUUe>7*ekC)?J(^y z$gLC-*DB4|U1XFUAWh2-_5<4sbWgyl2CK03pg!sE#CfSlX4e1HCTXCo{3NSJ~-Xs1#NTf ze!S44Xl?4Jcf+KlO03LAuI$Tr&C$14Xmsffx>yLfJ0OKT#hT;(wMH07)}c9WS!<*Y zNSedFmfWn^%d}vkd`g3rzmwmiF$Fu1-V40{;@%5dNgMa}F-hs^lMdUTyZae<|JzYgx$-d%o0CNBYNzxhsCq at mmG{ypsc*x8X5wEF>^u$e&sJa at _2G<>$@MbakereL& zp~XhMA=GoQq8r`_-VpaYsR%HsW(h;k2AmybxZTe#->GQy$NbBpiL|m}&Mhk0F z^o>^3HT1?^AU!&r91WE{hjLD3jTs at cdgW%ov58LA`L^yB)QC!YTJe-|!34MROCuVI z!JPkl3kga+_wTo3Oym%U{Z?k~hMbCoNf|<^3a=Aui~8qItP`HZ(A>pSCI;`(OE24k z`skC~dXwGeJ<%E>HYl(bIMw=!go(AQf51}X^-_}w=Kop*EnWwT?fawOg{=v?za|*R z at qX&%=3Ekg0(qdixYkx$?`8TL&`Z0b0~{UOt^x65dw|{|w*lyIKUA*jRmGx{Xr9_D zarVixGfwFvEdvXag^LDEnIyvLH~At3)%*_b_9}vzTKIu zY2Jdcn?3Wdz+AH-asi}m>`t2mX`dpj_RYP at da|0yD+b4*u z%AK*}_wpgLxu&|qBw}dITG8Bif7OGuEK6;p)&r5~a~Ae(Sy8>XC4o#UYT)EqDP~le zYuv7ywFw?&j;S+ZcAJ~!PODJXVnEI&uH!qZ!z0YQdB-nP*m?ThpOyY=C3ZFe9&+Kq z?P?aDEHQA^`^Y1#b`*_sg4Q56oYtynkkLKa&m80XF2wPyhVgtnHpa8N({PO4=4YIE z52I6-i1Iki$e(a+-e09ctIQm^iSlVGoqkcVaXH*LkONK?#1a&?LBt__x0 zEs{2QkaY=VeE|Nd2m29!F^whN4zI8y^7PspDh=~STSG~1NM1F-+ at K|015c4eS3}XD zj0Vj*2J1)~P2f`S%Ts3^+Mf0vwyY^qs4#Ysu>h$eMY3n at 59Qm{jD8#;6#&_qvz|I0 zOywGe3xKjp_p-(4_A(o(D`G?0iezq$?wY{zO@?5iYr=2fS1A1pB<7?oUWLyW7?BxE zn}IJIlWw3ND}QrLfgd-dUb%`KW#)y at 8yOIqB6}~G2_GD(JVTnD|5^v&FXYHZhMaWn zQ67;lvX3H8{C;F5<#QZbX(EkvH~}y_Iod$odpE07Q%|E4v!sW4R_nbhsYUnDkKX* zua!mp-Ei{DU5i%>@L&?zc2T*%pGUdN2pRK`PRF|@WRWO at J%WG@&OU-6qS}bgJ4GSC zlFwCwkJCNa{r9pOp|F|)C75I1&Cqye{StoI4XL85dG)2P9l{g+(fq~LAUtJ&2iJ}@ zBjIKB#TcLN`!n>V=(uag+GFsr#)kR#qKm=lHryK1E%-NquU^-VpxtF%1+@!*s%5p| zw;-SXzP>i{UH2Nr2B)j*f82k7#Qg0PWs5FYw2CDl`z)@gLfj9nn zSZ-8n4$Jbi(O5)%19Gn82`8rLnYw)?Qu>)(^5V5q-E*2eB~oI;lx|OneZ|kq(#WMJ zDTJn|FIu`4LZ5_QKwlq46RbGj)04R_l1swcVXQCDl!)Xf>OmC*PpBQ z7^?p%wVOqDQhMi>%Wr)Dg$7TGJ2WjB2)|eFMy$NuOMbGF;@prI)P!cIimXMtzpD73 zT^jmBSFCSA?lR3MxU1N-RIeggA_=0o1*41P7>iDb87)%5j?iqom|-aoO-m#nAminN zbOXOCNs_p4bqNqT9&U)r62etiDr=g2>`JO7pO`LFAl{~W$A(#g#cs-xqT_Y~Bao`O&2I?f*b z!h=pqM7h%#ybQ=JpE3&D0VMhn^~^PB2~Z`4`k at B)#aUI630S;ZMX_0Q$FFb29UmDk zxoVduRFZnX;AfU2bl2acp2#v7dd~wZ0+wBOk%DojR^5nlAH^EffA7_QkK(USNjh;O z3go?Pw_C}zxdsF>v??#qT^-|={-B6Q<&MEC`c)>O6se at zt?2_KcMcMT>#J&|=S1eN zw(#*(kC9)TD)bv|O_&V?gGG|7?A#Y1es7BV9=S>Xo*aiafnR?uE>C?d4~)dqcGLiH z{Ocxu<6-eBd3HdoE{ydaGDR8uSUm-LJqcu$92u_O6j$*B(TeS%l&BZKcz at G)m#bcK zOw*KU7e&(4A#p{oj1^^ukU3U31~($~g1b-XF5GrwcZbdi_to#BaG#GWx+PY$2i#u! z4fol}*wJwxVBF|Jn*ALe9cXYEe{`tN@~{^lxLJZ&(xD$6ouF&-10H4cS~td1WOR zU>9=%_Ty4ifL%z69N#mqg&gE+j`jB&4OH at M$h2=)T!dkVfcIk-uwv*p9logtEFX~8=B4PdS%_L9HH9$6Yb0XdTDV{>4sp)nCjbjSk ztTwBWDAZweXz7%VoISdWB>YhT*h9^W$ZwJE`w9` zkukst-chUH+2I~?3?$KLG at 8fffDi*0N^)ftUhklv*XQt3DY9e}9#*P6fhh0idC(9X zAy?XKc~E339{kpZ!Fgm+0us!XjB7~ ze522e>G=SqV7=9&?-sgx{z3I3PT9{o&@2uu+l=TI{v!0}pp09618{OXB^L1l8%beN zbFy{AX!9uM!Cc1Ng#S|WULchuzojuPvIxsFf-xwGpY{(WiNJdxZ z3P(m0)Ol?hG^luh#cTf1o3Sf+0;B3?rvyKcl- at 1W_(4T^iL-OC!p?3BP&*|!=4R|p#h z3mZhEt9ivx*xA&;^hk)_ zj1PmYxHOiY)jw|qvLDvI0`L;j`tXelr zW_Dm?kA?5xi9HrFQ9V-aS$+r?q;thJ)+x&GY3h-FxNTe2Dm)n2pK%uhsr<{+D91S9 znr0D7gD?e~($V2q9w`#-0hSxr-`#YY{g&_h2C+eNXGxXXmH0hIYk z%nW4x2sn3Iwf at 1udXm?*3-C$jAJABnn$W75+a9AJLqZuEkhfWf`%#Uh48w_UMT`Q2 z`W~GB>)13)$okeo*lp8nA?rWsAu(iq6(2qUCexyIX?RB`pR}%a0L3G0bkDRe6hoy_ z`F& zgdFt|ARnwnGqFoH>{3!8Jo7G%rY at z;r;lc6bLV(iI~j6^790)ZFl0Jr{4{_ryVaAw z*EIFuaU^$$t+Hmp;2jfDtClVoNx8TP at 7?dwjb!hrjml^qtU!58 at +J%aD{p198ul+vhfxFQA25eKv1iGKRkFMWCxBC22A8R<7#6 zgA$XYjlTLsp#Ez+R>M+y<~Z}a?i{OYCZmcL}>>G^u~#Y24XdllnA&#cI^Y_%ruBX>IV5 zGxNYOc at qu;w(D}T)}{>Vt(aMPB!4R(Xsd$RbEdZjE0AfmgkKmti&RfOyu?*bvD-i+7nY!A}^AY!#qS$A?h1Z~t^ z_{6MFLnXDlP%9MD=3*M|WtQ|SNJk}-B+W4$QspEhyT~hRIBRToth#u0OvO6+GgO`^ z!5a|yF1w*#OvMSTFTpP2Q(Z{_ex}uxpd*rLP+VbPZ3fYRGDp99;tT-D zJGg*8hqllNlxe|1fb%L54}@esC^Ra6^d!`P ziYBw}Fh*HEynf%@fM>~FBcps^Ad4jxATZXfImS}no#8DaoqZ6}-%a8N^WMv8 zmKdkhkraobsd$zSK^ahP9D&|XedRZ(Le`{~j)~6VA9(TTECw>jm*q(eH8uG#Z0Eo* zsHFtCLRUv%kURy$nn8|ZCu6gkJ%(!v`>3(q1bj>`!;&_6`2u$0h7dHz!!*?|A+`YG zp+$2nqFLFgKEvH#aGo9Z#qGEU;5R=On?cR_01mXu(R6LS0I=>|G~H8fN7b(z5l)8| zkZ8GZ<*sp;#MaDJEa^(GzGm8PBh7+~c_gN{Ph%xN+!k9iJVbqh`Uv at F>DGTi^iQf^ zWhcG~)mo=+Pfhu)lbitBSxW!fghv7LOv2wJf0vd1?#V2O%z)>Ek?y}_y z8{StJFW1>xXv+n;<-zRS^3^$Yo{0vxGQ$`d2yfYSo*aW4U0nDN;O&}E at nkbGnHXfz zf}lBv>`CW*@$X-w`^w~OPw)76krZL0CtV!5?X19hXt=@E^0qA?*F(gK-4 at gP8Js!j^-L25MfB+Bt_O-e8|+cZ+IhWm0bhuW{!Ny7)X~-nF0>A<#3c7Qs3Q2+(9Hw zln-ANGwyni%pn3;5n4aa?U5xpta+b8qGvY#rh!`(sIhmFEvbr}Ma_-+}?iw{)$ zlY?&3eIJ5n;RR5`P*1dmr`lutYmd`ls7z}8$7Xa}LV-7Tst2Cx-Y4PNJY;(}E>$ll z(!GNgmNG+7FTXfWezq>3{weabYWSe$JLTuav7lJX?(UD%YGYI}}aVk>{_DO_reXEop< zY(UmgAUqozIa&+V7`W2dN#b^#DPqMWXW7xLg~|-Va`?NPT_T_H&I1_>1S0^{V`Qy3f={k z*q7a&TdD>6K`mDV^YmWx8fYBUfmBU!1ZEIQcVLL~QcWmD2j^a8p3|sp4_o?DPrRL= zG-$omBIDfq^rWvdV>d(U4Z{fLd`X#>i&K(@a_fTpz^4mD=M_5Xoo5&d{33OC(7^>`Rx+z-P*#R{&E7V=S+TacWnwh at H$C93_UN*?9+zB;as9yD3oW;+40j zP(6O;*L_OeK+w__0W`lWQuJ#ykeCfLe7?L>L)3L4t8EpkjpkY;3vS3)r!ySb=?n0< zy^!sMZ#MHz`nEvLV5sM{b^-j)lR_)Co3f!&{P1f3k z(kBt;Oqmv(<<7p(7?fZ_|F#|Gf-s*tdkC%lG?cp9+ at X;R-Jt>tDl3 at Xq0u;aHyL|+ z2ZuGRe%C^3ML-)4<;u5{W$4ASF|Y%?Q0K^JI8J$)x`qv7pQwZM#HS40xC6H4C$N;& z4JYwNL?}}!^BiX;isva at UY>fWj+fa*-_SMyYRjbz=rMCMLJb)aWI7)2*;4|8yd|fp zEml7}9Z8Us$xqHT@<#ZT8;q!%h at aJ$pQdgv at G%@b==)&K%zJrQ_J<$g8XFgq>bqEJ zp$5FK-U{h{wD_g58*&j&YJ;7%_YnNJDj29%^aB0N3 zyJ&BcmT!e~n(=CBZB>hDSJ;8sq8d2lg{wJ+P zA4Nt0y%8AZMGM(z#>e9Gi*kpR+tsq^$sT3FuTVS7$orWIJ%auCXtmLx6WIn48vdw< z?TTJQjeUX6)rt6RlZN_qm)KBZ?$ve$k4el?HwpE+{eb038uLGOc)0|_ at l18-$zl_c zs(&jc$4=8N&~4r}_82CG9!K*GQhrFlK?qH^%~ULFfv$MCii{+*sWNQ>H+5fMsPBA(5538fEVQMyR?DWk@}i?}w?=|`#R2kORJ zGTj_RTHt?3Mtv_8(2QbTi23AgDWX>Aa~)U%Tx#l_pA z++|&RHJQp04Yi#kw|a%P;$65+GDWi1FL$SAs;`}*%^omeaGKA6Bn>1=S}ptvW$5q_ z&x-#TxY5BPVjiBLF-44U;1R-6*&2Y{4vd<0%{Cwugt8l<*ttXkx>exZY-<2m z&&y~k{;Lun=VNv3Beml+AHY;J?`5-XOtPrkz9hrIQOG5#mpw|k)q!FD`#Vl?ZhYY!O{e}C8o`DnK3FP3JxLu?l)XW)Djqh!!fLTI1Vn0 z4aeWUjd6%0E<(R1+hG>*!)L^kk|A+ARlm`I1klmI>T-b=4G5lFpBb+jsi1szddWo#u96qj at b-Ctv6jCPjTLuH1q@nPd z at WdtyajcqS9(?6)FyidoS<*){(Q-(bjv}m4^)pS~-NW zdUzW;sW9>jLrmDajWA!5Jo&rJ$p(EM-Ep5b;2k%aU at 7Aq&{py7Wb{FrJ6pzF1!l9NBe zkS_h2B4X#3|Hp}5&DE!pa45*S6pc;MjHrs>XpU#xSossQ6!0vX6XXghxLCN+XD`zP zT|bpZRIRI_H4+%YUpMmcNRub;x(uzklQ-ewP?rGV!40|ZJ`;;a7fKp at gKm=>vm>Ql zqHezc*J;uZvv5lkxw|b&tKgZkz=rz}zN(K5?k%dqxI?eC*oEjG=Od`+DiIaJ_DI#I%wOEzqZ)L-?z8xvrr zNEu(K2K4KB%MkG2F>dw-nBV8KwwcImyL}u1ebkg-b`;2>Y{`$k%Io7fb zNC^_3u}l0wTToQq&6A0y1RiaBlz9y zXP#+4zOwI-!G1zw{rnk6B-Z8KeFlBn7y1j1Vph*q9C{*}n{fgjs^Zu=2t-oC!l^k| zFA_ at sg5y6mCvlPP#+^nd0b2-bd_oYRWOPZ at nz{W8Pu9^gO(;hxr!VJ0I1C=831|o2 z97Gx5J zvLwrOcwSJyN7?v=`6H2~(2~gHSWCjo$dK`#69#{1d}JN~70OPb%uHKlYX3r+ZgSNN zPXy3WRzX!a6rZa~kne<4zHVUuZcESwz7h%q3YvT&X9EmhgAJ;M0bd0W-8oB~D+56s zyuU-Ktt6sU68o`_)nD~9#LzWzKEE4R&{&;y`0ENjm;mcSA6w<ozwO5B<=sRy0|JklG*4Vk2)xPxc6;iuv_v-PaazG!n#94FQM|HpB# z*4be|a$*$AX-zRKcLZ>1_(&X<`zRjEZBF0~L~j={5}HumKT(35y~qfwISFW0PYl&1 zz*{gNp at sf--1so-CnC3UWarBn-vim1Eob+C)7i+*U41sP^M$TNa<>q}Rw2HdsN*{f z_m>Q>U^OwP;&;n28Z$- at A4ce zdXATUgwZ;4Vi at gdi4DS~*Cl3b^A)H#vr{Cto1})j)CE;KImQyi;v%bIGRI_XW3ej&|1YrE_?#FPn{STCVvd~iVzHCGvDjmMVzI(_EY at YxvDj^W zVzHO9qgX6}W4FYtUu8>*WKuU6V>s+){5s3rjl=Rx>LYX!5xj{mWtzMhA4=vq&O&$j zSV^miA+fO&yOG$wUGYflz|uG*_QBF968mo-NbKMi9f`fpvxQMPNT=ms@{m+k7d`I!GU+I(y9`d8k*y#93w9Bl3KF7OuNr*G6>W6M5|`jo84$BoaZ(f&KZl5s+v3wvLMm;y(sUZ zE0aY_V at fMyU^txYJ;H(2!IdbofmT>~E8f=}pInQr__N-Mqf at aJ$DtKJimo3~;q3fF z(dXSCZw5JnIgARkK6a1}vyX6*UDiDs(Z;Nt8g0ys9*tQLYs?AJbt1SW{#LY>Urt8- z#l|^4?Dltv_KWR%rB~4^H6ScpS78U{wX`KL|CNN`ac^bRUtzZ|L^y!`C>F1>`OG_{ z_7-o}Ztuts0;F+7}dy at Wk(%+6+3M3P-7w4eP37LvWu9~H-$7|1$XQj;LYBjm2G;}hmRg=1yWD8~c zgW2kb4Y8xL8W2}*cCfdSOHcU=TK4B+=%l%7&Qe=2jb9&~oUa#ciPM3JY!@~RTnHE; zOW07|=C-F<07YxHx!GBP=Y$PrVPj+ULEFFvS7$IuQl at EX732~`x8^EInOC34rgivSt-_<|FojJ!jnAYS zAU|R;aMb|WWef~ubi0#@?s3ia$i52YA^5f?P_o)kuWjDHqZ=5}*%n^`ze*-2FJrvsPsk%LzsuGf&t(}6 z>PwJas{@kHjy*w|CY-}%#%~beE2d{1g`?G}FvcH;H}jx^~%IG at q*e(ju9^VAFnt z5n7tVM{U_v=s?Blc4Y*v!Uxyl(}6Lv%Yb~%9Op{qdgH&1BD7s{!^ry0^`h1sZTiyx zR`NTAdFZH%q8h{RGO1@&H`2~T-MoBD| z6zfD}nUur^DI{o)xxXL`rq+I~dR`8R+hMxcrFCh>@3Js`p>TMN-o(OYAkv|0+Nkxvz+x!V+>OrL?togNUJb{D z2fo&a96Uw${9UkjE0>E-uD=Gg*M_Li9Mv>sR+ at T6Bq~4J at pn8ePDy4|qR0WjUb*ND zEO85~i>%r-2D3cU5j#)>_3mwP+EV%C#ZO&m;BESCYh zqT4DU)d#EZ&@q_!MK at mrV=2*;o#QO^vm4QB$x<0++ zV*AP(SKjAJdgvCDVcC4Cpi@%Dt+)l(RlEG{2&uZuDlOIkts|iCpMkC>nl)4O{-d)C7|S}IOZ{`KV8jni zzsi-Ah)us7eM=}w$<*{3bQxXUVMVvmz}Ddj2rcgikM>BaTBO%Br at IN_zYz;GaA9m; zHbpn<%ht!f^j4p?`jiQOpKCJU2*K#gWLJOlE-oawC at awryjr=Tzbc at AOa49#j;1WT zzONR;P_*wE-ZJu}=FUpwTd)?rZE68wCQJMV@(#6Yj(OvO?yc{&lh8DV-w57G^GH3u zbZ%cghHC79t45`cHyX~u(fU0btcdqvJA4Djk#c7u?DJ*h^)r~j>cYtJpwIEs(2Fee zu)1ZA2_r%}Wi3}w7+zWww9jCvt#qmVy at 4x}XU<@jR>^8W>rB at kL2iWfwrMt_Q1%)f z*)SNBc$ZsIk)9GRk(8Oy!I^ahA)SG4Ws#Ahz(&m4G<}f%d=j~&qrrPHzvghkIAYa- zME;%y?-2=mgqfz)!6zw{x1x=?q!M1Qb{!*nCfN2>T+!`V3~Ef{RhYk648TbKGhKUxcXZw zxfw2K>gB$iS*q&XHk%O`#@orTTX1)|*|(T^(?A at c)t%_kcbl%K7eGC|BGS{#jo#VC z)^!j4(eFK3U%5jI)V3O%C~Wvt#2^}iXOFP?(4b}J;+ at 5%Evw)MhPWz&X2+p9`el&Q z_}N>zMI&me$sMMkwRmT4#3px`gHXVxmg4P3K?k%@k~NGg_~kpe;V`zM+5wO5PM$SO%uHU^kb-R9NmWJ|qb{qZ{-($}%jy|ldhsKh!_pSoUnVjhM>KjpJv zNOZgjQm)tJj)B7CZc at 3?h6s;OM7!962N#L*8JF<*74#M?6y+{>yV!)vwzn8Pt{UNq z!DMiqv at I3*C33vuX1;%)W{Lk6GaAwT(cMueWIY_yT!fxy&T>IEl6yNlhgTY*?62 at E zcbSB;^`yViktRI#H16x#>59|%lc9__FO;ASAgnQa%!kz1H=tgQzfzsKnXB26-I(Hk zTYW%JI7~#Dze)}13EOZBk&iiXGYtkXBO4BmjRzQv#GAazq$W6t zCwa|h at JBLtz~p+(UGnOc#*k-EU?@Cj!C~_1N(1_I^EarYHgMm_Qi1<%$=r$YQ)k6r zVWLWA&fk08Yht3auS5Y8)yB$xo_u^aJ})`4j$i5` zD{}7`qk-e62O5BgY5NX2wl>snLkbJ`>|!ok{0c7x31PGMLP<6F=4xIBXM9b6NuJTJ zEv%oa83wpROU>|frC~tb)T{7qy1RVoG}u3X#R76ozNE}(kK+A?rQ2E3%30*gGvK^i zD81UqH7Xa8_-!%Hkf4&KwZe;Doaq+sGU{{U#EHx;`i>kMv_{ zTl^@@=qlU4rU;{sYk@`h(-pW&Z1Wh5f!pxM#?`7c$KOX2>*A3Lj-h{cC`yN!#J0;{ z>qqj at e93%8HFq`YF^Cl&+ywS=j}6ZGQQX at 7el+~?Bx?0uZM#?AW^DmjHpe!>$H25?9UpkbfmZYQc~;2rupVyel#A2865kn?1IGM#oIwGu23n6pTlyf)Dg7ywK&oJq+}?4TKDFF!h^9ZNq)Wu%HbVvL;) z8N13p?=;A%zdfq9wO6f5!~h at ae_!Luz-Yy*=H7=jRb>K66GZv_h3a^ovH(+75TmMD zrvj(hJ}m`xY=Q;A0au{fbwLNLoYRJ2#wJvhQNKH^X+Ra6#$A{qDbv!W&@|Y at W>V=7 zO>>5(*&;(>S)Hz*=EMT^(`@)7g=Rvofh99jOoI)E?rVA8p(5TPF5^QtQzWWwpPE8N z**?_Y+M#|j2#&CV6b*KhT;MeDktwi8V+C{hZrjup;PUt2t4>WB>^WHUR(YzbQWnGcl}&{%(uK7YfdZoxM7{Be7LYD1ecw6fzPzLXoSFakef)kj_uYHmeRn5BDqx{_Z&sz)iv3G|I4{3)et%ngu~HPFvZbG at YR4@ZR=b=jC5zt0(EM1V zMVY`J{gkME<(ewDf$UIrtJ_&BE?RY?*P;Sn?LvtB;hw&{_ at kTI&&Z0ZOSZCWsmS0l zvnxI&g5|dyY>8ep-8RbBE-g`Mo7;(m+M(KbA6;1V at S`s(a5y|_oBl6 zOp%0$K>0Mg<)f(dW|tXiFWbrOK2ncUNke(vorvpOP{eo@`~4 at ni1EI6$svzDf7)v# z(OafT^zblP4(B^iyBL+n6-ZsVzDE@*{%qiClpiFLLh2ykO)d3OHU`(Z%vAy#I<*qu z&^v{O3f55c^H2$BQzZ z{*6%da#ArA)trolFBHj}Dp~|zAq<<^B>2Xg`R{S<`Cr=apS9oLX}=}$^jpyvzYHJr zc1;(aM<2g}507JSmrd|pi!@u;Si!fAh-!!68%jCj1m6HkOp<1MyNU$gc6z!;y3pJ8 zfZ&U#rxL-3N*Tdnv50Boo!)xX1eLB4W!OFy`=!f;4e;T0-zCqx;B}y!(PZ9`Q at f)p z*iNoNCTC3yevkKX@(>@;sln}N(9^jw7rFAUW-mV2g#YU)T%@x?B z+to%ObNWhV^oIgiyPgA zi-toYtijt4+}bvZ_~Gy!d7?P>_Ii7kE7umd{aB?v%dJeZ(cLhX*&WG>aqhRoF%R?l)>~@Fe%Z^7mYFs zS4qm;cA6xtWgz;ro&!m%l;9RN+|s2ChBYy!226EVR6k*McD7>Y z%uv54iC1fK$ki}6Pnc~aHBpjn-tRgcmQxO4!YMnT)nfEJ8h8^6#m?42O_yy#@3=OM z1Gl}RX-OOg$I8SAf7MRdo}EWsa&=%#uD7dTvB_qtM|WbIl^rg!QVUdIEje|fTIWa8 ziwXti(@1jv#4<}RH(~^M6$?PH)-qeUis6D553>a}Od~D- z?Q96Tdh$D#i^LGft#YRlZ`<$}B6Q+KIkln>%4A^-h4rV!k`4e}qo%JJjA19-Wp-e7 z(Z*eNWi4>Y^;(1rpi_3*ku^}8ZStA&A5fD(8U(|Irn#xEK1fqNPBly^BUL?W>_u96 z7M0%_Szcxt;W5(`;5`AxwKz;C1dfNjU~<+}q2d-~z;Md0#R)RcOTaZZ0_LS-qftu3 zha4IUWaX80gk4_~~UbGUO-;Z|-km1!cAspcq?DOeCr z=|=cFQ_61_&WTK4Ww+qv)3M2C^iR|qB*5}GPor4-XI&tfJj*Z zD)nRJD;S&D&Q?W$k4z4vl;PU}yV#5%!CUx?nUW3uUIzQ8>~xNFDf}HF^@G2;LPZv@ z!5kc%hs4+#~D603-HfW{4*KM~=;23n3x-yD^&dKw zH&Ha10|F6TRx2Y8!o@{K1;TZbh#z0TSq%HLoMH$_V z2C;i!%YS-|uC=zapJ35*b-3O_#mulBL_S&myU`}976Y*aQZM`!Cg`o6P~e+$!iWJU7P#MpwxX6Hi4$TBi)M%=$AM}2?k18 at v{R_kl=co=hF3~s-`>xsJ6>&|tAkVh z7ha2gbx0*Qr5#A7Ts8fU{>Z_n{)J~AWi4(pXL;!+JUO$D8`L`GdG7q=jYGWzyqcx^ zS+WD!mVu(Ky;-Kh7|+d}whSaor5ogeoF~%Y1R25pjdo4)q%^zS0Qh-#uEAhw at CfqQ z3}5vVg17CAe{6=5;2ocli5CF!_%v^c*??;RB?lo_*CF1tx4&K8l=nAdiZ>nG6?Tb1^`G5%;G>^XcO!zGz)f5dS at Zl(f<%sn^6R%b-_7mC~{n9 z8)C9EM#0|0=c>2<3MxcS)9y^uD5%?A5d)aOx_U5T9Q*oCYVBtBMi0i7qgbAIg=Rk_ zzo8EX>v^oGkS|yscfv1*>fI#D``C{s;ob2WVo7^P&C|f~-}Bed%^yuOATX3scGLjP z%5I`EQhqy>r*_mBrGfsZ%pEmpg3nKAY;2nMV2|iG`NwC#nt?KJ+b`b67+5ubC*jXE zOqikzjHEuyI3+ABN=Ccx*SX6L>{MK}0fj~+HS-0K9M8d(ne%X(7#L%OkH}-Q)JFeU zbH$Ox1MTugc>VIL0jf*6%iEL*EePI>D78nGF7x*ENEf3|2w19t^ppZ*V>K4LsYo=X z)S`uY>SPmOP at 6eZx-hRr-ewPsiD7S|mKOzR`h|QKj8ChwXXREJl>uLH1<1)jqHcqa zv-d{er!8lI0Rl*26&cCne8{uITQc+hbLdVx<)frywokMqd8WGy%%0JroV*UjUhHo4 zP30$5dX%n>M^P~>n%xcDRu^p#1?DP5tT4!J+VAoY!bp7Rl#RQ>U|D;)gt!)Kk&{vR z!k-+iJ`%c5Mwv_*8p(xZUc!0`>@GZsF=xF84|szKaEv)NQvi7Gy9v%y)k*Pyjl!xl z^3!fq5?H1MhNGF(0J1}NKs-F&)9XV9YiH?i9~0$nH38Kf|B6D=R>Y4f!m37g-&1t? z`t3P1!p|WyD&sPvGA=WE>lb6l(J{%4T!BZ at Tz>Z&w9=OkVO)`ks6V;@71v3Y)Zkco z9~uKXe5HOzB}tG9QTa22-TY_$$h_)Bez at 0@>+vS(Tf{nm6s(?w?6pn`K^kX7i at wyi zZiq1;{uqKMa)zs<`Yf?fY?ESwW%!1s*oy;2NJKY&_ACbHZUd z0i$n+DH+KyO1RvLtr>t&`=6jG_!{pdH?uE3HyGTe?=Y-+7OUn(zYwQ at jwvPvuZQ|S z8fME+$r36)Per|ISC&!mEl1-r*boy*wFDY7wQ_P+e&w_>NMbm|VrVHexCs7R;eW2R z>Uia}751uc?#bIYMc!32BfjgN~!nMaL&ehPu(I- z@}6=EzPAyXopK32nG&~2h2B#$rE91W-cz%sB=4#D(xBibl9DVk&h{ib)s3c;F27@$ zGQa>Ww8tD$QtgI?S^18bALz9z;7zT*4#77aRw}Z7fWr%M9Zj at XJyM1vX!kV<6)(|7 zbF2a8mhn)Ske01o$QLV%s3xpmS!t_s7=f=C;0(B9$_hq$QeAS8ih~m8Ec)`2>pW&C z2`(VELi)OJmbAChCi81CiagB&tHbu%sw>M!uANhA4p!)0}R%`QOfq*wXyX4(BfO* z?=0yuY`ah~D3)YCBVk5-o04z|!Wy;9?ZJ*DbPzDzpt+Fqsw0GoE8`3X7$|FS82Q<5 zU9XjR$i?mg`5S9xz7pqEb39k#Ql5znzMTfcDQ~ssd~Y{(u5bQrFlWp>s at DlWN5>;;mrrZ^9r&%itO=7^|6HVVBH at 5)T!IkJWlUz}J)=f9W zzCVz&k*)YeN&h0 at ONn;mUtsA0I;iCCOO4b=YgMjwR4438T1>+CU!t=7WS?~?*i&ZN7ON_OG8VZNqPI}h%IpV(9?h`YXQp`gM^|gR4huQwKxZ< zoT|xL1-=%^WS6`0r?m;b8_>&w>~7Tr8^Oy at B9D;cL2Gj870n-Y%@gO4+mycAj4kL2 zwU&ndu3n%LS&uC+9o0vlcmM3spV7%jAE_p794_vP9DVa#8vW&Kc;)T1tD#ep;FNa( zKe%F*b^(W at 08@kB1MT at h2zlTHnytmqwpYgH3G0b4N|jF6s(={>72O zJi)h(=XnI*r#x?g;7h_F--ym`qzd40iOsS!2o(YN7ETQ9R9noRN}MD><(uLWakv at M z4#6+rLH4W&eVuv at gWn-cXm^>~Y-NR6_j$}t^-Fstu*4Vwz}*h?WF~v(S`>*CW=-S0 z5h|ABHvDv&+w^U{<5Xr4Rj43cIKuOY!*@iQX{$=fD(jvm-4B`eQNej}_Npc&-chyH zUKMn}^A!$Z)h=lIRyWWO@=ou;1ZNF1IbxKSLvGW~G3Lo}?Ep6SYXGSM&>DnkBbchj zmP5S!x+BUEirrAf;4c&dP%j81Bnqbq6(!{KepH>{yBK)k;LEi0ay$caj^a%4aPlE9 zQB`|!%17ep%=D_co=J97&?#@hi5|%sPK1^fioQ at m4nlYwJ zfPVLcRpHgg*OE<`a9lCLq6B;c=km1WHo8cmmJA at VAhab8+Jfc$6&faeeEZnsjgA}z zM}&OtnCNvnuUY!9A$2u=ShpMa2`t%hgL(RS)x?E>fm4O&cGGE@>B+&pB~&yJ0n{Mx z0UFliJ(M7+P^B8il{?5WIiWrWo-A7lr{@B|VIDWUXBE8hh#zl6>~1cBpWO zGyic_t#rJ;2E)`MrT`@N8dB(7~r@%28k~| z06~?wy3iw>>`qf1(PoJ}$7$M+ZwB|FG?I_ml~ehcUJx47k3I?^C$g0S%F5Cz_`16_ zk)4R|C( zQJ0D}GnU25+pNO+1MI at tI69tX@+t2R2cX>h3$cHva2W)~H4}LUq?`-Ij3(foJj?h> zinHhZDBVE&4=Ft)5WYGZ+Va6!=z>>Un5n?5V9bG)+TcMAFlJW4hd#8#&Tp{J;4$R= zrL3vAyZ0KRceiu{?rbTScJ+*h^+fTGt274t4z@ zI47s_p4YUYN3*GH091!xmQP{te>f010EDUn(oM}qKvyvOQ}w>HP~Yvm at 2%~6-^Z(G z^?mM#)OY+0^<9eZ{06I&ITpOdCfKPzD>_4`=}_1PbFi^W9IXl<8I}VYL??NUWx#%G zO2(H; zJMgjtXbm8@=nkn>zeC!Hk#@8 at q^ENE9a1xQyH^%=2^iH=X2T012 at X=ki(GnBzDyUHJX*%3Hy@{+ExpQQpz{;wrBE-tx&?%At6KBUFOD9O#rD9O!h zQIeZmG|A0vA<50rXvxiOA<50r|0KC_|3}G<`!yHf!8x|7y(qc4z*aVDl9UL4b=eKj z`NQ$b+U|b at mg<>DrQgF}lHHuqWH-e`(UR=uNA~mCvYTIK^pf4oM%m3Hja+t9OtPD` zy=6D(pnzJ%1vpKJO?NLGuMTH)!DDa1Wb#P2AHuF%U+*JHx-b`lQVlt|AdK=l)^cV at ca8=i>5p*#5V zLyI4Wzq6zw92}vdFcv8a5~fh%ibNR-58J&5Mh%6+}re@*=2$|~wD0H_QJ09NP%fGkaj^8yzup#We< zH?kUy{QE57K|&aB!GJWMN368Amssh&uvlqn_iu`oD!DWz+?ZE2Sx~GdQDRjOXxC`y zXd?6p$@SlN&!N@$FN5B_W0CR=0Mo@)P!^Mu^AoUxR9@!LwD5 at Oh0tpUYVlHmGYR;kkhKB zKiq+HHRUyEWwRzv3R+In_mWJ<@a6|TCZg`lbElCXt2!3!BuUYkIfCyn#}@Mh-&Z`( zBlr&Syaj^qVv-&KLLC8T8 at gGkSbaXZ(J7L*uL+X8+w(4bj!TM;xlAp9x9 at WyHRDNj zs+B`>3P3{AioK>Zk*ruY$v3H}qgzl>F#;r2OdU+^_kO^BY2>ye3E0 zQF2GaMM>@F79|DIQLH0BN$_2D28RV|4f=FB(lMNlC^^zT8c)KwBu9c3q!T)Mz2rzo zG&$0D5ptv=K3o6b>xb~ACPxxUj`RhWBLT)IY=1gJjnF-m56eqcV%MLr at h8KJlJxY zVRpjOqhe at 9!*bGz9myeF@{DRa&`s`~HhYznHCZ3xbU;s{Tw}{=MCDW*o27&{fqbx; zs9rYzcyEbP4?o6Bq_Mc^A|*;&8fD1yS?|d6WNNA`K z>m at nUVUjaZUyBj3qEy7x>L=j{5<%lTF>*(Tlm=}y2S;~m-%-}vE6u^HwMQ2c^hkWd z!bG70K at DU({H at A*Gy z)aQSYGJSe?sO#sDGOa8MOPQK}L&{XdrA%7i+d_TUq)eCprj#k=P3k+BGP!z5nGi>! zl&OaL)2T0~6m(PoCo48MsQjue94yS268y&CQOGKV-yr35AoQyAz%PiF`si?t+|~vqM*Yfe8YWbn0D1x#J)ql_ z4rG#%B|eCfqMzC|NzqPCQiNM(z#D+-Y9RyA+~RoH0f~yqUYW=qFAMqW2);{lBo!k@ z@^=pX2`PAD-~v#_ZY{&9JIuiy@=qbD?PbB=qco}Vvf!+cC<<|PBYWphnkdTIfi%xo zbSgUJVDP36uKwk at f}L2R3jhv1h9f?Mkvu9yq#-e+Cp143u8-HW-GiVqftbk&08 zNHjDpm|+<*5WX^R8oGXwkE1UUS76vhkcFN_9#+v@{#Q6M^3C3ZM(IZQ_HgLQGR*C; z=bMdEGRi4Pu}K at F+(GcIlR)^3aFWPz z)tf?+vdoJNhCEnj?JoJpOBQC?VXz$Nup+NI_#N7LRkV19vNsp0>LvN?@kRRbD|v*A z!fNPx^OQ^eRt&`b*cT%$pN4t+VJIp at lIYeAqi3s#CA137K&g5 zV5+}H{7RIao8Pwx6-aGXCFfO_btefgSL0P9eBfjnDQ&jdybCX!Xpk_h`-QGbSJneu z3R{V0N8agBgbgcJoM_~ED4x(3FzfYVPMy=VQA7{u&%JNthUV5#EUKMM`XiZx0_TZk zYMnAzqZ8zv1j#0a0Fd*>SPuF0Hy5w!reesLVy at 9oJ29`N!Jd^JXP~My?^^qUcwV*P zc-*EDS`&Fp2HrR+L;g}tuVs7?F%E}(%9eA+v=HrHre_ri&&DBH zzA($hwPm!JAV`39t{t_LOqrVXszvFO4fR7SZw|G314 zs%F5eZz;uBt<0o at z$fv;)D^kTmb1}jsh at Xw5Oun%fbmZ6M$@1M=*%HorCo5rvOHvK zuqTkI9&Bh=u$xxa at E;Jx1%HasauvRkKkLKwhH2r$N=A2 at dHdb+ceLU*DdAHinV3 at m2 zykshd^r*o1?Q*?6r<&g?1XA<*&`j5$iIg4XnlvF=0HQx2yqdoKdp<3IK~xhO=<W#~1dHPk5)UutcHGhzl^~N z_6Vi^0XCR0v`9j`K>T0okEh4-?jG!6-T8ZXd+LAg;gRon58XZI at 8NLc**&yi5BnOm ze&GRYTa#+wyBQeraF4F(-J=v(ZARXeTKca=fEUY8u7K~(t&iN%xSQwXG*aLs+{aVk z3v$ic;2DGA^_<$gmK|MoxiQpYzPZnQhojJiUHTL5{|-JFd at Gi069X@&BD6zpfC0)) z;RA#)#e7`k6tg|2UQOS1m=IR7321n`rDw?+#jK_m9mW-nkLfn~H19Cr0h^^qc-llh z3}KAXtt@^T at a$CYsW{JgcKv+)+`AQ${*2(7ZuGvDNYyD#I4dIH;7n?QL$0Tg4U-P@ znfdrM*{+Fs`;~X$T*!tRf(uAW#b^29Wb8z24V?^DDcM%G$Z(P1yAD9uXOH8T2jiEU zAE!e&I2!VEU_GD)d;pI at B#c(~=Y&z^AR>(L*o?lzOAFB!A-f(M9-fDQQ1YrsWz6CA zGx2eq%6Ohr8S^ZoKTZNF<6%)g;F5oF)|^4FSDz$Bc)g1K8K{g5qB0yn4}JLwP#KuZ z9fkF^MWh$=G#U{H=SHMUc^dDZg7-wEZ{z8^Fg+$BeFINli0R=G>5F+f6YIPnA{|fZ zylQG)sb!P!Vzqu}OJ5RJ?_~#H!~-74w)j%-srx-~G$h=a-o15Eu%G at HuqF-G|3AP^ z`z=_P+~g2e8J%j4EnwZ??HV{g*5<9w6jmjPYHh$qIVNvSCdOimvs-GU9rm0Wn_T^y zK46cEVJEN`rc=Z}Pd3{zS0_@}KL}i(7Ry+7w~GF(mnaXTmxGSYw8d4$yCwatA zM=-9;QSy$|;>g=yHY(E*c*5vF6U2QkIp{GvO$W*>nNnAo@#CRm{4?W)RPJ6e5%$`#g~=%ZYTPlGYaU@}t% zYj7#h8bRqJtotElUTj{A5)02M(0%HAMG|uB=(ukcG)^&vh8B(`X_`@s;fhrKO>gmN zhp&?DV4W!pT4ot7RG>mb_}%nEdY7nnIPw1Y24|Y#y*T*z1&SL$h7pKa1DPKNF#||n zWjKIbKp+Vk$mBP83(|QD5&$eMvK0oQ;v|IwbY;zS$Xnoigi{!u!j+*A^W^LN?H|yp z);Rj at eMZA2x0uNlmG^R>R!Y(TO=-5lf6HM1qZwM| zk#|Hi*0+p4nU02d818_aA&;)qm|U>^w;r4x&JXZ7e{51E#%TTj0Y8a9P7Z7rx}Xg&O{HJA{?s=)dsTMUW*>H znEYoFT8Jg^H|{p9%AZ1xY^R{PrRL7*`+YR^kLOV&#rw}<8$~Jh%57x{A+g4z+>drRa z?Da3gA9(pst#I_Y^QztGDGlgAv{=n%b2kvFgJs&w at QNMjNEgn}ENpbIXnBetYyeVh~35VITIPU6h02K6JBK>cf8M!=1DBK8&5p`*4*; zziS*Yb!EE?cg4==uBf}t-8vT_p^7+u*1`<*9(X)gBm|jU&)4`lmIs6jNyK?t578_xO8x zzaMu4XB~$DH4eIDx9E}`R`PG-vK%CbntOzCHK at 1L;9z_jJ#Fy6+3#qzsk<;NM2D1D zQN7?2)!n+lj29`D8A=+Qxy>+ at B^$X7bgbN<^eLFuI;L{!<*M*zU0`evI at g}a9iq+C z9ijok(au}42hZk{5jh-dfmmk00zULMA=(gYxWzVqhj=1#QGS*+c{#rK`8nPr+9($m zyPIOF1Fjf at NBHR9sLMYchHnlzY<|L2Z!&nhdOVrT^gG>jHkozI3hRH}%}IFJ^7lsc z4X<_C5;bIUe*PHuPITwoj at pNEx4WWA@cl$LUe%s-q(layYXTCrqZrUY+HQici4t(K zqkPS2X at 1Xk5<+4TtoHH59288MiDpQ#V#D at 8g#WIa#p`CjXQFCg}IPk5ZqzqS(Rz!zRS{Xeg* z9go3##pil2T9>k$d!}f8Nbk_by8s>ZL+P9?V}+M{ky-%+6snJ|h>?=LjhTL1Mi5OX zyp2Xkax?1$*7!6=92R98EEgj>YcQcxS$P~BTz93(jqIO5JNU<$@n}VlJS2VmBP2S; zWjyVKgSQWqNpF``!3Vq zZ}h8j7=dqRj~8z!hH^DE3aQ+6q`ff$P}-(kg8r#WldVqKZP)uGm#&SvBd%%cs z6pytauS?^+^l|uj9FcFt|6txc%3Go5og+>{F2)J&cH|uvy(eP at -z181deS8LoM@uc z9V7VCk!|Tt7knv{7{HAWktZO(Ro-ran-+Py%~Bs=Or%6_cd}5Ch_?)nV&qC-pK$qi zk-&aP=k3t)g4dSg4cIj>1RvgEG_ZSKL!XqstmU*y0C=+zeM!WaT>v3Kjg2kYtz7{TU6yV9aTl1HpR at Ko^XXz6zoPS(xz;-bN4NYK#=;Rnt8; zc}GwD2GPRxTGXc0r_ohu`j+h!k<(-L$6X8M$^f>wgaRU{={DFqeiIMFD{uD(p+&C~ z%NHxn_68HBo4vt!sSj{s_u&G{404BvsV!gQiu|>iFGlJ}C6#Pb)34q^8{|U(Q62}_ zRRr4 at hLws5E}p}^ig339+%p8XJOVDC;J#@lxQ7t#a)7&y;1)!{r4igJ4tEU{!^lW) zB6oM#1KdHKGQz7Gr7W*%l7 at QKROuqGDlCQ(>$^COO at 2_v!L~az|My|~91fI;A at A9G z4Bb%JpiuZX*w4uR6z6rwJG?)}@Ea6JNDty4H~uN|{%DdWd4G(RuJ-;IFAY#PN!PQz z59pt+za1DEt1B?Aj~0`#&c

})>o4o|2&?pNT%}E}zyoHtd{vf$F-+R_)7SRGPssaO zv6_Bz8%5`I;w3j;Jf0?6#cx1D^$r0^N{i;uFz9vsjv4`vXtUI6)Pp6 ztT|h`$|bKy)ZikAD&D_g+5nKAes*~k;*o}D at Gp)6S5+y-!UDk8w;2uc4m^G3xFe7@ zHClEo8ZMS>qKG5UP}jZF8_fo_7I>jdIrU2bQg*Vt=aA#sENB^G%RBz0svD3Cw;b at K z%CD at X9RRef5+`qlAIky2CeY+WXfl^Rxct;!%K<^!x_!vN^r~YjpuICk7al(L%J_2OXhWo=Y%if!SY*3J52h1SsQe?uYk`q0rOSl=DVbE?wFjbs#5m)O*q>R3sUBuwtv7T+NArg<00TBP8O$@4os9 z-kdOK&QxgsX2f<+dKO$Vo2YC4ic{Xk=DdPP9l)fifhk5*RzCD14h_Y$bGqb49h9ql zQ?xltsBUSfv*d)P!oH2Ic#(@3co=$&EM!KKX<)2Im_EyUledKpfP(`a)WM^EEpcz1 zE#OeO6JS?KBYP&5M+Xj7(_%s)p0b7$r(t*L>^m21tuIhcZrSCTj4}pZDDSq(Th#QH zCX~E%L1V9gYUEwah|Q!nO6hir at vK3vXreFv5xqoDH*qh~gkDVcpL| zC|0?=+m122;k`Lc{A%Yyv|B(IIi}zwqLuuq-|acaIuFHHBc3$%&&P4qe!htgk-%~C z%dMvWa}!^!mW{&Gf6xe=oUdJh60_5L+AKU>&et2u_yetWr{&9e6Da7qXsH#2G0o`7 z9uD19gn9V|vZL}05CeB+ik97T$6 at Ybo-2*Qh at v=cfkN01=*tvNjMU>OcHOF`OZXg^ z0L at QO(;wo6>=+hq46W%%ZbOgdrpeV2mjrIjV1Z?PY2cQ-gxB(qV-ykoPxu1_T3ldk zh7ylM9vxTutoS4_a7USH;{k?Bj^XevYC`1O2G8T^`H?0XG8h)&=|9m>bvbiRy8 at 5F z at STC-L!J$FuJ*p94d2FjQ_eAbeGz8LGE&RHh?%J16B53dya00AEgg^KZlmZsLkZ*+;U*mb;&VUdV7ZOa`o}L zEv^zd+p5n5!%uSMQW>c*T=1j0**xQey3rHQ?mq??A*zl* z>PN&s{ZMZ(Xhq0_$h9yyX|BN2gf5Z&0KVfVF;GR%z<0#i0f5+!^Tb{U_JKV!i_|VT zXC(NZ?L`C?6aa-7`an$@Qa(S0o`LL%g>n-N1xZZqz=H;c7ri+89B3co?TYiHy8KSF zEnq!OF4CMtOCzy$Ieq6nVsQK)eyYPqd zg69l|YWXvyAUr~Y7k|A-P2hb>dBHL$3}qws3qD8LFJN{G&qfih@??3zOA&b(3qdI@ zF9<~BVZ>VHj`D)%Bl1vtRk^9W;KhhM3`wmFFE98sCY*=P*pva~1)o5k+^`NCA=qpE zR3^WKf5{KCO>Op5Pn0AaDA^ecIijD&CHPej>Ajtc9$15G%F^gbkQ;-U1Qxl+^VEXT zPaZKEJaO#QgNQSRxQ^h~jT?bTg*;2QmRU0ACze?ZQXUX>SC&~W^(5w1SE#U^a5P|$2E3^m^(+d+rkafOg&zXr!m+65S8-CqA2+(jNRkE^lp()|G`4>tzI|F& z)iTTIz#OA=wOI0VC?q2*tO^+yOY_J*|1M-mll)}hGM?fWm(+_U7!8AGHB>qnKLGVT zdkQEI at 352_;xVr$8T17M6#UxzdZNa^>jWj&dsPL}9-2VoNH z$EgMdonz;9;KiBmTWAGdqs5h356}U@(sRCo*@+-QXere)>xK*sfTW)l5q$tI&dkr?+7Y=)h7IYe0{=HbUO at 9#z^D1 zOr!}F9UgOGrZlcFQ5p*aa-*=mkySotpiT`!Nlz6nVCoybsC82z^?WG6JQ at SFE_gSg zbNY@!11EPSB;0p;v$6m({ybt+{QxF?T-*Yg+7>t#wszixI#nbZAO~<~V5Lt*7 at WKKA4HYd% z=S>w$P^-z?t%LT6WA8(WmbF&*(&ZzAF&h9Bm!s|}zsDJclK+oG? z%B$`EA at 4z2G3g4tbjcs`p?V(KyH!n}wH|L~4)f0nzQ1!SwbWjaDPf$n7)V{_>CjU@ zp(1U*nA3{Cx#EsfKzQf1*aPE at z>h#yHs)ul=}Fay92hsW+sbxUgqV5BMm5mu_!_VZ zxFIndoTe?deFG8j$;gcSr4x_$Uqy`4-0%f9tzJo{r?p>%Hv2 at J@FKDb#tENEG10gW z($Gm7ckf%qkoww&>;8OT#OpbDL^en%VkhA9IQv^9(!m(BYWkA(novTpEIBn3~L=uzB0gqd>hrPYaPM(M;bHf&kD0>ti zH9Z}?Mr(G%4(%iIKP{e%fgeMq4=J63A7f!`zJ{ke>wkuwB(A55w=6 zY?XtMAgRC`ZmKD%a%x`{2$G4)AK}x>CWIoDd$*kZFXBEqX9sk*qb5NbRAn4f)jx4m zt>;crt${DzC3e=Jx`F5WW#RDBw+8wrmX;qC-Y>i zufroF6|21*B{%nuzT-P0xQ3isiwokY^aviq7mEc$PC|xsKU1u^I z4%{Sf`8e8;lW`WWW6$BUrQz`m$SEr<80`@_Kh8!_EmAxZ_ewLe2myP(F+!>laSd@! znt_~GU_c&RJlX81JG?T!9v!;WKF8sE2|o|9Qwd5V{*W4xsUB4gniw}TYY+JtS%*YG zlNV$7pea4|mWh_S#}n4jTKFTsv_^5lfifcdH=T99zf#ysA1R^_{GyR}AUC1|ga2~} zVny$zcrz*0JE4U)Qma|0)f=(Z{k)pr0WmN#2Ipq3j1)AvPwCHUT)IGMm5T&Q%Se at A zH@@1xjGOghZ&!-`JmtN!I#pwVPU$|W(QA7X_uAf{mAZ71>!d;wu at tUTm%!7NUbMd! zN8^L=Vht>ioojJFFjuAKg!!>EBt_%71D0|oR^#2z5i1pi9=UG$Al=!Xbjd;f;+du7 zx>~MtR~+Gu>c at 7B4-fAb(01ifr+*q9{z<4HmxNdLDVR#oqF%{$Fu08f5K}o6IrE*T zL)RSAbvQ^Lm(!|n(yHi?E*35Ik0)>paX~1m?{?O-n1-?sZ`s&qNc}XOR5Kz*bKWQ# zfL`1>s at L<2)@i+TNY3tm8*PN6{1b*y=b=%d&VO}lxbxNUDL7yJ7h~5e71Ii>e=0`_xrnYNBxfvaN3r==g)Q9NHqPu!}nqemerXDAmz=bfB--m-`~KY%{v z@?XPScvHo>2jS6z|1=0Z27Fp527LH}KnqDI$Mw9T3p(+x1WrJ?+vy*_0>4#cmleBw z$}S(b%ilshD+})KFZjlyQE^~aY+#yJE+ zBs#TQi?UfJL+5OtqxKi6)Y{}NNHi3&SBBF9XPDZQ6wq1vxY@{ ztkH0gXr77~lJRqwW at KtRj}ofj`yC}Z1m6QOIFT?_a$Tj-1U$*M(a3KsJSMxzq-Ktq ze#L4oK*V_7-i29n;)JC+F{qGg&zgg=yDasKugRa9^|*8;k`D9p2TGa3s at qj1Ni3-~ z?H*Gfn+eZGOY`DiQ1?FnZq at T|*@4b#@|}SIehl at C=*}N+2=bb2YcUfh9x(d^GygWO z8F)#)t3Lo+0XTmRh7xxMo=0YzqS&HpfIVO}x}gz3v=K>}5zk+L>U^(1*XwodRofc8 z1E&i1#PJG7p%fwTK3b)g!dACc-oM0Fc^~|L8^zhS%D3>R01)fq0vd|E&`=Dgq391o zVWW6Orro6uzt4d^*RX5R6EyWlb5&Uo-`Za$x2U4%SeRsVLs0kDf1bgxfJU}g8~0iya7g)JQu9x4}U_McPslp^t+wC zO~2dNtMDs-gV-W~sXAq{D3|lDR7<9I)hq_$>aI5$xO-dw>r~_~x6MF=yB4Ft|4|Ch!`2`r at GR|O6!2evxJQi$?U?VBAGSK>c_L~u={G?n(=54*bP>4Z zDRtVPfoK^Zm!Z;eMchyzu03W}IE94AayflYi%|lna9nU5vUajjCew6YU%y`UrS__C z`+$9&u-+*}Qq_B`Y}|aT&1> z9>XOP6v3ZNo4m~-Zv{HmCht+xU;Yre%l44rAE1m_GU5ul`UWi-c3>JHsvy$AycgjryGdwBtV(-X(;XV8$qgmA`fkbxAm+brg7 zWfR-5ov=7%Se!B}&cKYc(C&_iN38KGbI at Jh4#e6Mo$_8A9Ix4cBxGOK8d`O4 at XJ9g zwug=oC|nsjJs?dt<6M at JEpx>b4Arum&XGEx_sW2W*GzDVHNyqerJMs8C=IX=9Kzp{ zufWJXX2m_08 at 0zup9}3VgY21!mc>E0+-{do0>v4R2xm at g=d?L6{IEj?wa^NLje>jR z-|yodY18%y`es}FkUsfKT$Z-^MX)cj^nG#d`Ibn(>hMTqjAA+f>a)wDv&bw}$o%y0V$?jr11`^w8L;1+8e_}L`UJK#Q z?|Uf53Q#OC??vDIFY{ik&%4!zaap at q?x7wPCmiP!=J7Rc-mP|>Oo7~G92dE8f;Asj zJv75b+6+$&8Cd}d%H3-NaxLy1_a|Bx*ea}^I|fL`2kjaoM^_e?qMtMGj4o(}&1_qH zE!64=%xV_>Q`*TB5#E6B;%#uZp|o#8nj_%8mUdDYKyGE%@X`z at y)LRWxs~;WQYgv8 z%;Z)vFfKE)=HmybbfjLI9a*}ImtL=z=0=vT=A}18wicEoeDh6SawWZEjqc47UOHT_ zRg5fsfS2azr4u7d$3iLP76Hsv(KQd_?~Wjd;^@)@UV61&^UTQ7;5Sryjb54`S-P2* zj at 3)&M3%nKOYM5;g2>Y6d8s2*x|APyVSq4GJfTbM3tpij?0hDrp z+jM}&C;$fsxKRgajsnQy0QovVYZQQq0~F{0ZBYP+{!IX*bO06wQ1fqXB-{B&TB1jC zIj^Bmuc0fdh9w+ev<_e}_6E3*1Kgwon4mB0KXW)9rBj|#qQ)a4ApBu zE`XQu8m`}un9tpATWbOyoIoZ@2^{7ri%>k|p at AW8v2ln;G*Grd00a*9-M%hbWivk$B zPaD^nMp~iQM>n!(Z`91Jh^pah4sd07uSWrVzPC3DU%Dm=;7 at ydWAUZcQ2Py?A0Cu%%BgrCGs69NK?330g z)ZQLd!%MAEsJ$x+U~X#^YB$962DrU73bmV~0CG8iGmH$P0EE^k)SeLq at bjK1)Sejy zuys!qYR`@W_~)J|)Sep!Aaj5lI3kGAMl)h0f43(JwOgZVaPEmh?P3%__MRxzJ~0X) zVNVolFNy;Aem4PFbb#V0fQ`GOQ2Wd%fOmICq4qgZ0N&kEsC_{cz=OM^PvTqEP$tD1a|Gz>qKkiRq1X-{1fjhY?5= zz*D=!F~5Y#>i$ur!{4 z`R9pjz<-p;WhW?+%#QF3D?7{+BHPas6IlyS6tO0rC}!0>F_W$4iG20}Pt0L|<%tFC z4NAyJ=&@xyjWiwe at idZeYynRrrN(CSG!kd5n5U8cVv~6qNi8PwG*VTpkf*Cj{>Rfu zE3qt|MzV-y at HA3DEQP1rNcPXuNY}7mTPcmC3}ZZv)C&7IPa|Q%nt2*&5cVZcBe}uW z at HA2u?4LZ1LsqK5HN|S5$Cg+JdNm` zP339C`JJdG%hZQ*IeW~`d05pl6kcp7mOTfx(akJuYLjhKfm<7q at P%*WG+PuK#U zM%2M(^E6@!R?O3g4%lQ&d$kw}`rRnMgMK2 at fb4Wfc(Y5cnC7%iq8du6(+i7G-D zbuQ9JX=Fw1bp3h(UL$^f3ZXW$_FX-y(%RrH21o)niSpN?yp*Uu%SI`oU9Bvp^Z)H4 zV at QWX)1V98J(I at c4tsv0G@vS`Fn8evg#}CcT$NiHBdWFb{3Oqh$Lk6$o?{rapvr2r zRT`XXwXfQ9OgTg{WvMib!xBYH>Z0eNM{(@VU4%}|kTZ|x*m+JG9Z>|iqZDjkrFAq20JSH#YTW=F1UNJ=fZ-!Gdvg2eb{jrX7-%X5L^W# zumMq)W~j8sCU0Svm*^MEW}EzFu#JS6uW)DOjV`%?4Q}XBH{gYsyqzt05U;c7@;nJu zZRUIhkuop;dzCw2Dh?oimARu#q_eBbR9w_<4*a)y!}dFS|fd7jilllahkr$zsRE~ zx5E-Se)bZR%a15E%gB4lK;d z*IE&z*ZHRJ+=LJlX-nh#Rt at GOy^dW3ak~y7Y7i at Rh>tgg=-7*NsEKw|5!CoUy?mfv zetSguJiUCfUVcYJ`J_$Afnx3?4mO43u26ZN_CAN1Y+HM0 at A7_n{dej0Pl+f$-V`do zLodHGqI{=bK1naXE28}4CLE#kUh^;$CsQAx7YL$%FNiq+ at v{!`7(oo^1+k#lig7nZ z&$cfMw->Gn9VojgG at W6fN)Gfd9mv##mjTqn=epH&B{*)~JNrXrABBMX2 z;d5H}xd at +&!q3I{Tx at HI#~qD$-)w6jg#^U?ng0Rz6Tbg$3*mk`2lj3u+ at Bf7{VxCC z&cglk0QWx?iTkJV`*2e}k_4%-UNrHhYig-q=ze;`VlpN8_w@)8=YK{s--q8-{bQvA&XO8(-h-+T!|Qr9 z2OGa>6M*Wq47K8p(m5a>uV`6tGc1$QPT6e;#NPCJPVJ5^v4pwg at 7$)tk*b&i9;2mmaZN>alt#Poa$QJK(Hqun=krwVOyhUnd)4&& zU^n{5X8FfvMxK8mR~;vj6oC1hgbEC|!8ZD3n9;!g^%YU{KpLj+AI6O>-litfRoSRi21mF$BrpnpC! zz54~OZLJgk=us|^ek*+37O)yiElHAKH&vroQk%CcY3|R*>&RqkOI2T&Tmx%Cxgs#; zZCFf&ar5KKYWFHhfiW8(Z7Qqn7S?aFRi!yhO}7MGP0hX*&n_D`Bg<>4La!W!wuP~U z_biUT>Vd+6^JCRoB`DX{McBfN8ILZ84abDT89>C2@ zENeu)ovrfbK`rHnVyIpt)qCt&+5!K7TC934?^7+F^m0B|Fq;0iaiW4~verSf72{b_ z at F7NGk{qs*r9324L=BsZX|G(VW%5an at xP6e&OW#k#**IgjN%n5*YP#5!syACcZq at 2 zo?pW|PklMtV}K)Lif( z_So|~t>+K&>OJ>pRo>C7MVIjwjYc=_9Cc;#Pxxx;j@`Wp{7fI*hgd2Vm-0kAz|1DESLE(d6G(^9;hPpZU%dN5~;#dMvb>5)8Kt7!{8r3 zSSloCV*jN6 at IB8dP4ik!?*m`y9GiwDpCn)cprm;CZbIaDMcD+$36MI~W!<)gab?~2 zEH;+~A1Lb{IRAY(QoifeuH$!5xAZmvDK$LeDMrp`l+T*Sc>FOCQwAwCf}>H)VVHh=QrXYRlKZAx~J at BgER#Qkb{Gb#F)RcnOZpp zvNma1&rz0Vm^@x5h$d?odedT zzp#32W~tu+?~KhV^)HHrbPTDwqjmI}{${k+cNjcZy8>~)41x)_8n|nP#ct~UwP)F) zT%V|_Ti}DXwFv6Q*m{JW4ptCK7!AF3qYz*np1&MOP5+V?!b?fSFuqJ|r at Y+}u*I`M z_iETIWRO&ZBtkLwQbcZAf6M;M>FqMly%bHr`j;-NGLDK(@>~Vvh*NEZJkQT=r0#S#I!^Ep27YHM@;g(J-QrkSRYnKE?Za``7 at mSv8pGq1Ym^}Qk(?6YX&&_}tS2c~xn)SUZF^BK64vM0HyTTTD0f*`&m zh;5=jZthE1$w;48{wH4ktX_T(mG=*oKgG*kdifYC|JAFN-&=vosI5>?@DjIOzZAgZ zIJla=B?Om;_4wmb07yaMu<0f4WFzk6i-^&NoO;nn_M{KGEC-}%^vX(VL+U{+k=xbu z?5NmURZY|U9qA+J^I>q zX(Z6Ke8{9L)n-kbbSMB!)d2db=~rq1h>$sqoI2t~90WltNwbq`DVYxe2;Y5ZpbV=Z z?-N=D6C?clM9TxvhEz&KdBBiTyT32{cY0VL&=?mM2$b3j`bvouRsvZ5qsa2dmpc4? zm8~cf5LO#X$M|E7PT+G&D>S)45P{MVh&_`Y5)7;W#^e1hzhTds2>{n%%Pz#0U4Vsg zrT&2mBbf!HSV2S+hsB-KqIED at vYorQR;v+$8vW&-~a@^xnTZxzyWDS>2RXlZhtl zqPk5=q5&zj)JXNh>Ly`zbxw^kj#TO!=*ZHQ at 7eG>iLkzc4b)p{&7Ykm3ckrIj~QXr z9QTudV{dg26>~*qYlI?makS%P9B&d^?XVZ5Zuc1to&|h7KD#iFPMqb*kxO===2SkY<~As~uC;YPp(v4K9|HmzNs zU0&;Z-E3cLt##L0zy(pPXszN>_v%g4x)*TE{hl*(69VFU at Av)u{`md)e3-eJea_6B zIp at sGIWkG*8aGsDeO^u!b?g at mgfByt5HWwpNE@=Y02zAAeN8 zc#A$`=*zNYa#X6o@(=K>b8oz!z8zW$1LsnxlKd=Ds50Jz*`k1Jns#LkR zlx|Bqq11s;Dk@<>i`WMR6%>$WaZ{>7jddLou4-ILRSH^^s{G?V8LlZ#r7G554ax==P!*;<>L;0W at uWg?{PN|BUKH`=^C#oNWUZR6&R*8jDgiD)9i6h|K z*6488@!d+-kr;e&DSbFfrkNovrZ3kCMP6w!A?7CM$F=Yp_|l~a*vpmUT^c1iQhn^$ zOT}8`Ezc4S5r1Eb at Yvn1f*xpx-8W5L&2_{LiP<8 at A-E0!W>3^KMRmbG^7dDHe=yhG z-p3L06uLp^_nm|2&gm9CySbH-55Rx#$tce?SopC+3;uIB9%m6GlUf8>d7rHQ13KO) zSPGRgb7v#IXx%Lt2w?zS*&}(@lb;fRZNaxT`1ZoU|HN*UlSj0$00?GFnntGoDnMC} z7zM%8hq*0pYnG~ve9B-we`z+6#n#&HJQi0>6hbw05CBsMWgA`Zz1-2nSoS}miR%v> z?V*X*I3gCa#UqaRqrizHs6}MJ6Yi#|9)mNAmP$B-DS3mek;8-v7Iv`|Z^UDpm$(RWdV|1C%kn4^->B*5~Tn^%6qYX6*EYtoK{_v(hS}Blfqpu=LB>Owk zaI}dNp^3Nk>Pl$hul{aL9II!(ZNQEwg^?P%i=f_ypM+1YIh?Dvt4 at 7CucI#foX#5H zgVfJ%VeBUuyRUuS*p|BvbD*%;-)Tb1J`O0Eq3XcPAIoKV19d62K*0a;G0u}J%Z0wW zs%9_U!dd{lXEn1+qf}bX$J#pyPrI at Uq4yo4Q==PM^E&8hJaAaCu;z8D1nlu(H(d+C z!aYCNBEEXhL2L{xzz2{z;m&q^Y8M|#?@i6z=@3^5=Si3 at QdpRPcCv)}?MTub#$ygX z5f8~BYR at z@*C}k0vI8pa1SH2Q;nP;-RqQ11x1gnSoVpoW+DTO6Sz|+loe8ezwU14+ zzHOS;eU{P%!6bjhmGW_AE&HF#n(9_oaP9MQqAl-$To)6(r&KOu-mYvqsq0y*8*o5Z z9=M^D(3gDRKc#fFkS_2;nvUvE0jk(QER0H6S&y^p7QszN0aX%3;;0wBUq?W}6_fHFV4 zhQ6QmkvI+Lz=0;Z!!aeFI$F2vZDOwAk7&tyL4?zKf!m%-UrzIPnJuSai8NS#67_t2 zd5%ih`lZAY7*j0dDLG2Z5hoXDm at NlgRvAtb@|4kVp#{aTG|6+r76P77>4;%CqAv<< zo3z>EphB#gzY8JpLbobWY%!b?Z%C<>DidCMNR=eV(#qm#q0&Ak+0Gpo5(_vTT3}fc zBr|)lqRbv9KBp`Q)bSo=N}cGzY_75^(IjixozpuB13z0lO7N3 zZt$mKD{NH7Pi(~@@t{zO1OKeZd6u4DarJTZ&*SJmh*klwzP3!Ws*@*Qmd*^prT2>8j|=y61FimdWHE3%-sibch{xV>-cKR zMQK+%nxt2}U4^+C$3+)&PYTJNu4YfZ(|)sAexJ?P2UWfu#qDQ4Zs9eWivBErO9SAF zMMtNFCX`QGqb<42l+>abPk#1#b_X7R=)`IQ)zU_$Y>hWw2GWF{ACr{dNzd%sGmhE( zs`7l3hs<(;u`5{qfG(v9HuXw7{D;+OhjQ=kQw=2YhOJUqoK$wDnG%`8)b7vwF? z4sBs|kBUHToH~+j&@72IGLX3)6JZy~$RI{BJnrQoj-0TXnjl4x68qvy&TLLQD*#%r_kmFFXgAm1!aI>`GfS zv=PDz$R)>OSc{fJu^7Sfw at XE)ypIQo)_5a$W)WbUm{%1F{75f4YH7}3N`5C0&!V=^ zEX~cj{d?XDV;Rj*m>ugKWNFd%zMvySX-W)D}dRJLn@@L^J&nf$W z^2a-lx5_l3Q|xgp(fEpSv08t-U9IPzMNkR_O%lMEk`ErhRBha=;=IzzpSF9HKkbB| zZ5j?J0EixJz``;REjF4`!R&+cBOuS$NT-i|C>bCur3<*RoR5+DabmN*8w?eAK_txE zm;&FPT7F_P`5g$D|%YX=+v*Z}D%9xkn2;e`ZJUo at cw>$4U(3}Bb6<0381F-0DVePyUf)P9U0 zV{0jvfaZ$BQP(U=`?aNZrUY$;LK(ir>PUKi1zALh+^2}N-N%FFAh!5Hx_La#64JaF zscBf$N)e6r6b)QiL+pg492V9`AvdO7qa(^c`3AnpuEeaLkdr6~3G6yYE+fEWc0JIg zG(zI_Vz7P at xp7#m;SUoH8NgK)82EjtBm+J*z;8%T_}7c|EdOxjRiwMPK2eo1P`0@% z6no-Dl!nVmIn#=X44gE)2hd{}|1F8Xkm(j*td1}%$ylKNU0BsUftx~L!9+p$XkrpW zXECMELf6Rn4a3n==K0{1i-2Kj+$-mT at JG1Q^n}6Q5kfsUl0;<}Uk?qj9 z%4rc5s5L864S3iw;RAXxL8TxU6Og)aH at FOwLeGr_cRn{1+)OSI+s}GXs78QB zI6^H4Pnu%ciaKHDUr4?p94q=eH+Qn{cOyq|?n$5e%QY&tmG~f|_`wjfilt~0*EDVm zD=>n0;Mi+yx$wgp at FVWb)@8bSOk;bIB)EsI(%7ari|NTy?1;n}VA}F%^5El;XH$cn zLH%0RfMQaL219{B|7WM at 5rQ?SKHogB(@?5 zjlL{2NK-K*h~-b>RnS_t_j;^qWaQHGE(| zbt%v{l`?AS^aS|dWkAwYE=@D~B&UYYY;GjDX6`9)3%Do1P2vVX=2Wh?W^@%`fa2zC zt`oRsE&$vD&Kuk$^FmUJ3QOrpN(m;VFr*Y(|NSJapA at CSqI!~|f=N*fDasd%;(*jU zs;=hnMxc at 9^Bz$>iy=PTahZk&X%%Wn0Km58=xNM zol5n7QU+gb4 at CRGqhXtSyP8Goa|ljY>OrpiLH`eUshWiUZ}C#QfuC=em--4K{xdIC zhAG%Z|*7P%7dCh)P%yW8Wd*4!a{)!YEWR}IuU`Kly;8LEayzRFmM zdd|zI3Ao+NC7jjG^5yF_{B at Z2@wmjxm#-2!zYpw-3+Ullj)aa`zQz_8g!gwsVwuu^Nt~3Qk#JJ^&m$*Q(~6V2B>%6RRHfXFldAb2 zIjL?fP4#p(l_{Am9Rub#jZz;LDr&r-mDKCbn`EYfbDo~adfCT)DSamwYdvy{rCnK z>e at Qj7vG~=9U at Ub2>r14F!0*d2Hsdkc*|*PXkS?MZSza81D9dx>{cX~g+Q|L8rNb5 z4c|-?8mxM`HvB%>?~P>$96U}QrG;Il>|~%!RvZ(`l-36#-7Tgv)_s9Qmtw3&4NPBL z4IT&DeF=m4HO3e>;xo8c11R4(Px8Gbzl%ThML+5%Nd7y%l)u~);KpCpp;FJ1G*5}Y zoaZ6&m&@c5e;Mx~@s|_HM*>qaoJ7Iy%qu95nLv2Vr#vJcGmh*Cm!bU{%knjHb09*3 zSn3!TKr#OfB_$<+sq!IQ&2LJ^vJ*amUQCLx{QzI3jb>jx at 2$7&Q`*A-C at IX}zJuKQ zlp2@=v81#jA}}dAL at WmK^sY at QS!I-+UFKqEP48*SXRkt57NsM$IU-6H&~Uh>?9)R; zr$+hLhdjZzX&`Dl#%TFN+KN3$r~TE8MBZg=_Y)8+)ZTWjrp=cCNkylI7TAUaU?J01 zk at 7_%Ang6eRLUgRK{or9)_ko6sE-p{DSKQGE35PaIWh))u)nr_^0sWSlLgL4MZ>^b zbs%ujP`JG3?+zDpf1S1D5K%P}6J++U!R}F$#N3dx#3F8b(Z_^wFPBS< zdtbT4xXZ~05HC9js}9V2rbA-h=gKAKeKeFon0Fgm5uj~)%C8lqySg{5ZRaE)S<5^7_BV58^*H;uO&}c~EreZlu8)%Q4`5oup5YWL_}D$l=_7lT zP};8DCj at GXTp=EpCzD5R at EYl2w^`**Xjds)LEF at 3UgLvQn;L2)hVE>W9uPYCw}3oD zX(RU?Euu*IAD4y~W^Beg(&S6|prvO9US{*49IpyctxV#5r$AE!jm(d5t=p27*)vI7M&Mu>Q|O|c zL9@aN^BF)A7;bvJLNX2cI7q-R#8)?(1)M4ABAFIzc0N`1vjut^orAn zXf>tRn36Z|k~_Ura8n9DAd5y0hzBJ%X5^X)Ca1Si0G$uK?V7H`?%^|K?P}XP7=E$_ z5L59tpd)@LKtz#&U2hH~0u&apna)01-OR)_V>2Y7&l4>|pB?>(I6zmfZD=F+(P2_e z%(ON59-06j5}miJ=m0c$wV*oJ!h#gW^Ey88nn5m;WJF@{6EDcfnay06fXG01_tue>Zt at sTPam(#q>hsE#yheJF%_y zzUW%^V`mNauFk5d5a`e?iu6h=3rN$rHl3Mqi%d8m3CZOFU*W?y at EVb+0eKnQvWJBC z*K^MiS&W*jQt5ZhizF(%3!jKRar9Wa;*XTHV=V6?|%aNWlMYdprx zbsST`1&&GLe1W#vXhRAQ>kYE4#INE9LzvQ6C<+4}n{FDK7D^bYZP}_8Vi;*)iEIwv zjbt#vHsm4AYWKO%N0V;i8bcvW52Py(BhR6;bs*b)$i5P?@egtB{HXZ3wQNRb`xUV_ zmCfjE^>Sx}56}h&usk86=wqW+Z8p6ApWAGng}loE4~c5;;o+p(sctoBI;*bMFmd&| z)r9y7Am>nSR19n=Pm2UGvFnGh)Nb|b*MNFR#|@%2ER+-$#$urO%Nepa9`bBD2>~{w zVt8$_Q<`LeenaRL!u~u^aatlw8cBpngNQIGgf@;yl=hIF=8)31gMN70zCmih-%d>1 zQGwD2G|I#Fri=^$OadZ+)4)eDe#C3}-zl>2h@=f%w;7=#M$ zrmYeha|x~j^rb0zcq?8ecaW}!&Zs}?fLdJVk+KZeR>5aCc zA8%fR>yMwdkw{A4y$LId3|W+jmyRv>e3;UIP-acT&)#aDtOW*MZ{TZ;DF?KrM+=?- z6hUD9T(elqb%+08`0oh+f$;AO|6Z269_HDG^5J^1k|1wOb%;@2RdmSi5k(0eaW{~6 z$S8X(hm~&G(dUcdMzHUth#uQFtw z)MGQ2%4K=WQFAljq^ojx8LVLoAjop5uWsS#Bt7qWhuLKaQCcp at x#|32VM&-MuENkp zO^8y?g+tKoQ1bX*46c|;?jZY#!Nmyx-v-nd4vbl_ at YxlISRNu2U2(R-a!`bf$HRzS zkIsV06(LML?hsvOz=-4rU(dMN{7gZ`-6-mf24q|iN*>sW=8i%?R~cw6+&&#pq-H=+bCR-dPO(bt*jpLK*?G+H1*U#@#w=@WLf%=e^krZ(#AB)p!G|I8~{9 zh=UmYsBOX^C%m2S=vn>-ikT?nLxi=z5eb=4{F`e8-XtSXuvk6TUI at _70_Yp~>-wsP z0R54F6uO{4iTAwbf<9h+djRa*Dh#F2 at 1((}562+lG~q!T?A?U!u4;s#v}PTJ_Ixr- zyY0P%u2PGxU3MiseazvqvhHSe4q;Dam!j8$IAl&vZbKWj!jB<%;59x737?u{h4TJ<+Ay z0Dys4_KrHQ>`iQG<_OwMBv1|r32!^l{LRlWwqHB&4jwk at _}f%Zddn<*{9WL9*srK1 zBzp0TqZiLK(f!R~NV|BZY0CT2%b#v)7tz8FDmss!y<56PEL_Q{-_RpyvI9oA{OB&JK zLLSEj7K}#)CwCp at 03kV?Jh4inA)?u5D_Y&NhtZo_NK@)?H;rYt(pQmTMuM+SqDh`u zs?EcBuE14rru9fB51eb zjd}Q$htI at 5W#uyR`odFZAGnQ5HOYx-VrZm>uM&fI8zgfNUd$GVV7632)dQ-W_1NAL z$(?x{Pkk$^+D(p^$W?o33g!TsBo`Jxdf6ea6tVui*+2)Jw`|9ulNSN?tvyel(;pUo zLyH6uiLcjQjwOO8&jQPNIX(n~5WE7yZ1#+{;gQoL*VFkL+cq-IwC62bY2o1-{wmHx zw(5ZrsTM)AfKV)*HD#ut*s|pv_h~y(V@>uDq4J!AzHg=z2BL%ZX*-hHSA%cd2!M=1 zJnP94IFbvCR;>ymBNYS_!kmF+uHvV3AzhyH4?6j$lA9!QX0uks`7)c0{i at C@{j1u& z>zeI|ZsTcd)WQTAI7(D=bwid;)OP_NK#WLoNvKiG?8hsB}Lu0r0Q< zqnMCQ?51KCUj>}1(F&*}OJhx!moIOC9wzC^m*3Eq9O9Ja%bVFPL3STaxv5!GfqI}C zgn>iplppMa{4|tRdcz#lv`-f6BQtx&Xd5_%*6$(z6HBHc>ME^d2cY347#!{eptD%` zj~2?#0&x&+ at fU>`;mdiW^|_xM#G>7Yq1bt#cCe}L)Q*O~VecN>xKGI`p-LH4`6s&z z#|3y-{s!8UC^zq6f55 at B*n+qSbOxZ)9UaDUH`ZLDRo~!GFmG1_-^w4c1CQ{F-3Pch zy9a-Q-?t6Ql$B50KcI?^CpUprS8_39$xHenV^N^Y^%;wDDelR!C|lwNkCg$($#qay zalLJ!gyjFt-kIHr(k8nk671rxWizQ1<<+F~oalF{sk zDCk)%*Ol3B>jA|1wIIs at PiP8+W3QO)R|4|9S$`>=3b5^VTTiv6FXV;C^41(rXq zq1I79)Z<(R)CWZ~rMwLFaNyAL`%o2!c|5^au_ZUS7%0P8D0HH+Z at UFzhs5BCZiSjh z>r(uI5W1Ap_98sco%@g!bBMuxAOnzY3!x9fK}_ZLqrUU=~pFf11#c7p}Q{uNY~=!l|9Ts zx|C^kkUTaFMc*Q~7YfH0EyCeJG+-mmNm|e!TCg1#^fp;6lyS=($ZH!0RGU5hZ`wWl zZ@`#W!)zZv7S*M4PmGlT8sz%JFAuUBV!`VNzdU8c3caVy+*?zoO|o~}CPytjbi(*) z$`&QrJrUc`h0K(EO(d~3FeR7oDPLa4lzvQ@`x-LQ22_p3e$iWwV+k_JQCBggX#Y)% zS^;wLL;c(0AlCB0b8!T?UQ8(p?U-H0B*6H1IEMOS at NjGb_%+%((E(I>2V at En&;Sem zHVWk{xjH9smfWVC22=8;6T)@uR%H?&}cl;1=@e6Pn+B5H|GXu!P|uK)2ml7Q zn*BjRYS5?bfxNKid(~;f_XwJKmFInwnvT)2(aVpSRRqWPXn)-pluDI^eQJmz zpwf46n<%+KW%zVK`)dh0bD|;_76P2q)E7|^?9g~^N=D3c{h%S5IYjeFF?gGXAQ|rl zAa7H80w2L5V+IW{Qr39ixZ>0hr2__Xd@!uNJe22P&km5D-F5ctCtbOxACMnIQ9SK> zKSm7X2w&|(+s8now|%ywv*;Q`%iJ?EEqTAg0_~}VH5@{8JxlCBSPfwZY`ly@fJ-ls2*$K~B4+`7MvtyQ=8_+!A{QWhavV1pTec{@?bhKdAGdd5vE=0j@)D at H zy;P*UO^C4Yc*~YQeIIW5w%2jTX2h0POWa8dk)m{Fo2u}N77`Hnk_KXa)DVl1_-I1v zC4Yjvzb5)#_y&j=0huFVi-y$wbSVr>BB^^N3m)wr&j>7xB-%sEMXHPuZ3{%vC5?!k zLv4y`%g2Wp%O|N4q at E3y8Lg89J#f7c+MwZ;z;WYiM&SW2G-CRU(H`WHG>)Zk0d|1p zt2AgPOv~3Bfb at a^BMS&6`WhZ4^ig1Qg&oeh&B7}y0 zEaVZ+CaTi5jGQ?b1x-w{(%hL|%t84=P%z-Z$>heiXbu++9dk{!?R)U-yDc|Ip1?mv z(l>JT?025b=59LipiZpOloUm|sv9-R-a(v_+5EP$ zH#sQV?5z{`v3#W#tKs6YW+;7+eGW886Ftz3ZP;U<0_oCNps*ovn#R8p0xQ!rYL-;V zk}BCQ_Hg*_ni~dgNPb at k>0$4V32B{v%;pkOr`?m}R#%(5r2)H6b_V1UOYya^4R~U) zXQk!52VU}~fOC68<+5 at Q3t}#^)Wr0=^WAC?p~)UQ-h^*&AP>e|dI~zztFMF~pJFEb zxB&cktKnt0Iz-z^nR9rr9c__+R6lljx67QvyWSJ|b~3yZN;KVjb59|VJK^y1br2HL z+x#N4rQZG=jx2(^&K^jH_JT6ae?R16Hg^TEL&_e#xiD#fj at f&<4bU;n;f<34W&#e8 z`iMC+t+bZ&!sNx2mG98zt(fEg3epH?Li?iVg>Xj+t=S{XA4$5DDwc1k(VmBNV)^XL zmSzXgUB{0(>_!Z$};BE7xdL;zjOlzj?cYOhXdz&%@5lLsg_41BY}8hHEkLs4HP zdReaYoy5O-7jJCo7B(hTXoe}*%9)Z(NK0Q$FYYGf9YK657>+nc$Tr6tG5J+QP0zsR zS`VgllsDBqaYR#*IV_spiu{Gv<4?B!AIRk>*8r&I4^Nk>=bpmP^$w?%W`TU-d8+Na7v4tFMIF^x$H|5C-|^Tk zuora8z&A|dOGuXt<+CDVoj>&aaeC0wsEJhSm=Zi1obb=I6?%IHeP-Axkr6iD8Q$ z%FRRF@{Gnjy&+HcmOM1WUC4 at gMmvWEh=Ma3Tr~m1B- at _pW2jE5GUPE*rk#Q1UbYOr zA(6VC`P)mL$ozYCJoON$qKi;^Gr5lkoi1idM&c!x;)fnUli;!WQM`NojGx)3*bu4o zw0jk&Mk?JpnRlGhDz&rAdBJ>ZOKVrq zF)n(itoV6_jJwQi_8-UWDv{$aVgdc=A*W;z_HvsUN);;s(JRSy#0LB9*5FV>Rb?=* zE%!W at b*xZ0VS=HWVKJ6_3iBhOqp_s$2770KPtz$U^?X$5coj$n?PUYMD4q>Jdqkl2 zW|5wYI=T(@ry0=Bff)Q(4B`V6d5xsdw|U&+DvS%TGKMpOYFJ z%e+&gRa`D#7OAs+jxS)2ZpX#R1*WkvUH{{RoJ%I8sbxX}AA>4EU``H2nIWs*!v&?G ze1EqG&O95D#PZs?K#@9dV)lTE>5&!_WcGzZ5TkD21fN?oD%hoPkjl7_r8N=G-vqT_8DSu_h{t&yZ~Ph zIOsaci6)=qh7(IJ#w{{?^5^WEP at e@v*`9oe8XfFC1m+;wV}t{)tiNn`NNSRjT10Ix z%-&tsqE{F9ni6upLT^It|qP8?It)D3*&lje8>=J*vkxzKDC{8)OPx zHSkS(a_l(vHUzVl%YBUtFXPEq6D&xBiX44q0Ov*Dy)*A3-_S)!I6zJmpFH5)AMJQJ z`Kyv1k2Q^J)Toqlt|K`g`vqdUH6uG<4;Jp#x_ZlyGU(yhBwunA*@MJG!9TYotK8-~ z8X^yx=91$vmw5|ngL_3Pl^6IC-Sxu!bWv>dS{W{vd2n6m+TISNbu4Suc?f;CI7BL$ z*M1MoAMZ62(rNhW0SDNodd+}JjenJ<+)E3A|AQ^=XS%xV1nYRYmIr)s3r%So`Mbb4 z0*%A+zp(sIQKA?;X{3xAo+k9-&oVR&+ at 9U&|7sZc-V%qq?Pxc{z_Hm5 at jn>`rq-Zo zlf>ZdBgm0P44?_tQj5ApVXa4#1a*WpoDyVVE2Y*(pHCT9c_EE*^0xqyvorED+l|7W*N$z%A z9t4>~Fs->0rtyL_W~e4ljzocx--?Yerkp`kv0v0T-A3K2{C;ef7TOiZ^7}0pJUQQ3 zX4i4c?~(Q%?8@^v!MUfb6F$bkF?dAyyUJ2s%c_s%b+;T+>eY91!^}Q>wO(DlxR>RS zCqUV(0s=X2x}Kv)wmm<0zXgJ%J`HdYlEE-jgM8wcy$;dmk|q@{1LOS&KkJ5 zj~sRO)(VRrI`z0fdU6J@=c{NgoQgm_O?ucOi^DWytD$nFwy(3;uC7d& zr%jR0EW(WkuA-$geWF>AJYN+)-sm!6*E0qJxL{#Km4lEQ{=yLW!Y!y=spDNo{B;KY z2wvq-Ynjb{s7Y5k9`fQO at Mb#SlY9e#k=MiDFj+0v_oohO0WMOHqk4a?&1DnO zP4yX-cU$iInLCu$lFRmF+S|RT3Z>s2?rS8flB85ZN>AuY6VZrN<7mD1NWKj%`5psP zofD{vT`fSp{tW@@y8jN;LqE8HYMtPM=>{iEJGjAACjk{O5>nHTgR9O7*k4)zn+~jp1hT`PdKhAD;D at s_a1>HpNHkT<`-YxoO*5sH8^`B at LBZ+;*W6b-r*4ZQ?5 zx3sbd7EwJeOhX`w at i-OqtQS(~8vY<&mj6W};(=J7`2;|)TX+LGF16|$jIN5%Ii;r= zP1S$U&Ixo20kgOtb?5s^T2jRQ;q}&WBJf7;@>_EGx>YK~{((s$`uu2PCs*j!r z9xunUROIk!Z7HhNR6ERmM9yKGjtBkfrXnRiB7Tni5R3c>yliUnP-R*WVVPDuL0F~_ zpvg~ImIry{o{pZ~RcF<9<&H)t$+<&pg;6$Ind>!LCtv(2J~WFCv0sLEN07w-bS7Sn ziQi%?0zx6NFC=DO$wQ$!&2V1BA2#xP$z40B71oyXx?S-gd{;!YQKG^&y^Aj_N~4^l zzNv|DlG7(y4bQqb$w((Bslew!$U<((BrK%Cni?8ORQd12v-29yP>GRjn(L6P5;_ at 4 zy=4zDk_P?~N&a^{2&b)-(^leZcV_s{g%UFi{3_~{TUz5I^&x7mOR1=f8LlDB at O?};)!8yv2Qnp2R}2mz z9pL)#(>#Hn)nZ5YxW_98;{9r!HLivI9XZEA>?F2?446Z&P#Fg!LmW08)iIi)TM2er z$<%Tae7gyO41a=DGCHuRjlGQmU7KOme!l0>-0 zyK$L0xZn$j8o}Llb&uG$Y)@Y;o^5h7AFr(TGnrFaZKtiSEn58IvC3)-+A6Enp6BC( zVC8o)K!q*pYVS0PqJ1;j3d7TJhzlYyjSkPx8=Y5(JzdQaZhlU$ z5XX at 7-udJT@nL}%VXib7(GcNYN^r5_al9IQ0_~#7M4GA)l2g^Dv8|A`%Z{7TMci5g zzm|(4(KQZZ>mDwwhw$)6!v_N|K^`s>`t<+}OqU}VDsA^2t;0WAPs1;@3BU9M4L>OH z*_J|HH~nxRy^ePyCJ1$u?$hysd%MvKx~R3|u7mRy zgOLu9l!iXeo}P4*`}Zgj&&npsVQ^v&QzNN(!zv!aJb(cENf>aL-oD|+qM_;V20T7~ ztxAR$eqZg6wp#I0y>+ at 0xp~xw`z_W at O|1?ShHi2l(hb;zcljQ(m!h;1hi5z9(S%B0 zRFIS;eM*fye$4llF6 at Z(13eK;M_j&Tg~ zbXE|%DgAKO!^8msNDNj$8|~8yXA>>4zd)jAesbQOLS6I_P<6{eUyMYm&`OuY^5IK8 zQ8b4M&$}uT781qG4Px+6r~+lM)C;4I?0~*eZGb1Lp|7^zj z8le^4`j~e!8n<^dIU6Vlbgt%+t3jo;1$pYR-%o%+TG;B{%*F}rzng*GQ`mFE;r?z0 z&jnc5yBQdTuENFdTmt{5??}b;U|{%7qFJ}6aDj#j+gcKS{!h1)fmUy32;2>*z@&F? zXqJ&`dC^N+UY_Fv4vwqP$fGAPn`gS$-^-Gqo1fECC?;j@lHHF4JwcRg`85O*VSHxqX& zakmq9CvkTXx01Nk#N9*OeZ<{Q+ylg|BkoVcttakL;vOUJapE=*_Y`r at 5ce!`&lC3| zaW5113ULM6ub$|>P25+ATR_}-#NFA0^ozJ_i2EjSONhIexbulSleh-rK119{;`S$Q z7vg#ox4ApIzZ3TiaepFiC2=KZ>gh at D^YW3YzDm&N`q94^S=8uYZWAgH=wspxYZr{$!LWq+TMr+2z*h za$)@iWS7Xf+X%qh6^fEdZs3^yW*?onTdcABvSkXrhzc+<#(V{tPzciTRdyfY!BmIn zlr21>6O73HTIkJ4s-#>S)oAFK6T(_2dk815Iz;J6v6$#F^ji8YYE>e73xxb+@}Q=V zrMas)*w7Caw3`8ibssGvV0Y4(wLZrB0kDhGvX62tW; zwiP3K!$Mk*N@%RT`}HPN-99VE>lp1x6es#4;r{GJ2f5S)xktd~IIAHtK*QUp4TU#< z7bOObDOnF8`;dyk(@B)}R+Um~sw?GGk=I`cVry!MxP2D#Ytdao&BSPM7&O74KF`g8 zp1;=%Ik{huRDPLc=k$+Qjo9`+beb(56Z#bQBxFhJg|E;_mN=TF>mylS!7SLN!3N3H z)nTFk;}Xvxi6MoCG&t0Uh+2dmFiflXk%~aMOcOIwHAqg))iL94l#jd?0DUX7|#dXYGfgzyUtQLSjKe{f|6kyr~&pX z6p}0?NxC4l^(y2NciUG}TL at W~oo_VT+6{3#YF-7b03nH)S9cJ4Yc}Jr!tS6B9nd176P+~ zo^QZb4)j28p<*p1tLCk35ztOvO}5PVrs}(p-h5gNo*PV_IGDSN!C}GVs#7kc7b4ao z*JB^FHptv>t(@!KxZ8sRI(e=00*nx_*7bzvD4{LT5Gmf*$Zta^yZyyVtitcxP{EQ= zb&<@!Jt|<&+eCfdHVOvqciw0a9$ujlvF>^B?Sb(0jCM+cm`I`bV`6lI;xRF?f-R~2 zm;&K&doh+Dkjj*C{^TrJxO$=8+;ZTgd8H6GS$wo}wBPG4w9~z9sBA at etGzO5RKeq; zX15zf7{GClj~di&6k&%09-r&x`Ie|Q<4v+2Ise$KoBvDJcORd1>3_-kLc3W>RP5uk zlA=|Q&+7GGYW?lpZQllxy>Kr zr?i*VvRoxI57MPf1J3t=j;}^O6E at GPXx9@CJ?~jbU#KYfY4|$6 at Y3Vf)A!TbYaGGM z$IiBwDaEM5XCr*@d!q?PKOpR!)}|A!`ay~+Z?`C1=~3;~kIQ*qd#DDn#y9QaAW}{L z_NsyH(C;zfw|;FGymMuo5 at L_F7c2BHckit`s)(vx84ZZGl6kv|uOg&sJ7{u6+d?B< zQK?c?H!++UbL3 z`3M;oZCM at -Trtee$X0VRY*hPmGZN2?~{vXJ7RmKIXp z)c?AWVo$duk^TSh at 40XV@s*MvBKbv%&@yACS^* zm;7~-|1ZgZQ}SPy{2a+|XjA^=K~j4pKU4CTNq(8+zc2agB!8FWAC>%zl7CC`y$4gj zhvW~H{Be?>DESK{zew`mmHZ8oKYAGTpOpMqsr(MoZ$~8cf0z7IlD|jtH%R`6l3yYD zOC@)IS0wB)NK-&^wUJVpJ>l3yqJ+a>=i$zLt`Ws;vG`8vrTE%`&Ge)O08E|Tx* zgyTT!pOO4}$?qZcdzbWkz2vWv{4&X3BKet;|GeZ+ko-u=?t{|4GT$NdAkGzfAI9mHhW5e}m*7ko+@}e@*fqNPbWR_4`Qv zP|1&#{Hc$T=IuVejmy2Ao&jlx9(S+)X(#hzr9VrANRNR zGZ|63(jb=;zu-OUul|twZU44D>p{ZHCQ1J1vUbz8_g5Xh(uh9pZJF at THG9aoiykCy ze6A^(Gifq%O(|S{EQ{-=E)#=GGqyH6B4JhQ?;|=3%U8( zS&}zCJJ&QTEOlsD>MUtOU}wlYnUScAo2-j7YR87*IL9Suu~6Cb$(d#o{Um?$%o&+n zMpm9{eia(Bv(o2G$jx5#e0D}^JeTVXhfH%OWalnQ=ICz#|D5>b+&ojFIR|HkGu at nV zP-H5phx{HtL7GZ)CY$o%cig-MFz$0;+OZs$o51D5T#&VdC$tUMFUo-#HHUh}>{K(U zY^pgc3$Y6z0vLvu!cW*D_%6d&rO>s+Kx4vy)R*bZAr%Eix^F716Jyf82bNDks+zk>S4HrJm5~66iDIayUh6PoI)wWZThst$1OJH z=H~*YqlsEzBH;zjgaeoiTOMu|vZ7Qo$*<2^44_O^rKF{&CUeQEMak(IDXJ{0*+wBY=Ci=*`$Jz7>`IH6GKe}85|i_+GJX`bNb2>veUTyWLVYh ztn<9Ki=50SGT6@}S^^(hH8?HX3{*fymeliH0H$n99Niw zNnvdyXQi8DIV4e7Dj*-S6|`*!;v{Ka;vh&x0l%2-oS&^qceNP-<81fPmi{en>0hqt zB{OUtfF|?jXTVOEpPWa=`LRW``jg6oaxz+qB5Q at ik(PGpp)fd^fQ{OKAX{b5GmR$Y zOv{p at BxKPaMrSH4-o>V{Je*ejRS{+t28QKDIOlF=b~;`Pm*vls$=W2BMUIG6O*N&f zG~-kRb&giOKr+t`%NyHzJ>{8ToJ at tP#RS7 at GV*dVlM7v##MwWDKQ4#J;jVHgnF>j% zv)f&tluUzmMdTE^Mo%V-iHU(#2FXZniWlfSHRq<7T0#&HwxUVkGZ$za=4WJ?FoSamlkhxgVMz7rCTVBP89#06RPE%%InxrfQ{BT2 zapPIT93wkkr=P5qwcqbF=n4=?kL!4R%ZB7a<5G^HeiVJ+{GC9;RP)RnM<-qztdZ}; z8d!fW>|9crw8+uWMZia}y|s`MNwft~fUg1fOZ#Tae3;dS5RK0?CFhx7aY41P&H%yZ zN;^`{BR#;~H^Q~T>7PDtTAnGF&0- zzyvg;lWjq0!mb4^NOmITj5GvE9*1kJzbZW&3Y==nftf5#&{ROS80DO=qupZj$-Emn z4=I_Jc?LO5E$iTsaJt-pj&4m(IQ!e04uF=b+S{=yO at Mz9xn%XX;1OxaO{x9px=1Da zWS%NH3p=lJ@?9AwL|d3O^?yz0=Sl-J!9703)!uogR)xC#{lBr^Trg{A#X;NLr=x2F z$M9C at P>N{@mk?4*`bWtSw{R!Z!HKY at OK8*vGX%SGj6Ec(2 zCHfbLbxNMYy1*QW2k4XnNB~Wi?IOSpK!Fl0LG~ecy1c!7DXs)9c)^^tBqOH{b%0qU zyh6iW1vv|F(#wybm1R>+$*F~I$lp0Gttqy7KsHbUqE#6HSHKr4eOj9tusFk%kBcg0 zKGH<61Pd`KnE-8;zlj5!nV$C~P at h=eIG8X_YOx*4Fu#Q+90vqF5FNR5=qj6oG-Ymf zrV|~>va at ptWU{ie$bw2XbJ^$vMU#R7?c^o>mYO%miN&%c0%DPgOGZN62_HbxD7um8 zFW2vEX^uF5OB0Fmlc}&9rDYQt6KM;V!DY6hvk}=N{{ujx)ITDoWFY-p at DHK8UCD6P z1Lv8US?HoG<`qf=eV&XGQqFnSY8 at r#0v1~A;!f$`yOBQmPbPP`wtb54d)@ae at _GHv zf}D|`rPw}sC-tM at Wv4rQy7f$9AKNeI%T6Bsd$?h690%k!%7jE+V?B3czwv*;PEpv#vb|i*O4a&j+ULBQat6v{;tXOKW at 6SvEP6_ z-#`D}JKGO4pZ&1)qpco;m1SOYHk=ID7i#nW?r+PopXz9spY-qE$yH+`(l)PR&n)(S z>9l;O>gehrLBCutFa7SNzMD3Ce|GuDkE4!l75-K0Q!wJLjCpOX at 4F$ZJ6zZixL`%Z z*hR{}XQsX(pOtdu&Xk1<=Ot(MYKSzIPL|EP_2)a at nM*&D_pG|3e0lmF=C6Gx*PG&P zTRQ!|br-*^Y}pjk2n>4d)d#gnheM8Cnaw%{xoINXim2ClZ%l%jmaTto{{F}J11 at e>ynpmNE at t8{zki#5^dG?kPkUOrp2_RvpK_^0 zo%;4O3l;^gow;C%|KSdo{~`LmHE5m8 at 4JtDmTTT(ZXEqY`M3GEYn>GJ^S3YyLYeedTso!E!}>3ZT(!~ljFyW z-a7KnJ=G1-Q*WJ%yP3Y at Nc!}hpa1H;>Dfu6Ht0@;2R0ab`hDB at oMP16C7$f=>vPXd zJD0xp`fFLk3U_5pc=h|_gFP&1JJ%e|4jXlG{?vE!1L_nL{da8Z>e2tHfnL*gskiSP z?Ek}tH)n1P_gwJ(tS`h9)x!?gZ{j~X`DE{PXJ1%fo%+GRTPc5h_{jpZ-&>13zV!C} z at Yzuv?4{{Gxt*uWyk36p$9K9c*?MtZ_;*XAdu|T+;I*S~2JZUhw=LJtEbDjfwEwZA zKff~W;<1~}-~T#4%W|skp{~1DzA$iG4bGVzuf!LjzHu1;wlLLk>N&9~5bIE%=dd{Eyc6j!Xr+4{p{O4-{yL+DVnrXf65kdC! zVLiLQJa5$S-3bxlo_jM>wRiHDzw*V*=WE_&FE=jR`+_h#Nst$b*K#Dx>u*$qb8i& z;4^#QONlvuMw%AhX}UdR$L8u`|1!VPt9-;7pH=sFe%x)lwWLGg*)PMQuWuM57T(U= zr4tq`@41&9GvsWNS6tx at P0>8t-y-6w_w`CVEw2cEJ9bA0t3?>_dG*QY9|QNUi8kEX z(eL#y-u3(GU2A7wS=}t%uoGH--o2~?2^aDcXYbe^oVn(c^`SwESH`nT)-56o%^l|0}-&g(}s;m7y zIHCTD2}Sqk=bJ7z7C!sb7G3BluBUJBkwZFp-rAWk>3gegYR*|x;jrsPa~-#@T>Y{7 zp<~$_^}mc=bFl8-s0zytpEuqwNZk2djOmNDlU7^QeqXNcUwdzpZ`r|hL2-0O< z_q_c at _4QxgJ=tj6>9cOFwbzz~XNP?_POAC9iOeSGOd;qcCdUlu={ zx#7KMd_Uf>BD&qC1zc{A8&3Q21m<_t^7n at UYSj9R`nE9ha{7 zGO?)gUg5Nr2j?03?u}mg;++Aj|M5kK at 6Ws&{8dj`;%_sD#XWd$-n^|YREd^%`I#SiCq9=!EWYrTEm*@u+_u3tI%!-bt) z9 at Kvk_^hR3V9|y*p4}E&pVJ(CFhf1z%D5%@4`0}{&~)a`%%Z(d`zBml9Ib2mZk_Me z8y|Q2XH?y at 6}b;X-@^6(^nz-6*0B=Bj9n8v&aCzIu~#4T-muK-S=u$uYwMKG9bQ)- zVUCynJ at CTyX#uHsd-x{2)u8l?_{eYU#9971pA76ZvG#KBKKcLZ`$X@#eZKa8s^P?wowf(Jx8x-5BZYggmtCEdc{-~ZRpZ~pc4QRwjnE1MR+ at JIdvkEz4vkBq*ZpDnCAc{>{X6kEm(S>@-jJJ-+4nS1X$n zc6>E@>cuY0;(saHHARTIIP+YB>V;SSOq=oD-#$$m at rHf2;{Fq}W@@uvT=dj8bBcS8 zys+h^rt{Yhe|PcZXL*-qeLv>P!jq1x!_&9^<`uZ)a`bZpuQRI4*Pj3AUwzJAfbSCcY}y@ zcZ*1ONw<^&DhLB8Axev20fK^x`dc#t#+-AW at 424$dgG6G7B_o;R@^J^wPV)a11H`t z;2!++H8pnU$xp;*V?*z0-E(bI6p?$+&o4>LbbNA|jn1i`8)NzO@|DWD7gJ<*lk1jc z6HQa=PXp_Cp5YamB87%?M{S)~#tj+S#wdRn^>L(RJ at 7yMykAL*eqcyPxA&WP>iztn z at t)LGSa<1NwZWXec+gXi9&W-&AGs6C4#_x#Jz*U09^q-l9hOSFo9MOYkiaX=oy5So zmYgL~oK~T2p8oO8$<)4p`IOy(j+~Jy|Lins(X2e5uXos-8Z)Tzy>2PD3*5djx|PX) zHZqp*no5k(0(qQG^ho@>I{{HMJJQiXN_dftto;!Y=9$4=6na4`HOB)+pT7vy9!d@| zE7lCXKu;G=?)oe&7r9uL-o{)yjAvQ?#j&u$&--n)3KiE~s!FG-Q~gzy^nsftd~bz{ zJuiC{!X=xF9&qjEZpmE8EC23Sa3{SpAL;g>@ihZMLuZLpQ{rD?U z)n2xUuCYEj*?vutrj6jUR*OJZVrxUxY)9}s)4k_LSGwK{XP{m#2w7Nlv_wB7F8^@1 zkxDn+G+uCH_S}nWcBfiJC-1CtHuOayh;EqA-*dtV$C+&Dnoxc at W&2UcYi?eL(o8Q$ zmqFtzf6?lZ9LldQyOq)pyRXkxl?+(P5V?A=I}JZ^zFCz at Ll5Km)?6r=jie9fSRG-M zj(5wiWbUtdq~J>=aaS<+>ccqtMk_HABotm}BdWnicI{pI;)Z@`c>1f0qv2r|4f7XX zUO~i|y7DSLSG1klk z-kh{LpXfcty?w$l`Opr#m}Np{aD*gZ;(NVhE^TAk1_8odvbj>V<833G#qZ{lenhtL z%3IOh*2Z<_c-OAD;WEpo`iMW^%gp81a%Ne%l6GGPg2(BsMS5HhNBIn%GhD9LSTKRwOS9zGwJ5}mU8r at LF8Ck4}B*-_q|+!@EF)0tHsZF}=pD|UC|d><>agxfM1 zrS15fKaEIF%Q5`8$@&VP!A{NCfAUk at sOjssO|#c7#S!4mWQl6SUQkz1m+^* zbH3}d`#7lem-Man9aqF{0>l82ZBgWEk5=a;BI8(jUazowKSae0%4 zAjn?UMB-`raCHAj**Skv_{|AJ_WO?Yk)D1NA09t&nmDFUQk%E1eEi5(piimFq|G38 z9fengL0)g``F?+#fFEU9uWr$>k&5JsIBGJ*mC#y-^}0NlI5X>XMyYi?Wg`%eICZ6^ z_PP>z!ExT&qlyw^GCcZ at -|l~&Su0Mo(mYXCGvqr==AL5GYPm^(KZ~+|FGBvb4-_V6 zZV_v?5js3zaJJo!Uo$H at n{A$2Krs^`=<}kbaQ at la@$|9j2;wGHZvR at pd#_t~2ot)F zB_3<0G`Fo`{ADR2nf6B$l^tKC1gGqmeN4A z9cfFw)pD=sFeh$H_BH$nqJFaJx?0jTHa;i6a6M~PSdYoEiY7~*i=Hpw2{@+`}7qv z0~|X$&21)o6Vp%&{;7|qkh(oV>ieTOMc0FfwtGGuexPenGu=^QwwWfdX++_(iPi^t<8bm-WtauU^RFUkELY2dqvbKt_uJ4q=iACWPK=~_3QVs;9x zZ?$|%JZ!R at V>J7Pf@}IwMh!CKTPDi}MC^U>Odp!dg)sjgvwh1DQ~y at -pW9l`4#Pmg*=j&sjbKKH$1^-_80 zOY59dT<7{1y5>$9mVb&u~0n<2mE?`=wTMmjxW-*5z$FeFjbHV>&E at 8BaNl?6B} zZ9x{ULo!JgF+tf|3K2Qv*kK;Nw36+v`m<>z5rXG;RH$1ogH zgLsSVpSz~jHYRpI$7$_H@C5}TM7hP#`Y7&cC+?I6(#~`D$>Q>^;Ljc9!Cgna{TX67DgYN0 zF%9D8(YkML--ma at Ygnw8Rf+j-n%9iGHnJ$dPL zUWSH0?d_SK!X at XPT%pKL4PncV$)Q;)sgq~!Eb}tiTwN$$-9o;;KO4;Uysyr}(6G8( zRzByglid)fr}KB4^8$9&%%`uclM)i2p<)tsn3EUT>Ng~;d+)66vTbL<-+p>)Ctskq zDUvDCBY`kim at cQ|8%0QL+o`fyAMv_%QMWChpSG)to$$V+H}qyti*NWK at YhWJWqT1k z;WOGy{V6n2II$G%QpK#R!Cj)$y`s5&9dm=8UsURuy+ez$3A@>Om;P$G_dnoIVPpuIIE8c$)Tm7 z(mPDU%D^V-{QM#-{IZD=WH##HZAeqUJb>)dloXIg3IiLoBB|z8hDuE!=I8 zM1IJj3g!tTuCsrn$X0>WqIvVpU!H5x!poXZ(&w`Xn_}}Z;-l_(RHx6XXmxzNq!?T8 zV=?P&?7uGXdS&a!kMF%*&yb0JLxZ^&gQG;gW+oE0*LG-omzG$Z7Yoi%Ihj#LLfrWE z5oPsY#IRGH>9lxIOmHJyTxrfOL^bg*cuSf+DD~uj6P) zhzmT5(fUgJRT;0|jggrr8T(U;qO zv=7#|b=P}KQa(?oJ*y_{SZijAEzJ^`wF^DHe)_SU&--y_#mZg7qfQI*r+F=BMHX)M z5$1x+e>1f$i<7u at Td$6m^%nAnBwBIhA1EP=H4A0Vf4Ts1+hZ+F!fu&}E;m-KwU8 zfq|lZCo)*Kjp`{%?v&G{y?CV!9o<6+T$waAy*2EkHKnwGpwsy3uXBBpC)IR_=_yZa z6t!?#`=t}@tBC};(?}!#t#=9*y;b&#iH;sxxqKI>L{?de3CoDsv~6LM7TjqiKFjeP zibaKqM=kF~o#yyB*fIYW8JpMreb#h(Wu5g%$HG1G6679xRIsFEVx7M;lC9NdkY-nU zMPBUccQ4-;7Iuw&{#Uj?Xc3>=Q55xTA+D~?qsrNck{l9BX8Vr*It{1S_S~V6r;fPt zo%)2tr7s8ud*9;4`qkkhXhSKeHCqmkip7(shfa`PUSA+){9;Ztm8?aQ%|k+Jpm33i zy}dWY3~M3?zY(zTzkgyoDw81JT6SzXX-ug^L~1m$#*Wl$~iN(+ePp7j at xnl zYS$M+x4e>1F?nhtxZUYCT|J)Nmh+E%;eAu332}p*h}Lh!l*K2&z0h0wc(N~E?&ItI zkH6b@@YXo^%Z59New}svny_Zq7-nzl_3o;*z$ILpEzz^4cW)AzInYR&a93Cwuk~nJ z6i+ at iH@~-JdGb)3)x1rt;^ZK+5=|bRiq;8rXqgswTzcV@((gI z6bLr%%1NnzmJMR-fj<$Hl{&2FCatt`S|&Q?nD(Z%#$_Q~D_xHc37zH%Vy)fom`fMR z+co at -ENXW8KfAJce)TG|)||fO`!K!2 at LI#SiNXe4-wqi$$z8ct#pkea_GrNTj!W}m z?Z}5Ex1#A4 at p^;TKc?+owO9!*`;z0Yvnz{!SY|%_Epd({qr(G*;hu&GvB6skABI1AiZl)?Xd-|DSqq?zPS-{k$qEM z7q(3dPx&;+U9c0I`t>v7=aXq~L*uEobGpy>A}MAhmd?+*eCn91&xwBdiDm4?Ih9wF zc4Si%WtQtt*Qc7E at zez(O$+fxbBBe-SDbCf*cc7_jDAo)$V%bpe}3A3fL=(GtxcIIE>rMlXy2xD#2mT zD~Vg0H+hYdA+1;xh=ii5^uPo(D6(4TW`O+TvRGmPL))ZRsE+* zHUsI4h2HWNdR+D_YLJQh7)hZn}t%r&!ChC3o_A&lzem}BONW(3 zIq}12s>Zt?;!V?a&&_TKp0d04;?AUKYhMHB`VAsPl+(R=^GTd=9Oa3wmXEemFX!jH zg!IfPbu<`sb5 at J^zka36IU-%T>oRw}`=Ql9NtK5yk<61}C-&5;o6bBidK$^X=5OKj z$ZW=uRgQeOcJmQL%5U1puWy-KidR|LX at 2ALjHM^`gxOeju({mnNImv%|FQXHq3M9QL~D&*mW2V_BQIbJFPhI8NWpZTqgkfD32#quh>9Dpg$FxqU?MB5SFn zp1`q$rpUaV at gtriwv~@d4|m=qTp+k_9AcE~Jhs9_*SuZUqOVFbCqCNyI at HELVE+0b zAH{tyMY}=r!})Ht)&nMZ16+_H8<=cO1^RE*pyNk5u_)XTAjRo5{VtY$utUH6A?hrANe?&L`@y>$2gw zL4yU2YIW_OQlD2dPE|)oxY3?lr^O4B+U=0wxWlq`g6-C2Z+P_loV$aCzc~f@`mx6j at h0jM5o_t(bi at o;w+suis`Y-)!q;h#N3>y at td8#&q;mdM!LHqUD|>ZzFUHV?N_c_Rt4xG<7#5{eaY%ASu01%Ad1*e;^QysTYNa*( z at 0*t;GVFs0Se{Cl$o5AMm;0Y98=1HX7j?YPZs_M3S^wbihY9^-6HW_xwIo|djxVc} z`UFxB+Duk>QPj2e<{9Al_n*%y`w_rKbL$nj{3nfL(sT^7q%Dzn?$Ue4Y4%LYc&idI zUf at P;%SvhixzhEcwY9*tZ124!9C*QSBWDL>}-vke(Rq8v!{EI1A)&2KN1dNC18T@;?gp9f9xy?f_c~ zAaOv{0q^biza|hEsDJQ&|GNMY0O7s+{ci$<1#mvt;s6N*0tdXf-~akR7yu{j_rDL2 z^MJ?p``-o#7vMUuMU^)ah!WtB`~80z2n|F at go}gee-9vMLHOhS{s&{0=oH{`utl|3 zC=fZoZ}$7&5XdpWnfv{J1IR_d&-eS^0SFJ^Hn2tM1DDlAYJk7)_dhBPHK_mn{r-0Y z0{Vftf4~1xZ3_H}i at _EZKNtw;XX2Ip{=W(Yv@>zqe*a$w0@{IiV!!|GP!C80ZUS4B zzGxsSfIsi|zb+8EKlB-|A|=kKZ<4lwb0-8zxfaL{|L+e z%b>sQe+|q2Z(-U0G?x9hLVw%;mw&MTJ}mn$g8sJuS6KF+ie>-Lu%l^l)?7trR+y1xy z!Ttxa?7sr~+y38T+5c at U`=7zG|90qa`~UV2_CJ7S|0U4h_Wv5o{?oDSe-g|7o1wq$ zf9D_Ue+0|^??Qju|2mfa=V00Y9G3leL4Vu-Plys92cpBr!J)>7K}Yd%C}H^c5Cc9A z9t}PmI);xUMTvh1qQ}R5VDz at lfdx9l;ksrRS%@Cr70xqs8yRq=#S-6>11Vgb*=A0FglW5GjNQ zkwJ$batIfqfN-G0=<^vfCs))`aOQ(E8EXsF3D9qU^y66jz7T{uO>#gjaNUoNUP``y zisa_wVCrP=w!g0Q at AD@&)Y{koc>Z({`a2wTLdDF(!|Y(==7w6&YvE|l<7CNWYVU+8 z$3Z+(n_ne&MX&7NKmYnm4|XQtV{KuAdM?(?)eMz|gNeJD^OM4Tmzsh$Ij#^ObYT<@{=*hvt-P&n? zWi0c-1KsEcwb9Gk(F^aH1U59(d3xcg;5jYo2jk^y3Y1RywM0tG at n5Drct4h}BPAsjp$0vsY7G8{@AdK_jP zejF(r<3IC1$nzjCR35az(E&#f90PESz#RpS3AkgxNdbrI9|va>cN{ojQ3VhYcd2K)xYQXALI12v9P<`6;U5MQb~GxIwZ zbo`h5@$)%OqInj>ZSmxCr>c;!j8Y;<x-8!$e3sZ4V}8&^&rM#63lLfwc7+4Ov!&%}4(WQq|xv_s^y at -&5N%SM6 at OY&hI zgxciqk at Fko*D@%d;;MI^d`|eWv2S5?_$vwL>L at HRyiss-P1mrOPxv(ZbtEjN4A>J- z*Q&3 at m;%Qi>>Oo%gSsE&cN>-8M++Fsiu>kFW#f=6N-U7 zRAg%%g=IVg at teY*=g#kS(7i*#Vktp+4s$RB{Gf7x`Ha9)!RdeZ)oN18n;XgkV at O!5 zGzdRLwZLAjc9pON*e?x8Kh5C!kZkp)LN5rvfCNlL<#V!J;*gr?nKTMZVgx*Q^{E+FdUGt^ z6zM(`mWPA|DTDm4$^^rUb*x-wk+9&S7`DKQpFDHcW|d_~wX-#6X~37u_mZgS?)cs) zthg1EAD&;wTO)xnSQ8(Hr8?784H7|p$ALcO)pJs>5^I)%M_?t?nEFHEcpfL#!T5*( z at n6j!BDfJY7)!7%Z$0 zWp8h8O*Jl`iT{Ih2Zlz1@<(9_L69*Kesa*IHC^YU_eNon45<1%6p8u#G5P4RaaaKb zV4sT7Vp}uLi>YI<#tD?Y&?EUbPc^SAFj5w6;u^@pijxQ}wCm2(u_FAr-pYKc&WC`TnT!O60;49V^J? zwWpG*n!qi1N2f*@D?C7(<73cHqV&C#O_5~H3-5T(73gFQkHK;%KzsLxeO_j$tgenE zl51^l5A*F at e18@zeFBq>5}iLIWf>F79-ovgkUCQ|-5G`D4Wq`7A at wzjmY=PG!-$rw zOuG^X>eo>my7EWiW3b>%Onuw8H251cMquqhV7%NLCauTf1}vtGUBHP}8-s-!qTAOB zYFtnfkspVp?*M&r$a=%%%!uRZR4T1xY;%tmUajUI-uz*7mOwo@@HX4z&QJuq;(*qz z3L&-1LIJu@$IeAS1vb+^Ujusi8AyyyIt(SFf1{ougLJ+ad24ZX8;Yd;4PYLqbU2WRVwo^Mwla z3MYxwUe#BxW*e3AK(9ka8!M~x_!HriB~X=VIwHptv>)<_8?i{7{26{{{RM zmQ`KdbJa>Zun?&%N&hVDjN%Bc6$DWyMh_X?Q| zX%>aE93HPtP;M{d80_v7&6NB0L*<4rfmBgvC0UJ*OOi}xCZ}wtu2kVsJzvks*I(qN zw3-Jc=v6z_&7Y_?PgHVGlR2gHj><*+tQie!nSI$DbMiZ^dPzATz-!suv?>g>}`}x*ySi9 at +TBJ7?b%1wEPWQ%K`lFywPlcT|6R9_NScN2RcYi+3Nd{A^*+ zg%$En98)Uyd#w_^RAWUhT>jwjM>EB{>%0CRSK3Ym8CIC~e7~<&_L7kNn37 at o>vPhr zmAVQtiJCPr_JX53ci9x*FTW_23tZguu^A#cD7SUQ at SnGnDFuYkvoQ-hq>3fUEm3E zM8&Wc#AmUn7tuteq6l$nL)=goMc!{qSBO6{ zn9o(8)adeTN`=8;T(L7<`XnZS-+21O zHf%NQ+uJ5W8*zB%4x+bW!>_OL>k&cS^bF~ClcciQa at n63=pnXHlW$7-Q_AO08*>*J zS6qH2Mnk8TgIDz9)*j6}0kYAknbT>~r8~>cRDzFOjm|-*RZq?;wT#M=@2p>Zfn03s znWGez>3r#%PkPe#4rRrqZ1UYXrOFl={!iB4mtDt92}$~DR0 at J@Zai_l9Wc<7GQyN%ZU8g(~5EvOfZb5Xn=Ek7ZJpYXtk)k8Hz z#eC)Ku8UntRd#47Z%!c#a8pbc+_{6Og&FJs>HDhAgW!hx6!w45qP-Y(#X=H$x zu&8!UlFC9Z(fs^_BqRCjw^hwAww&Nc+?M<7%zDkI8}Gug8|||+ at YE4LuIF6L&sjDK zFL_)qQ_Qhb3D2kOh}Ty1)*0;QmJhUvSkkC$3E~woEZNg&MpT|D?JO6NP1bfif4wgo zlIbL23wm44$S!iKYqoSjU$rS8E*GX?`^Kaifj^}dt`N{fjLZC>8Tu(`pn9jhMy9cW z$MuzZc_HJOzQ-3EU#KTd+VMv9qzKbfyvxX7mQ at RrwM~kEDW% z#rEM3M1eK=nxg^^Z%%bWnOJUsdP>JFs!0tv9$(UNB^jM<<&wARzSOaS?)fuLj6B4c3C+u{dHIVgRwmmV!w)52z1 at HK$)d|E`Lu+qPjYn2>xtv1AF!Fs zBW_6tnbQ*SltJIm)jzv)R=)V at bD{5)+`eg7`EI)Zd=9 at m#pGSIRh|FpnnI$TUYmNX z$Edq-%ahOVoVjOrZYL|>yT~T#9r!e9upxYX_+zL-n4W5Jzl3Oie7^4GV#8oW1aa at 9 zC|L1VLLm|4ASVGlhm}ib>DByeuC%-H0SrIo16c12S7b>neK^IDq2QFQ(4Y{={q+WK zJhCRTY2342HGD_Ukb-R9*_Z$^OZhckr7(pcnz at dZa4Y2;nOtMJOaa$@cmBTE)BT;- z&&WO`QBM3i{P|PX_dLA$>51?s+_HCcjY!@ioLrBdcb}NPM5rFDZuKaPa_dfz1WUm8 z4uon1T|0*{l~oxx+t4Y$Oie_|?Z4qSLcOuK;w*vzwBUzUf%8ZRW zdfz9LhBOZ9Hmp at E(6FNJ)xU|*(9v(sruiCO_%59!iAe{=DDu4Z6DXe*AVduz` zA3?qAx%0*p^2zRRA~ePK0ycIA@!notQ0quY2$p*g at VVUlT07oGqk5bgy9a}%uxh%H z{Z9SeNx7n&D at tqlGX6dH4xQX&43diB=RBVS7garJCos5kszo}ASeu-+P at KRTjGkF*XcIoK+Big; zckc|GNmI=r%`;k8J)l`fjkmDT$h}bf=n-}mcndY- at MDRKQ*s7f6+;Hi3hnCQgW>I? zrem~A at s}t_-I&g@=9Q_6c)>3 at m1{lZ#=$b1RsG#90BERwE2{)H(5p}KLShL18hy+kf7#3 zA!;=OOC!Rt at 6#=Q1 at lo@oH(k!q7K!cNjtnFMq$BgsQV at TPlX>c#QOZfC$ZX79xMMO zEdBgg at ddD05Q~Md_!Jg%Vex4!2IHOS&+)E=Rle0$vbSkIW3X^u2-+ng(&xrX&yK}% zSm_n8SP_dKU*MYw;{)x9haNwfgIGL-#ZRz!7>h at +m}uZmnx_G{J`O|OKdaH5P4G$K z92$e=?mz+8LgQ2b8+e(i^R?M)e9HVUbK2{R@&Gf~R$nuvS3~FJiIthF9aF|8ISe6+~MV z4p<7qn}hW|wh_PiBNi`V>GQuHqh&M($|H>_kIzP at Ur4!%Y=^V;GF9-K4tka0l=1pe zSZf2S{hrli-*W9%`Z@~By^Cp|n$X0XNrQbd0cA-XzKHAEP^@<-p*3hPO3eNF`RjxB zfAX+M-9W$xBrM|^=6>qN^nFGHx=~naCuE$S{su9J*cf*G0qm&=eSd9auhNI|9 at jW5 zjvRBpO`3)QsqI6g)Im at uLfR?U#-4D;){#P0z6O$h*L`EfjpF^f6~`)(Y(uj5RtC4V z!I=9aaol7lHJ`|)+~u4rvj4)(9PK(7wlfS%ssjC8qKZ835F|tY`h#@G<-A3c``3Sr z*W~!;BofM0 at ZP3379dOZiSFs3ZR3*-co3z3pG;mXbH${nrGXlrSY+Pc at mQE&D8ba( zY>893$cnrBJO|cxjnh z0lxy<9pS5aoyj^s=g%mrHTFpb-e7#vD)_QWu}GW^Ua{0za!R0%(87}R$K&}{r95wL zgNE3oqUYbOqh6d~R*iWJx0GotK2@?=gO`xfA)B@!omN0~Y0;rXqAB!*lU!bwB2D(! z&}hj{x0^oS#FdH%{1?>O^x*B!vY6H~5 at m}I3zQGJwusx>G76rU*iuQaKGMk*)-IBB z!`CA-ksf|)a;A>x;gBV<;^$0rJ$BU+=ANAxBFCjjx!MBv#8Rcm0)o71?%O5NSogQX zcCOC)DgeHNVe%XE!Pm&l;9ZQyb?*4brK%eiF?9TzHqS(nu9ElNjDKniDWIV#u{BowFycBJ?19#cg%{ zWx9>EdMEq&CZVcMs!1I77uooG(z$m|e`jfWw&RAS&j6p$O}WlaG3OMmguX9lS!j#T z$2F2rl}dt_ at 4iSy!rNf!ZOMA!3MC704j0YKq$xp^3~;=k$^q10N!&aB$%^0}& zU^MlON&r at 83@==ItH|JFaw_)&0COo@}Y5q#ea*Mz>=A$#1jni{JX%GZM?+4e=;+ zzGo=>>?Y}p8((z%%Clqen(SeFma)exMDYyy{Tm_zlev;|uxl?1YWMT+tWPF{beGZZ}fQo+ZMI|T_D z at M^Z?kUe_!R;Ivt!|FP9xN2Zm&8Nngqbey%j5OI~ZsOM}d{Ycas8t&#RCa=$9_ at 0v z6BRFsxvA9?`Qa5wbusRya!nhJcq(`4zZuWYZ}sO^8t{#~A0-n$W9{ZG`_s8(YFJlU z@{CNf2LDId;2p#^d{o?4d<@o6jvD`5Gc|ahRMTdWuxLrpU$E6zy0kM5lg>tpaS~30 zR}AQJAHQ%px#xaFHom#f4!?47va=dS6i%wGn(e9`^H~YUPL6!u_c$OrCoV*lHpPr6_Ko3_WhgVF|JM*scEihNZ2JQ=DX_eMr5iYcN(u{p0XLwPp+<_&JSNDuc?JaSbsHK zfij?Ns)`#z!r~8OzR!IqGe_BZY#bIXjQRc|M73kgRq~Q at G2ZpTt&B76aH<)%(Bpw} zafs66#}3En=0OFjvA0KI(I+wU*E!Dbm`L04SDy%2-m5_=<+ZHwPsJjp+Yie`Y72a4PjZ9vPn3+rj%F1s{<5XdAe6E zDHf-SmF3>uB==nrFR6{%l#P`c+v~DpLOzyExbbCzQZZOC#U96NQ6Yutin!*ZX4Q5F zvE(hX;beCg5;m=gW6H(jPgBId{kZrn^`n;)4}*G3wIH8_D`TU<^Y{1#8FUI!Gkve0 z-#T8KuK&H?E+;}U{7}j&Ma-UwqAV4jlOtApX8zG-n_EXj;z=GVMMKK(>Tpkf zJL(-CRdW7>a(R8h?JVJv=@&O^UNnj^$t85AS<3#Htmzo*c5!eWk}K}!73i5^(f4T3 zXK(q?tQb#N?;UtpaioAM2$!R2O(8<3N7~}DI%2ANz>k8fLn%_OM~dkYzkR6BWb#yf zh-@&u)tQ&MxWf|`{a-%zGN^V51)rQe%cnU at wdL|&CIKGewWehkbe2 at FM2zQy&@<`w z>(_(@rtH0gVa{vyD<2V|)`224KL$GcYf~dmG%%?anUd>BYXm#p^?mr`%UNI9s%BzODCim3W3fV@#f!h15^R32%&+qAa zRx5iiMnOt ze?0RH)1okU4ooJ1-{tQ4{*aoqk^{cUW5b~8pUM);6UhFAVrV8&s`Qt8u(^xdfK zdG=`@(<#Q$S<7v;F8dQYEVpbolgK}l(_2r-*XvD~IKN!Byhb>3VaDaFa^QyKgYO at U zTDoQh%^Jg<0&ekIet+rz-&n_Yxc^B at --q@9GdP(6`uja5UZ{@Z^ z&Z$!4Ug3hcua3nqUQtH5B;n%}RO|eqwQD6B>wm0wfUwuIsfcW~S`5R=+A!-ajL*bk z*5gfL*3;o&#kZzAAykI{Qmw`D`I6d;TTxoq&!%ua_Erh5Uj5-tOpO at XDyc-6bwb{j8-Ruzcl$R%{;+4i=enD}sg?d!#q+_P at dh789oSS`FDSXwU@)^3S6f(F* zcB!V*4$&w at sDG0-6igALh@^xf!^PoM9g3eCVfA7VG$J zs9l!do7*6rPLx~M_R{O2(k92lp39tS$ws=%e$~@%-_{+6KFjpUr!idjA!9U!FNhfuRGE)y at u z6?1#4307+^e`6vRa at -x0QfM^dg^eosp2W+*NUA5y zPHjuQqyeA6QjFL7WN&BKNB((WPsXE6lLnl4ZC16oCPGHBYkl$IF`4pLJ=VfJB_d5Sm2Bf1eAC9hM~76COf5oH!*oZz zk}jQWs)%7pDt~uYCQvBg=9qBrhe{Kv4SiZk|qc0u+p+{Mwq#)J9)}lpx@`M2;2pbs{{D&2K|0dx%s|312IEt`;PgS zkI%k?(EfaAf4+Sm2-1MiKUW69_qV8zEU1kc5C_N<{CEB3uMXd9TN_DKvqE9Ak30?Ww39*UycKIgnmC$2?ttSAsgu6h23h931Bnm;P+4DL0nVd z{0{UV=sVDJ zkRFUH#S0D&7k>ZljXC(7VO9elX4H-k_+Z*!jnCYi4+9!txWM;^3>cmksCUr+8YfPk ze=!)uPACN9+5I2 at 3~vuNP*^b1(fYukM|V6h0UJ~wsG;88eb9~;rmh|)uD==#*b5p_ zW&!d-=||~C=|t&6=>q9}P`XfhQ0Y-=AYg4CuI46aJ;3<(_fYQ}_i%OlMWDSb%pEQM z at BkKzCSbg1PhiKGEwEmo2bCU`1{Dt#2NjM^rz&$zTS-k0wN<~YCU;3m20HLpL#WGX z!_mJkhh`aVeGR#T{85ZhRfTKIq4(jcsu=$x6S#l<4xu|4=JyMU_WhUDF!PP~2*!W+ z+28(t6&U|jEPutv82>3O|BQZ&KN8DdyAR`!gL?=MpMa2vn1qy!oZ>JgjEedQ4J{o# z1LIMqW5-W0vz%mQJH^hy$#t6h3=c0Kzkr~S at L7>_qUSG&iC>hEl!8mk$jZqpC at Lwd zsH&+WG&C=1XqnoxOvjle3Gfo4bdnm$#4ab-x?_ zH=%31XCTyz@~;6A19A}vs);X(VcN$PJ-*$6EjWO2&y1dlT+#D2Gdi3c!h9p84XJ`T zK?}G);~a#d>_iF79SZ*;6g9sffK9>CvHnvW)aMc;0`Wsaz at b8TKwLN|9cG?H&6mvR zS(F()Lt3Eca#YT$U=MYaF-QAZqIEl<<6487xq&?s^w9t_+oI-E)ZFiZo&y}gyv7Xv zo1k046RqL5E>yS;I>ZE|vw?i~#YDPxIaRN1GM(eXj z$H&yn1fBCiJMp0FhH6XHF#|Q{F+-f-SZ4;v72-m-9%@9G{VLO+?P>CFTgnk#M$|~c z9OGQkWpVv0r7XHksH1}ox}FF9e$d~7zxvw|q;N-%5l3`uS%JDTgB-v)2KtDL(u&b; z54M=v9`qC@#Nm$?{ZHdd;2*}5&^7&^?e5>@ zC-T3 at 4>fAd|Cjll{gt0Hy2ns at Jwbd|^jQu{$G@|r1Ka$q at j##O|DycY&{{1ZZ*dYT??Q)>m?cen1f&Sm~y(PMjFxG}SVmSl0L2F<}AKjeMKCWm!C=Di!`M8y_gQM657t8=UtsuPJygIx zGww6xJ|8{MH-llOgZ%gT_&yWu^NEA}o at 1E#Airr0v+VQyU;y$7dq%;+`+6T191b#40`(SGfP#lhq at B|eH}{j zN5Ao+9R!J^uOpqnI6%d8*gxOEXh7++LyrJ2 at LvL*4m%gQUsle7*01rGwhO=7ixYkI zi?TAz3K&jD4|{vCOMv>rL5+h$1P}o(C7zs|96suEmLEd at KsG0{sD>UP5p<59Usr<= zbO1AYh!GiE8-ovMNM~>GAws<-f)FA?zkLMtvVntfXlCXHUDlT85#49hzJQ48uj`u2 z>Pj*QSvg3{#|>Nu9{e;gzmUj&I2 at cw>45(l;A{?c*2D`~6;l1xj`(2clS02g#{lE~ z!D(0=3z+B+j>F=3EKb1UL at Z9i;$$pt!2O#Wu^4qv31y?*K**r~|HJ$*j`NrM*RX$e zivRM4g1=qJzj1%Z2>iq0{Fm;}^g(|(-2c)Yq-FkpyZQe=@cGw1wf=v41mOI3|Ly0m z5rFgC;r^HI_XzmE>i((zD2IAu#-H?O*neH+{d)h+|80GL*ZcppcP{WvmG}Suo}?|k z(Wa$WC^SOBDlN99D!S@=g at Oe_8{{HxO`FgL(j-e#D9W^4)K1yP81BcEX+=P$Y<7r_ zIX1h=v`(fKnM203bEwQAc8(z;!vFI<=Q$^rCa9a+ at 3;T&m%hGzf1c-@=YBcQIZ2*` z`lz2kR$iT}R)_wgO-(3H#4d32)_jmql(|7N=ck}n|yTAK^Ee~$p zw*8?U-+%a#oj>^Dqdh;`_1NympZM{fpFH`~y+8Z;Q at y|V<0>7J7XapZt at j!oAe) zY_Yo9i1^pW?N*D`IKk+1HCbB3*WStNYWKAkE_HcqmH at Y9vB%zQ(cH$6pKjjaNVuIh@%}c;3vaSn92T+RO{>ei`dtN!ht_Lg?b3eByQ)2NkG^S620gWML6MGhDe zA7E*-_}xxqRz5T2yf&BB=5YqNZ5=q%sku>K)^?Bfv(}nFV#4~^GNc?fhtX?sEVEd} zhC`ZvbGz)Py3tweoF^x5kJaAfur~+C)9gYQGpem0=w|Q-aO&-flc8A>}zaipud6wH+;3#yifc7pG=llJeTuV`I z3iTIm^bU at yQ0)tLk6e26CJ^oxo2M<{u6iD96Om$mC0W`NVZq;bW+U^Ui z26>!wr|@}DPx7W%N>i);yy=?-okx8K*ze!wcGwr&)n5o!{dv9#m~K>mCajgT1`#hc zCvpQ at 9NG~z-vM1I$ln;jpF&!TH%U7 at YqdgTeXV zq`8%Q_O8L;{JS-`5?`a{R?;_V?iosXG`I2rihRwjovEMey4C(*C^$0)!a&Wljc^!muqe%e9?QsQ?&WA>_gs-*67Ff0qCJnR z<4q~=pz2d3Z=g03-@)Rf7XT^pAvH1DBNcA?4bHp%V!8FFC7oA&$N*GO-vk_ zILvTGRAOvlls+oaV2B+ZJG;t66;<-nO`4^xGiC*?Kc?B#&vea`ckFDy0-U#sg#TQx z%`>}ciLKc;-MN^5hMo`1^M|XmczqSkKKnA8$>nZ$YyOI#5*^J%%$62grK>{;IhPu! zhU$krDgWXrrg at z-j33gP zOkG@!`JG*z2t|#pjjgS%v9ZHC-0tOW_mJnaRWzGs!RC^g^0?k-ny9{^x}oO5!)srw zUpMpXHFKZTzp`M9+y|~+#AWv`T7so*vulytaehi<;dle7OEDa at d;|@qVxE zKD)!asM*zq6_j<+ax7f1uqwQ2QV~`K)+gImgq zr!1?1vdqbpRhmRu8`Anyd*PoNL#gHwlvArH{? z26uLDGz~8;pyAS`6ysLnwN0*yu)MxzX)QHIea*#nvV>Al$#6DZr9N7<$0C|k;* z)B!_(Qg5O=p;3vuA8{*XU5~P^)5>a!g8!valqKCkDQ-g}`x&Fu_8N}5NoS(&>to#6d2y5~6;MDqOu8ZwC$~qGL{Yy)++$)WQ5r?+8GO8#^HLf|AC`Iny#QU zRaYP->a<>`)+N{V#c`Bwz6yDng1nSaVE^jm@?D^Rs%6*eU;^d=v}I`D;Wm|0qcQgL z(7(pY<;}hfaaj{}qs?JKH6 at A)^{5~3)<6XoWaYe-o``&w=y<@!=67xR2B=J;HX zzh`Of7K!mXp0`8#Z9rPwo|tDx)F%$8r4#3xQbd at JLP^g1%KNdVg!Rl+-f7p)3yD)b z|8<=Eci8iR=X-Rf?1BUuX&sGuKL_)E8jToC8A$FQ-kX5_c&u0n`!*`q_aM<*BJ4eZ z>E%RIPGweahC9764gE(=FK;W+8?f_gdPx!`RR(Z`L?gnvL)vUe{j+~6{L?XqY)Ntt zZ%i!Wc~**(D6UDgtK83$(9eb|*R2icXKEXSJH~1Av1Eyon?zm$-GSF!t)8Q_KC71b z=^qgN29`Zblv%#^4ac<)#N3oq5^(KPI3}vEU zWR~#SBH7JhJAcccxyJoc6v7t7Q^CnjG9Fw-S-vhZSnr_N(%Xa1k%nWrPxBQc`0nbwko1u1Ni{y)o|S#;787 zT-tbV<`PA=>he-z{-i%zdd?pQhF;t1IRDJ_6VGR9xS2ue2*#1&# zpS=;i7F^Fm&bt-o+y?tF^t_Pk<_?^*3zjxp7x_Lev`>cim!Nq#%sMFaybIOwkacXB zwMVFbm^|~Ea*XeB8e`o}V at e;RF;b7V-g8F>)Q8+}hROX#t&_25iB`Zan;lShm?N at t zW66LvGI;!}Esk%BdM#QV5HHuoKHRhUK+GN4=y%!m>HTUNhwy)`B+(2t4Yh7Ayxtnp zepS&DEr8iV;}Pcvmor8yC!akbMxr8ErwCgE?SOTwaSfdZiiX5HA_{A?VKky7S&Mf+ zt|cGBek$Tgh?S at k_WRip<_1Fy=Ef83JJB;``*U57lUAx-7E$V|$WD#NbvIpfNG z`pB^N>AiG;F&R=PLH!nMo^0G>W at EjBGRb$&Tu=NNxT28~-2iildU+c9vQZMP6YhAp z>)_sL3h9sPeOO at v?!o5JD6)~d(i^tELgt8+q2aW7>WjGN`6}#LQIdHtV*dvsqG#(pNoeg^KkC+t z*elNE>=n1yrDS0dKGGH+NhZ!8QuZ}jPgUMEsU$NQh{1U%PK%f9J4 ziOh8pt(g-rt}k?NAL+g(WPViRUoumo*I?gMUVeVfK;=I>j`g-*mfbodDXPQBri*^6dIVALcJ;HTeX`_W`BU9Kma_cTo z2cJjW;nw&mF_eNjOex{#9r2B7J&ao}(KOiT`k*>1%Dy6j#+QCYKVDj_50{Q{RLHo( zx)*bcc%I^q|7*8mtpK|sF#bsQYT+1eo>c25Bc3wMNtA&(A)`KZP at UC3sXyLyyF~Zg zA<=9#Ps8|`?Y+vptXjBdC*k}?#nULC0oT1`T=SA>)P at Mp$2d>*qJ5h#u*Qfq#zOi* zT*y6v^i7GPzo}@M;&|wJQ*msDIB!P4d7t!5?MFEGW7v}VfH`95x?jw(m|s!vp>ym9 z-;yZq+Y+s=4;i1CXjjy0X6bOstoJ{aQ^S3CqeK_qjW$!mg}W#Cq_t9n>+z5^xZExQ z>-rM^wTAQZ+IJ<|dJpED(0T|QbCI-qpB&OAnVZojuztkJ98$O8uDPG^-q;17=gV!J zpuC4ruRi1Ebs^?jvzTi=I8S}gC}54ItzW|4r-kGpoL_`{odw^Q$O?Nuuy52~_+E?8 z+<`DxJ}lAj263MQy)eN2Y2(?3FlCQOlrO@~fc|oTJG*!|tdWP;)c)3hLKD$pzPV$6?E7HOxBU}1J*Y~ zp9^VW<@W~+sF&pM?+=7|E|5J!na|{F2{4DK!`Mo*$J=IY(9R4u@{t>T5VV?1*;~}(M*<*0c z*)a6pul7Rm2aWeI&-AtRK)^ky++#JGvV_!<}^=ns}DSR6Io at 0Xi zo at 3D56Y2SpHlOM#yE5G!_9~Kvcu3zRzZc at a#>&qa zhGTu5NQMoG?jiaASFN)H-%t35)A){*E3K2lr7=G-pdKTv-(JR8%uLqN616VFt^F>r zKAU6E(QU9bf%9ePXD@=*(ZTD2FQp=F*k(1n+^3R*=bR1bQ|fyT5$1n)nvQOUJ)xCD z%tQQnl6 at m6)t5r42NFzDUOeSt?B~5daxiNkqd%=T)t%C4FlqCAnx4{D8{EkO{mnN9 z`GdU_dQFha7*FvY|MS5cb9K}S%QcI0Q8xxpqJP~cmk;H_nsgMdp`#EUbE+w#e at -0b zY{7lYKuUjd?{IfwV?t59DWD!W9Im^g&_1I|G6$8_MzWS4_e33Sfwijn`3%>Qa_xFB z9PO6K^HIn=lAwK#Knkb}W$sVG+;12<_kX&3!J>%u5$Rdzr(E|AIUZrY%g&3xJY#ao zFGKI(<#846Iw{|07_bgiuCJN93?cWSB8 at O>!UwL^(X+5sfo-%p;My1d8aEhljl&u^ zR@~#nY416y at kdwcXd>+1kUkLc{iF-sk5%dDr?A~>Tm)?y#_P${sH5_W{C<7;dg_7Sp*+8z^-?|6T6J_fAnbAYwc@<> z0eH zk6^c8m*7o;4#DdMrwSGc<_IPVmWce#5b0zI_qj zPH?{962T6^+XdGPZWr7o*eCePq~LLQ-^5_|py>Zc1z!=IFUIc-!BW9|!7Ra8!84aA zJT7=xuut$w!G{Gm3EnBVOmK0U^d0cLr z$G4)P)n at Zm@W-*M_`8s{Ab*pk#fD>5vu9SB>n4{>vN{|@olyq+K&-BLcB`$b)#9N#o%rm1h1Kej_f)-BU+1z|>+DS)i(JNo zRBdzE)HI&f*V`;sIdbx;c{aK1P9JY7`GHy=4g58=R%xooW)m^dMn1d2XB7perJQnr zdj`^Nwm3KlHA_?FkNS(x?IRao#QS6 at SvbH-!t-|jS z_PgHZ@!DO^nvM#}h^n`F+fk{ls5mQnCg;lJvAaBW--;@Sg=^p$E=5(l$76G9Th0DD zz)uakox>^)H3r)1?_V4aImq_sDj at HAuTy})o49ARpx}udTX@#&Im*6*`m6w$y*l52 at Pjbz6MRt$x2Kz1d at NdL78V z at WhNvHBPI^f~5IV$=nm+)1ku5PAF`??5qbB+{8J(`EE z(wSV|fZn*6kDDyq8EBbYOQPbmQ!bI~NAV>32G^~U6wPg at saIR(3UyAIUTODX=n}mp zMw{}L7xXa>$<0yaa`1 at XqhrVHcAm>_gy{^YBp(%gxT8RsOhjZW2UX3 zhT57swUfK4$~D(%ciMe+i}D at WH25gVO?P^I7H2d3D&aRh;2f93Cc<~>v_8l)ZG~5x zbAP9+wOQQqv_vn`t`E5 at k-eczo?{F62CV zAisN2AD z8Kc$9quHfhGwFV{{ua8Nfh~yDnp_Vi_9G{2`Ri`i^7*rCX0lF1zR{)a)+$bhC%}c$ zREKw(7$0;4yVTJ_3)m%hxaWslb*7_q^ZB^aX!Luz4G}abM-K;F^>FttpQDTgto>wH zwG9gc*9t0)o`L~d8V{t=4^B0il^o9n*nRjd1O&~h*c~+X^y(CMDaKl`j2>>7q14_V&8HU zcF|0Gv&ZFyYmu at V@GcT9CkEG|x$@U6Ee>TL1!JpD{yuD$pdrK^8{#Ix!4`!_TSAV9 zywv#nTY}?P-T!R->hG`a5$CCU{p}ELb$`iC!maK<*`ek~xEs}Ugu7O_hY9x-;m%ac zCEV(hFoSTXsTmXQ!Nm$YN6KI2qtG%O635H4!yoSx$JdQkjz@(Y-y at Ef&I%vCTO99* zaD2Tuoa9nI(<+(s_vj&y$tk;FI||te$x4o zpIZLk>;GQ=_xdz1bqw(}C(u9Ct-dI4}`q_!@ERJt(d2EQS$V$6%%yh>J_Um634f{uJD0v3Rm4f zAaB`TeoLp!9XS6N4<3Hd7$N>u=MEZr=f8aDwSfUup2KyuD&TmZ_+6!ag1v%!1@{Q<7VHt+ zA=oXrNw7<>L(n1ED7Z*)zMxsqBv>a{D_AX9E?6cwMX*$`NHAY8OE6I|DkT212Nj+a zJT5pOcu25MaF1Y*;7-AA!7jlL!MLd4`w6%3Zxw75oG)k+tQ9O5ED|&d8U#LZoyW;M#1 at lwSq;0MnOYJ{3JMdK;&1jPjHW5w_umx zN-lqu^(`XZvSf>hF&IPd)xgb0ZIZv-9PVmT?!A_i{97Wl8}>5neV75~ zUIv>9bBJ)0gsJ1ZN3i27pAT;puiYZvm0$VCsLnI*zvZ8|C(-|ZNPK<+p=QWOBdAO_jfbVQR)X{11cq&mEH1pgDq5^1sD7_#PYcXgCI3f$zXXrF= z2FwlJ2yTIOKyL-F$tGG0T at Kzl66+A?PH at 6#^jYZq(eg8C>Vw`4_G2*gLo;1Q|Ps56!_kq7HMjoIKfzMCI zoCCcd99xQd;Pb(6z}7l6K_3FsrecgjGfl9y(9EW3 z$Q!g3eBnCO8+1QdI1_aRT{KgEkARLsGnesptsm?7eF1tB77M)>EUZUeK^K8r8<00> z=CWP=4q- at Kp=)34Id0xCwm;Iv-4K z#yXPI0&j1 at oCtjyyt5VSd5#mj(T=_ZJ;+>w`v7R>ZM{V@}ZhptKS73>^iI!3AVLv=Owy4nenqzk(g(I6?a+^i|F?_})F}2hf9{ z at m`ecyiR5%EC;$8Tn@{F?f}0BD}e3>{{Sn69sr9rqm7`MZ^5dekAbcCqc1 at -?}53Y zH-jnNC_8i-_{@VC%g}w`sjd91PEV)7^lkjzJw0WCmv7 at eXY@1$T(ph9!=abCVjF*V zOiwGp?rr?6QcpX;uI>DN2EEKjVU5r|;E0EKp8`Flfi(~DGfF-6gJX8^^;b_u at TDF6 zj8abr!N2a{{Verl_&$;6VdNQlGuZM7`Z;tfc*`UF{Wv{!f)jS4jiB?v8)5sQ8^Lew z?l9^{Q=QUu;W}7 at QokvWUi;9pz~4GKeQV>537YX^x*mq z^FbGZtv|xp1EyrD}wF at pZpbnCJAwZhkwO;mgwmS_ at ie~=g__2h-WbmK&OGbVH=^DFFnh9$f7>M z)36=T%=A9qe-`ZvUfsu^*3wfMcq6PAx)EI4$KNT_%X|RV54{z94t5B7KloSJ0Q5;P z{W;TVSU-EO_y+QMb5^=7V>^VxiZ8 at z3*C#;70A1Kv+^>0u=&}HCLuyW{LaNG-MFX%jQ3(N$)6&&^=`X_WOcsr~Sx(hr3 zYvr^+Z$J7cv=2NC>wrE2e)%P|6Lcf^46F;f54`RG`YLoC_$X`>bPqTQi^6W`YVap7 z^K&V*Blt&H5A;!R0T!HlpcjE_VZEIHfPLSXH~$uO4$b^3tPeVHUpMBGL+C%y%;m5s z=nn9 at S5Xhpb>L%%QC>bDyzTeMKXe!P3)nj7ec)l(M(C5^l}9kvpr?RKVOyac;5Jwf z^bYVf*k0%XFyjxH523TbXJPxH`@ngxqn|*p2cLi$qV==~JPON#E*e0;`XkyGdO!FY z%mh6EUiv4r7j!9j>rvz%x)b~(Z0hlcEFvm z9BAf#SROPp^%Slb&}rZ-SShp#ybD&wVZmo$)zE#Q{sW>q=qPaOXK3{iEczJbf at W?zkMp2+fT#JXM66!sE0RP8=tKNr z0G&kT&_#NQz8 at t~E%Z)MA1%>*=qPXntQC4I_#CVYdOx^|_Y#9%3&swU=pZz+05$;4 z{Bo>Br=c6c`(Ooe7^h%yoJ6J2rC?6HL}kz>a1E>udM)@a%nWTzkmwnh1G=A?DA7*n z4)71K0q6m6eUe0j(98+R$WuJ#Jy61pWfpW4SUv*jLNjM(Abw~Q=*^O-1KI~Zk}c6D z=-r at ultg{d%x7R(31~a;EtnBHCkOR2MxuP^mEcpbIz9)?%tidrMPPF-?_s7VD|iyt z3eCLPDA7s|3tpKg(K=`|_&eBE=tJO_$4j&ux)D5^FVQ||=8cy~bcFrEF4$4%O<=~Q z5*>%m0`G-ICE_{`UNjMP4V?$>gq1?~f~^G-nV{E#?n2}ln!iiej+^RM*5Fy#T4?4P z+ at x>fIKiL5c0%t3w-igX7kVqmd+8p7X09wjnW34NOqM8dIQjF=ggy at b{2GbUl28_K^0kNux)hB5BI1FL1-}S0 zL6?KK!{$SGfv>_Ep^t!Ta0l*#-T}s6hqi!D1WRB&94FXOCs8jn^Iq5>^k(oW*lErK z_$L at 8V{C%MW}+WL$AS}K2IvBCHY^L;1fGHAL!SlPXCa@^9pFA#BQ&#THqwS>{tea( z%^ReDeGb|kdObLy9(jN+1sB3%4YeEx)l5~>?HJQ z at Q$yc&Qnou;0t$RtU>pK(p?y9&{5!3urlZ}@L^ar^iJ at XusY~{VB*(NUTEf}Fb8x2 zcq7aQ-3ZfCk^v9m~}74IW*G*D}rX;4l9E;Y?f#a%mi%)?}oXdH-SB{4vvTQeV8kt z_kq{kk9vSE2i at JsD|81qZ42rIx)!|lL5ceL9I$jN+8vttHtaNX^)_4ww`2ZHM;`$D zVFqaCR~|xLLHocfcOd`JQ^3UUOEd+Vxg2JO?f}~#MtiXaZ+Zmv1HBU5{3znj(93)U zRsek*9M^+9LFa)tz{;Q(fg54f&^_QykD<>%uLM(fqi;Z`fu6_FAE15U`>>tRC&A`l zpbtP>!TMj}dJSy`--R84E_eoG0(KmlNzb8gXYf6RL{oo_vS*^+z_Tx)&7hg3FT$Y9 zz~!(q=#}7UST!{Bu72bbdL20KC5&I_Ja8(kgX09>fptPV4xp`HMqh+BgGXUIGW9Zl z^a}D1y&HVvcM=_9e=zS5#v{iG?uDI(W?uZN#5XpS4 at Mus*n~EMZ^Mkx$G}y8KzQi2 z;JVjQ7HDS50Qwtr8u%yJeCVU#>_4LaLz}?$uvX|zVDB5~XV6UZpHTnM%;#Y1p!b8{ zI*Rs&-UvSTCfbGl!8vcCKS2AyWpATg(4F8Q8#MEcV-kP0iH?G|{26Tl-3i9LgK-2M z3%0-tpj*Kae?eP7r-7Hl8lk6v3t+9#i at -H7H}qO?8>|C*2lyha6WVYbedJxNEufjl zV4I+s%_lIXpsnB at SPwMw9IO|b-b1-yeb8p`BiIq>v*1H#(62ZxPbDr_h85%4L4j(VYc!4WAsIu4x% z=BDcCB(xE{6&5=RbqM}_gpLZJDNRQUVAarzz;D3J(CfidFduYcx{elR=x8PMN^sm5 z9j$}T13!fAggy(tkgKCZ(EVVFQAcN?)4-{)s2ucpaMD;EB|=XDH;vO#9&|VO^rbo~ zgWd0n&ml12-1JpqXc2d!f&Qmrv5se&}lODcC{iO+`8yUaX^|&{^PD zC+lbsx)bbyC63n1JOE3BJ~)|wTSG at V(6L}4EDyQ}{0gi9dN26Yb?gf*t&`}+< z0hF#py+KET6Jb{90&o`00c`@CVLoUpxNr*U6M7MND{LKfC-`mHM(B;;)mQQJZ(P5a zWjfjo%^ZIX$_SkgPP`Ungsukv0;4f#qc7^{$FL&kJ>X&3lrg;CL;4juDu-q^S0bO# zR&WJuJ%rJ#2lt^&-p4u?_k&E{m%0&}c`s}eH1AE#`%15e zX1)R&gyy}adH?5Q(99GQ+6(u3yazPz>AVP$xYnRmc?aUaL~7(WEt z1I>FF^S-w|&`jQYb~o-*q#c>v)BX8cqq_CPb`eVH(iF?k=QI%p>Ele86@$$J#_Lo<0V95dz_ChuEw8e@~m`_3%FxM1?W zF*~4{ywA%?XeRI7Qigucyacumn)h$1gRRZghk1wY-}6$w7owNnkId)CVI=Rd)XAS= zb}JwE4LDCC{vpz?A^uUszi-zKfBqct9*{pr+z;~k$HK%TDH!6w31f0L| z0FDQ^QO9x}7Rae8p51XY9yBhqgP&eg?{$4pV8X2YpJrblCHYyDk?56 zrb{llgtD at -_>-%cgJOwZJ5Sr1mGCG2vDg2WaPOTzF8~qn|NIdD^FiU at KBoX8;Qvs6 z*{z0qPjRbB1ieE21H+wv;wg5Ye`5Rgr_RIi1pj9p?7y8681AF`8#t;n^%a#1 at qa=6 zLRsIy{^w4-Cu{a$1cp0hoWS9>8Hmy!-DXHL at PDES&%poO3E6*w{GTQSg*#I|1HnF; zQ(RF|yl at WsCjYOfSQy~HQ2uY25uBbO9a%qROy9oEkdEZi_`j|F_U(oYgga%FwR|)q zB)t at rjAK7jKCOHz{-(jFqH?~R-Wg4QSRR at lvYyVdBW3Z&qXm2v)hKkv`Ecn~6wepw z)z;5f(lg-y!ZUCwdd8VKL&}$Cvl_-5l=5Y4-!7NW%BiN`4Sz*LQn>WwIuxna3Y}7{ z`t$$d(DaO?v>cZbZHD#~I?bT^^Z&Gv at _oczLFpq4xsSkvUQn<42oJ{%uDYdsM zeaPQ8!=)!;^`|#Y{qOIaA?c;dZM2O?fSQ&_iBrwkruEH`^it$Lfx*5|O;3yhIlXCf ziX)^){<%e at r;fT)Vh)Iup4{gb%qhMhOnNEBTHhQ}J}wO>IU!8>l-VF$dehH-C~9v; znEFgvc;FB?r?rFi;)(&(6;*O05p zOszPJL(BtjLU<2Z;aU!t1Aj)4WAx#O;vO%b?Sik7R)FmYVWeiLHsq%rXL8Du;8%t7 z?KrX&dKP>;aLfpEiSwP%9D6&Caf}{0440r8J`U|%4rv!*Tjg{8h29`)Bs50Vt6)W`Yr&XAS14skq)IAZ0S0X|2$BM5Gv*w3|n z61DbekZZz*8sYN0QR7?(O6>=?j76?Z<%m*m?Ko>43#}8a zykDa$k#A+-ttL}Ys?|uvBXY!Twjv}2+$~BEAdW1QV+oy;(^&JF>s`s`_vCyIM$G4Z zR2h)Z=@IMWlkbT`mZjnc!8XMQqGMsJ05p_g1BUV1EMUI=*3i+5n9?u2) zqF1g5Wu&*jRUpUdFHt4VW)(VPe7cz+^5~a)5$f`LsLLe!i=Mx`?3H_f1N<`D#e+Co zXkN>2c9Mk^5a}8UelTg5$tc5!$!(pJU(pAVS|#>s0CY zd{t~?6t$=jm9#cr`;>> z74<1&o2-OGNUyEAowqm?Zuod?Uuj1wHs1YkncZP)v3a$Ffrph1+mMku+cKNO=-~g? zjJ0^DJD0hZ+B{>8?e>ah-YDprv5PGZuWjtLWtT+=>`(l%$f=iI7L?br%d|qnU3QsT UpVyiyOcmAD(`QYaKVOLd2Rp@=@&Et; diff --git a/Lib/packaging/command/wininst-10.0.exe b/Lib/packaging/command/wininst-10.0.exe new file mode 100644 index 0000000000000000000000000000000000000000..8ac6e19b8eeaf7642387123c749f416251c496ea GIT binary patch literal 190464 zc%1CLeSB2K)i{3lCCL&Nc98 at kM2HevaM4B=G+~1-A-hB+;l?GqL`VXPbh|~R;a;GX zK;q5X+>G1Or_u-eXp2?*<7w$r`cxpk6m|*C2BgZ{gD6xZruD9yVw4ybh}`cvGj}%$ zDo>y9_w#%CfHXU?2+X71eb2R3sCj^m8*S5=N{S(CTA{;_Y at FMlNOq2-T0`k0XS;KO!?wg`C1tt{7`Ip>F*OyC;xYBmrnl*u7@`7Jl#aE!P9?)>yBS+J^gEXZ8`lL z3OnJnk*5FQw2fYyPQOU6PtxoC-+9Q7)!? zFpHb at Dg;*e7w8!k at E&f{I2}z-UOC=CiMF%DfXPi15Mfi-)P??fJM`Q(yeTkny<@+g zrd_w|x!h~eeEVMg at V)^&x9Ptg{#N1P^#WW!8LwvuVOx#EVe&X`*{$^}mJ7>)3@>SI z|2155hZhX>I&WoQTs~5<3(~KH>;5mng>S82Q~wa$)3!pJxh%Mz_;PvIXzKs}`+wjU z3=3mgP0a^|k&PF>B^o-orB3ma_A1ijC89alZ)t7>AP=cA`SuOmUcxor#R-oEmU at -G zZ*v^!t*#FC3w553bWY7)bXy50yUbET6~7VSJZko0hzN$oF-0z`VD|U|X=;^KI$(~Q zJOLftR#*4C%vN!te-G54W-kS3slmz#nS-Dm=}X<>Q*}%1VP|a(A|>^hJzgJ~QwYHJ z{?{O5xJWdK8Bv!Bho#q#*s7w*>-DIjS$$h}4FEot;16jP#aKncAWl%lJXN#;gfdoD zRj3Hi+!MPDKvIGiM(_-q__vD0JWF#oEz%s&t5tc>-mq{ht0tfyUW+)Dg70GBey6>J zi*3{LX3)H`XW$WlgiMSx(72GRk5|Q9Rm at Sdolq%h7{Dl=_o>;X at LVKji6h{?3=vxD zRmCiC!03gD1rPz0z<6>>eOtP$iWV%p5G$VsmB+u~^?Cz(=m;KQJhIEAzD-;vM~65b z;jsDsEPz8|=K&4u;kw!-2N{(Mp(jk(>t3HFxCI+q7;<$6I9{0%fPQzGWmhM0WjSTn zVdBaO6#AdGW9Oejpik}nyj*j_t^Cyupbfdwfm|S(Ij9OZ^ZpHp*hB;~^2)!Laa?t^ zqeB=AiKBSGAF(k)TL77UfZ>%pmjDFhp1}b4p#bsm_WmN#iv5 at aZSg2Ku7v(OV0J@` zXF`kXNQc&*rXDA7$McOJ0Mq;#It!>k%5&tPaz$046+Y5nl|y~-5L!_9v2CuIR9bEO zC1so(?1V_e{-z at SzO;1tPp9BX4xNBdFxtcManeh at aL?I~dAutfm6;oIkWZJ8@&Wr_ z>XbGh)WLQVJb>lqW{@>E8!i}jVS!B!{yv>v-qj8Fmf%}Bd)&p}XE0iV?Qn0|=b0ph zZw;9<zI}-)7<7`Vn2%y at w!%%v-zNS(Y8Mn!kBv+i*-xo&|z%VO`$(w)WX*Jy7|pv zF|qeqAo$9c2t}39_OoJOgv`Lf^imHJAk>^j>kJ-2FiO_=d}1OIs7>B-1|D0jPQc-! zEqI1z-h~aTRQ~G=9Y+Tr%VTNA5vT^SOcKH{WbBj*Iq_v^_XI7MR=<+(r=86nl{+pc zQwAGIXq#;Nv3-J9-Gv=&*)z|~Lok|G*W|Da>Mq2Z4{*w}mr)iVvrf~X_f?nxPF<5# zsqPBXYTp|`n4DnP(mW1$O8OJRaY8-`A}cs~5tLEnp^Io} zdFs>`sv3)Yk!tkJPLdv4pK3;h(H142wvL%gDflMqB64(L>q6+HgJOalip2EiUm}O3 z4-DsDB$R0kopR_5B_n0BefLbTb!zlkt&4m5j`UIP`0dV>(ezQ7QioppL?53T zFontoDtTr8Ba{h>GsQFnTiB9LTm$a7v1PQ|xe#RfztzFaR7+*R^DX^28wnY_ at +-(y z4U>dY_2oGL3pu)y>LB(|T1-kbe~c+q3)AhV{S{DmI%K^Y#8dQx^J3}IgRDdGX*$k8sM zIGLo12|ft|D2!Ca0i}Nxz{Ed*X4R#HnR%EnljbykRsvHWOxNOU|I>iAnw`gH-UfG-q8Hs$v%g9M*f&F%(pIyi;JS`}jU zSCki at ZSQBJMVevh6k?5en at Bw{#`5{wz!NFQ8eAbCOxvj6;QGtwJ8A!gA*4 zTcLyi=ha4e0AR6dDC{~d3TD2Y6KKWlTET at WoZ>H0`k?kYNFT4g9|XMFEAQ%pAqG;H zhNoz#(6E<=JrJtdPlJx*=xCV0`#bL#-c-Oh_B)__D2RFaP_Ua_6n5!imow~gf?bZ_ z#s4~#e!ss+5pP at a`mdDFg3?o{6K?PQJfLBu)9OqNfx%}rdn-^owu;VMJxQ!g zNqP^0__OH1qO1ozTZc at 0@?V1ANGp;8Az;_aN(lVyJa_7IeA(U^@(F7~!he z2hF*i4!#+9 at hf+vO0EW|SzH%B&wzna&BpucVf^gzl3DqX(dQ3CmQZjjVtUb^cPEr3 z|7kNkMT1X6h?G=MvUFZ)`!2}o8&EC)Reb7kn81R+!`XIL8J6POq0X8HHTrw+K+H~( zS$PE%G(^h+R^E<-58!w|l-q~`O1SYW67|VMlxPb>f7(8DJ|RIwFFC6m(Iz+sWZOSD zp>@K9Mm~cnt&MLlWnmtEbC_bkm at sO~;sX?}{{^jVrE zdXo?~7Ky#W_lv|HK`0Ux;W2+H_JQvH_INLB)O1 zFfDhGHW#VFZuKuMqz&5%ZCp^8BvK)ZY=hew?Dq9RB83M at cVLiSFAvgd2NDS>^pFne z(Pn9WfZn`rX|ALX8*90SI(}YYCyoSICd82wq8KY-(x`TZkvG8 zpyhVjAyMTZ$_aFTc=xuzyy8`AYN$CwC%TQ_APqaod$#wHRvEyl_1ZSVKEJ+jy*PgY(q=%H2*TC0s<2zvc!FZ0OO*=RtM zS<7IM2R^4`BG5+%0SGBFYpE99L!SdMcwXsBpT{YWf`Uvswu!_DFi; zdh%(=t>cwPR-l%Y;b<48c|4dZ*Cf>JEUHq0!1bzkVvg(_Y)}R%PqgIfXapL at st8TZ z#S~XxYKWMJN(?$4ki%1hK^p-BgX02)$5Vw#i9vepVaF-KQREsB?kIBg3AYuw62c5e zuQ1K;WMiAMS}hO at r~`u<1VJ^}uX<>BRUe7Q4N|8%sLgHVt};zQgS4Oac;uh}1t{<9 zhV@}Ur*&d*m5Tbxuzn1pu0XpoxSHOnyQub%?9iZpNbF#@{_916NjNTx1`=})Y4T${>XOCSJ$Cp4xSNj;ktpC+rhyd;DU4E^yqUSK(()=TI zC@~yh+5=#ckbqKY`;Y}f^KapmA3R8XOOErx18uJZ66B=(9F}K;DWk=#N5#4yc|j|K z at d9l!?+dwS at W}+q6Exo2vb11^^7(nVQ(jn(Ds`rR2Quhch^kJ)Q}u%yN*LQF-p`Fe&yydT2_|TQnyCYqk(3e> zS}an{UV)<~y at e)fAk4fR#t4vvKlm<_bXI?E5%vm$o0UhkYE&nvOt6P*m7+mp zjl+-y`^04hp=4&csWjx3E03TYG(q2%F^^YS8SAMs;n6a|S0+pxV>8Us#gg{)Ct)ze2x(KTzOb zJfv+yb)~ppt6dm_HJ1Vyul$X9eFC?lJFj*Xle5BIq&HyP=L86_c+US?NShdzPN^V( zry|(Y&rqsQ7*^U0TH3#|(vXZ{Q1YC$O7CKgkdhquNtJ z1(T04H}%1JQM3&8*r9xRTWT0!8FCTGNTn7}rPcuHMPHp+&LJI3>X-p5&EZU7s0vPL z&JjSH6YuoWx;G%rd!NTd!e<7!P}%58!;$*~Mqt3~1(feZ(+fwaR@``d(pGKi$-3Gl zmUMwxKeo-adTn#fXf{d8O`(~3`!RXEJT~bD>!E(D>vib2dfYqnI$_NH`G!p*c9aL3e-dT;ByIqZEgur?t z9L-;fLcJqYhMuO`#{oD3V3~nT3Z{xLrz(M3%L+E=@JG1GH>3JFptr{O8fCYcpbJeD>{OZm0%x1uht{S)-}J zY=t3f3BHIdsmy^f at jQwk6wO&UH`GHaogh5G3D`Iv+!SMF3B`uW$FejuZYk-e%}$Yy z%xYl-)X3yl3|PcTe;x=H{}brE zaNb;^=sYQ&YwEFHEh9alkO_*Z^k2{EaTv+L0lJ1 at _A8V>s3eh}Gcpx|2_y9OY}C@uA=8eODeJq*!qm{{1X=V-SC+ff)(zX8 at A3NA$&hbduCvKTYQJk4UH135{_ ziw*U#R9^G*X$=$W{pg8Q4lkzKT9nGgG#$n7z7T!ly;M!3ZuV>w%T>TC=Ru`Kp}q?V z2!nyn2wvX*^Hik#BV5x1fuZF$qOmZXhUzX#X-dcx`I-*`cwKEW7PEnrrX9RQxv4Ta zn|sk^6EFfdtN{C)IWB0+NN=!T96 at JemN(dMc{;3lknDiSn+Gcj4|5+Rf z14&OG8q(T~G!93c71T(jam8?UgxR@*Ez*HVI)}RT126(^*^hla2S=4K9kjM54XD~# z_g=y4n=2g=OK=U`Mif-_(A18tfJZt!fm^Ltjn21UD*%D!q4c3e;7ZClBPE`j_3lDfS z5P2wwAAN^@>NhL}3VM|F52E&Ll at fY!GV?5IZpE268n8XdF0gu(iHoQm#u`l1hU8E_ zq`YIYA8h>zwxQ+eQ78p)4eT6Sw+wwxms%5Re0|gfh*~SnTjro&d5Ad$^U}Mh{rQDCRJ$0Gv=^se=x0QOEe!dW&A}o47lHccF=8o=sD+3Z z(2mm9MU-Dwq}E83RYUHV!9DMvF{dP%AEydlnX)EXAlR{3j*?XkL=8jz{yfB(MXHOD zv&vMuSmQSjCj5PI%85;v4H)}){T#(^l7QLrQp+=RvBu+1$4L!m61vd97B1AcK^{%; z_?6<4|!98lWEu?mtqT!iuNpTK%Xtr?9({#LgcsM&z1OO_vU2 zv2|;zTJLxA8bty+&%T$7(L+U-Ow??SsT6?bv&AJTx(!8Bi}Pui?L*9b{tbhu?ecL~ z_3SE&&H4IN&-!UZGeiIe>a0TJJkW*d%FV2op(%=IIkwKpIz#zE-Bkr at 5B_3W%)iwS zwlbGlShSTLLtD9bMlp4e{102{)mk~MfhWM?vWG#1ai%;sGww+_Lx!8ZA-dUsS3bTE zk!1IKhTQ-5K4e<+T~{&fqpPoG+B&c18lfwE=m>rYtyyNr{H`ojeV*=WrP)hFlTW5* zs-^iaxjvzejX>=IZh*ecp6h)!VMIhhunaY%HMkznj<(_ zM}xRF-+dSQzwP1H7Ai}hqT4l48lJm)#s3sQzVuQX7Cmf<=Ido9Yc+~V>@p^sE2*sa zhwnlLD6L{+K at VmZF6b_xdVB%x%#$)Dw6z8 zGZd^m;njT0A1zkTRge3fNs1(67?AR_a at -5BiyHVRm3M)emc-pu z7qY94s4x~-E2Rv1nUF7{y&ztv9C;syeh<}&=nUcWv9$#z?a?(bb(ra4)TVLouvuZy zR}gfwNn!XZzQG=D_vhU`xLm)P?PO5YE^7KM9^@xY?V(PkxqiF{Em>3QQ at W39JJad| z+~A5`Ql*co;`ZSxv(oEIG4F6!b%?r?`6#_SO%0g!Y~YTA%+jCGkD9j5ESid_3wDj3 zHWW(y#bAle!%C#86RHDD{0nze-6T7g&a8QxW+WZcg?A5a5a at 3Occ)y`fuW92#h$DR zw|tpEVLh~^&nRwmoN;H|mdMTm at O#)1&ns#b3X+E-LSFODIwDoDKCD>K4 zkDo^O1$$<)$p11Tr at Zt?avj^hlSbTu4%Sot7w<+r>9+e*rR?1bFKg4$)xDs zKvP)ul=%JKyp#*ogBx6weP9g)mhiGGq3oCgbV=AxLq|F;Tbhx at yz>J!KINx#*alO_ zc}sH>#I{Uw2Qt0NhBx2vbkn+=P;#)+FnB)$hUi`U1tR-C}JWg zs=_#r|Mk1S44Sh4R578fhWVqqwr8~5 zlu6rT4J^S7Z#uMfPyNAmuQO1?E3c=Dur&WCI)^&aIrnRgpTdZJleAxZaK at 8fd|{pR zaDtN_9^iZ-S1%vXdqWKaQCHs#X9*{Zy~??>$;l$y&q18x<+ZtDPX!`G8U})@Fro2o zPRIt4({nf7pfiMUKBZwkPT$8#hwWq?TXlkYuO9^466OhLn}$BHbBnIB$n6KgoHuv^ znQ{=ljdG}mhJ7 at o9>)+m1(yipDl7eEB_&*CQWtl|Zo{d8tTy at rhJB?axN>pq{I7-4 z=*#vOz;kRmh$H_DxKme~l)w2w&FQa3hxsSCr9~VC21ynqdSiNk3rth&^Qk|*n_vIQHhQtxRs31R)R at h3&k;q!*cQhO$8k96tzO683;*cl8%ti6N#O8hEQ z_yt$u`gcErQFNeKM2-2~g-+ZQyo**!{kh6VtEor~<6DwWRrla)>ID%rSt zgBZ$m7cMeuEXI8)XAaHzqg2juUS-E+np5zoL1gsUAHST7qq!C*a|ws8O7C%EdSR;6 z$zJ8~MOBRl*xCx at SS}?D!cvtw`QwYO%6^JwzgU^fZt^PkUjjJWRd5F=+|d-AS!Gl& z!xpG?BoWHDMfBeC)D at iL*uueD6O)M0P!nrtd>liE;Yc=`c;&qhpdjf_7^{&$n8MZp z)LmUP#Ekyc&LJ91R(#^H#Im7@)_~JL(^-|lGNfvD+f z at MXHrwmp?Yy~DrkOL+nYW$FiX7dASsu=wG)L8hzs{*bjsz%uvGGm(wXF6lWmwnG*y5h?dCYka(Td}3yXTfvJry%nLTbU)e9d3A4 zw9-!UBUkyfB_G;NKFzt7<<)i!3qV>QU3Xo)G_*j} zDqO#IJ^R8fPMXp;nDPiqnOw?J5`!s^vXsCqO!2 at Vjk;c+Nv$@4R at _PV4IBW4S$3Vl zCHJT+oQD|Jbjvk8a?Poz>jZrZID19`F2gSwveuh^?^TAdI_ofuMlxqx0WO?dQ}g|6 zC_g;@!=)wMUbM=+>e~UnnkBx9-cTj+7xW_ at o|qc0RLS%B50p~qR|X4v6&H1t&J=ur zrz^W2e;WhUVs-xQ^f~)kG<0a(3&>!Qu=Ps`$S8qKKU>pk8CDKYWr)Y$2(f+vf at BIc z`u*q<^Y~W`%aZBu&A?cm#kS$ozOqufY at g25_q2(}q<7WeF)>eRJIB;qbb2T`^g(=F z!BvLX%ebc~ZJ(27y(;4k$|km0wov(yYI~wvF|e39 at o?iDtdtXOhbq(d6_#GT;Yqk2 z1Xuw!$y$1qYDm4)$}iu8ZhHZDEhv^RP>QhO%(k~Yf0)VK44&yeNg14>?c5l$qS0x` znG{&#H6)j3FS>BNDIbZ4&U5haA~Fn04X?8OU99c}tj!S>M<;jD%y7YU(BMZY#N^9s zh{P-Cg(gQ7=V>PCgbbw?(2ds=&B0{x`sbhRNA+H}(W1`U){ib1FWu$kz_(T1ZfbBx zg~?7KH<0encOgK*cQnI7H2L-=N^t|8Z{G>HD&tSld8Zmi0TTiqQe&l_S`ZOeoRLqg zO at GI?4JmM7i?I at l7i<2Y56n}Y`}&2OQr_Of-& zH-o2zk(S*$L+ at O}mHWicU!hq)g{+^FsQuW5Ps#q+FVOpYd1p3A%_llhy=s3AA0YKS z;3B(BO>ul~TY|pg-D3=&S$0?I3|Ht?uU!q=)u>(5v}?L{&CsqU?K(ocW@^`w+SROG zM`_p5+SP(r!xbrFg^7M0YF8chV|%eN7y3zbAKsA90OJd4xrtn|1n)t!@U*2l%uza6 zp7;rESVS at YzuE#RZcR2qpcoG89MVC%$9{}_imjpz`jlKEQBamgb^wR4m%l)J{LDu# z+K*9a^3H|xmOUMo-|v^J2C&cYVbA-Kb5`IT!v&i-5PCMJ7XU-ex6{slr`}|H2SUB= zombDQI?k~lZudJP5Ju{trrMG1OEgcW6}X91nQCG|mA+&*BxVi7w3WHon`@O)gNgHA zIP!{$Dp_v-euFUHvio*>@03p?ipg%=g at 7f{HDWhF=6QSpBl)b(@&s;gfYKr#ry=g? zh706K%I+!Qro3a%dakS--#w1RbMPL at ni8>R1p$9=Ev6m z4GN~3#2R?b+SKv^OYlB?->Sh>Uq-u7PrGn>gNe2`RXOX-Yhqx4K|4V9ixK3ax+Tau z>U7x^;VT|^RUzpkRb!c(3*j|HsoH*6YW%rnj*0 at xqQHI zfzsztBnJIHrIVOLWi_lfPT9 at Rl~pI{1NY0JNk{DFEm*XDG-Nu8{r(QZ9zkM2KFE~C zGQFeG0W)>lvqCh}|6xt3YFMWK+iFVH!y0$ZnkZY++MvuBWy at rR|6OhWK zvz+#$9{LgZ61$Q%I)wpa^lPGloOx7?&=RE%BQg~-(_M_2qJzvtS at iE0j*ml*=)K{f zQ%dA*_*7fG3eoL^O0!BmplneI6O?)twVvTnwQ%3>GV7`Z3wblNg~rXoIk@*|gITy` zcmcN!2c~hRB(V5vn78pv1o|$nI$d*#fYA;;h5O|v(&}r5N2U)(k}5MOszzKs!*rKP zX}Ac9+FF1U7vIW^gtvM~&V8W;*I$;)Pmn{laP>U`>Jw zpfFukAC&h`x2==5tqa-~pG48_(P?N~_LP5?M7rx5NJEQ-KLe70s$A6raYg0kH8w;5 zDqxrbiclfOkA?W5aR{RkDFG#>+5k+`L*BBLA8;JCJc)zHc2urPII6;HM at f6b6H({~ zi>S~)bq^v|t^nb_Ny^XI4(aeQ;VAF3NSgs}dU+poz}(g`^VRZ1%XsngxW{p5O||Wi zq5KR3wUsLXy=En}4uEZM%T>K`13b*Xr!{Lf(YZuG5Vq^O|`@_h({ zB%TkI9Qryasi9BbGJahbTsh%7fSM0?x|Z>4(_8P+&u_6fYEG=V)6sCm@+a>tiYSB{z#r+il&bQn#D&!Y#GEx({JFYeG-WoZ0|%qFhC#K56&gP66WJ) zL-*-qQ)r=1E(3l$VS7W0q{%Rn%a6e5GLfo*DOD!hTTKxiZa6H1fp4ypy at j&7SaTkL zq_7`z91 at n2xw(%0LKQlq`CPd&ORhA at l{s$tdj(R<0qAQr)KZWJW$eU`m#s2ylzDU1 znZ-52BcCVp(`0^z%ooUfq0AS{Wvk>eUM^c;57*YT2d*rpf`;vc1?7DiS(6*=7ph5v zIjDZ$Bt2~6F1#Nf0}6Y>=mf(_QVSXk(npq{Dr8EkX+wdeS~l5;dnO(;P_!{$7{#k= zrm3EMY2{2 at EOePXvfCtY%vYwP$cr1G#-!W_-P>b7?e#g at g>{XEw~6&qLsp@<3M at s( zdC?fS5`Rdp%_*wQ6EmakytAT{lWV6H)#i&CQFs35 at aR7b4G!qkwbN8 at 9!byzWXLxV zw}FV2H|Bcfx|zykDrsdGE}WQs6gD58YjdG?z~)j48}>Q~zK>y2>Qw4j*RV8sp>gww z6HhlOrq<~9&C;?$PFhxsFA>j>E?PI`6TUb!GgG>fx9)nMU7dgYBXUSyUA%BggZ21F zy7h(ja2;(s&^+o~unn2Vxo8A>ot*r(NAPJe^dXm22G`|E8)t%UDc(pb^1+xs-WAaC z>bhyF4^JDCk=$aslOB;|4;Q(oiDM8BC57xRkliz6?=)MTmAI!lPSxj-g=XH?S*fm_ zsmz|lw)?Cs;No*_0E#DQtTo6r17yBg6$fnXJoKf(UBD}rNw_RA0MNEm!VQq at fkZ5$ z{{~uyTw4I;LtXKS#5+yrE-3OAh(;_K<{pqCX@*X at Vg_(o()2P(Ju^J^W69iLg6kHKvbZ?-fa#2c$PqKG$Ig0I7abk|5RJ(_ODK?Z}UkkrBy)EH9uJMh?6636AkvCv|Fhl~AsZ at hmUm)%I zmSU5DuO)#@2|rfC#s1TR<>W`=M)C&C8`396DS|DTB_k);Rp13cOLk`|&!593853xH z7miCG>ZLbE06y~E0_>bg_S3OPp(ID=+C!}H9awmkg}$l?k5A*H+mfWpW|{z0;TToA z45x-rMXt3rUN%{RRk#bko$CUVSVMU|7Nd@)O^0S@(k4nDfaJU2w&D`8a6?OtLWu`> z at +~znBwyMExoLizKf|gq$cv51@^3*Oh^fUD!>hH$^)c3G zr1j-MeQ~UBOaJit3`6Ss+30JvoYgmuywUUl+EQ|viB#m#8s)j>Yc=tvtExorFv8Of zi9s$&Fr&203iC+Xkksa0O!b21mjKPiaRi2^s}CnGOY>p+T3{Z!!*HJrnQN6 at r_e3h zN}saGJvp}hFn=13IF7DeVe5=P#M=0uqyC#V%C$~L)~su_sp9jYZHl?*l3-sYC;%Wj z44swA>FcRzNS2X>2X=@9n00I_D{=KrcO`VLf$46iw9yIF$O7!7l};c-x<&>QWPY5X ze!+|e07c%Yn=6CHP?0CQy1?R?NGfyXs#C#Z!Wf{IqcU&J2*9MpI7W42V?cZB19h9O zQ;ve#fUHqgK;H;e`14fU0D9Pwa|>e2GLq8c{;#hT$Lt&AcpG(XbVklv4Ts3_$j7G0 z2c{|e4G}88at!TEa&%$Ndfwn33+8g zcA0n=BOU)(QvCyEF&)na1qHN2$-{X8u!yGP(VgO$NL(*{Vu;-i)kV{R%{eXNI86O1 z?2=t){(7Vs727Wyor<1wu$LT>WG5D2CpL^=orrbIZf7)oG)_9rua3ZaEmYco_ST1@ z;x}nnOQOitM+FOU^(JqbjCpbdzMD=NQtVMij6>+;h;{YqTs=T|7`id*h$JylkNFzB zM>AqhPNQ0`ds!r&MxUK{B+3qn8Zg~4`z$i0ZKjB+Rx0%Jq&)p!8j zZ%5JfOWAb>Mv>Mvy-;B6ERGV|4m|BO_M9$>`wd@*JDB5C9H`Wb~G!r)$31T68y8az~CGV99|*q7td zlj;*bvhgq7b%UkZkd95FO-qSpI6Fh at 6X&)4#hx^`KVLo0wXkxp4T^2K2^YCEMP^HOQ+*|S*R2X(JME8MIr045VSA`g_EWE*))_6SyY53((Av|)XLcZ{gQERueWkAU_9%{z0P7&pfYSPvW0uIgdT5H-<${_2qd z!{R`5m~D~R-fIcs+89W*$RmA_TGa=$v1NCs;gIG_IR!ilx*}A1{A0rrzyaz;u=re7 zzhq3-53wI;I9PU8|W1Y#~MBhWK)qrM27zC*7E{mpT zQ)-q$m*4G3tjT8$dDU>$2u3R6Aa-mlt3LzOAf3n0+7dtro!5Chu6vTA2~)+BofDBa z#!-E9F>&)>(MvUkFZI&mt9pt5axeYQdxyWOcmAgT-|8LyYkNocHN7)PaC8C1uE%;i zf#lF1ad>B}&C%R@ zNyN}e6~lMINd;KrGePSgVQ^2g9kuO`8*QjwRXFAHQxI(-M?rgZ^?-TcbppX1RlRG` ziwESMUe#+mWOMZZAA&UjikIsYjQ&=mNp~gR zL at n=a(J?U+8$kRwngHbAhgeuMb=TBuSS!m-y17|8cdqQ}22xIErzvzx8?77O#ZUqTS`F%@s(x2?{qn{U$9W$9{jvFWnw zgfJs`TA0RMJwqt(`-oEh_V=i5BF`^?GSEC3EnOTbj)=NU_Ec*ngmiJV zV6-2Mr at ewZ`H0te;oXVHq_a-LQA3r<;4PMYGlF5!2z8~ybYv7qNeyQ>Jck^Qe}Pt? ziS37p_qiobu6wDId$h*My$An-S|?Wl|EfACcMks2GADP_awk^<|0m)9bNJu&pp$zE z{=bEP-a}4qFZ}=OVJFuPM%+R8Z}vO6zrlY*0Lp>?XYkMdu9JHc{tH(*xyA7R4gA>= z?xtYB0HX at se$z=sK3H})5hpr2O+5M$k5*T!Yjc at LQCgWx&xcL=_)@E1_OK%XM%B7p zN3Sr7)R>FhCSjCxSEev3=?H}faS~cL$IjrJZdMPkbe^H!CFE6O;EVX%WWH7TFi!h3 zGufZ<2yss%4OT~D?Ks;h-tfK$eRB_>3BkN_pxVsz+1 at gAdMcH95G`+247@}%Vj94<*E9mHg`JzV56uf5yjlP((9+(D{Ltyxy- zqJE;<^pOs?eC~d?DT*!<$NQpTZrsv*jPgK6!1#deC^_VGxXkr`u3I9HPWhXuEAU-Q z^MByLc|6x~$C7uq87{9-9# zs-Hv_7Lwl9`GwLsQ%h;K350lwys%JSS1esIt at -HwkjoTW=a;_0 at pOR?`fQC6B2>Hb z4S1YB&!{u#=9#3sjAWh({lq3p^2uaPmPc8u&_O8AGs$bRs-qbr8Rdriu!mAmDjX$_ zl-3t>Vj9eVHSI$wSXqgO)8Y04OS1*Xg=ltMur%Z94XMp_yl-i~$h<<1sHOQF5 at KUM zOm?_=bkNUz1ce^VB2h5|hV&u2M>0|L_)HkJ_YL}qsY9GXCIE62^(`>Jcl;pmWMFhP zE%N+JL>%yVm8ocm%v%upDXOWE?G?N__Sb(a^wZZT;@!Hbwsu=2lF)~msVWOvESbk& z9mkV-t4KrQ>gZKLRme_a$E#~*`jnS5*g;`H+Kn^i)wzQ-Jvd0yY(~@3(MFu{kZGY` z^eKL%Ft;-p8!<^2En*rebH=ZeF6M|MNee14Hh9+C50XZlT_asqL!_p?4L{YQEjvHO zU9~TpRDs&uNL;xd+4ZtLjC-^#drtXCd*nlFz%;VGI at ECH{BP|C8RIN8cIia at N+owuWzc>a8ljVGo(Yu1>Ssy0&9vXYp`#M1$48TtguU$q|td$)WiRZ+LfSndu|zVmq8 zQ1f!g{LAT8FOzp8AL?yyNDVJ at q^3>2UX0t1h00W#;n}$U=*PjM;-%m*VMOQwb;>)2 zcY!reORjDDSJ0)iQn$c$1{x~nI$Td%n%}4IgaA^|0_3l`to5X7yJNrQ$r*S{+dt(E zz{FAhl%+Wbm#i9ga-u=5+DXcHgo=NRhgI#gAG39q7$V2dLb+?E1OFhWqLR1OvM0xO z92g}_3hU>pt{t*#D^TBX3;^r9 at D=7GxDfs#kh{ob5=S*Pyoi*xNUu>P6{w9-NN$U? zoud0P8AocKZ81MVMz>aNZ&}o&BcsXNwxf|tdfD|9nAlBvLYoo$E}n^xodV=_LdP%) z$M3 at i2-hc@2JJ#!ZM*dFPLABw;)4F$Nx&!|FhX4*~E6K)7Mu#CfuvhhF{-k4^%DIqzXX4vh{nwrkzBmNgA`|_bw~1W4X}E}n^iaa73us7R_nlfwLnjT3X;?_ZnKYb1 z!)Y|kr(qrqb7`1E!z>!^q%|&P_0n(|4Oh_6Ps3F-TunoPhU;laUp1aeUqznUOv4r$ zK1IXLG<=$dTWLslflu8=!xw2tUy+?UjfVL&qz460ZKh!(4L8tmJq-mKuBPEC8v1Ft zf`-dzxRi#AX}E}nJPjAnu#ASKG<4Fin1+QkoJqq122U|8qhToxoir?_VId7?(vYWN z9u4WczEe#!%%Nc}4LKTS(a=gmGfSm)ZKdI68sY)?hll(^CF+v)(2MkQU7;2EpgXjd z=9 at g^6j~&U@=X`^<3f~>-I^)w*Uf%Ic&quKP{|_2_(*Nu at s2!2GWV%hu52U`a>4$F zq1SLx`c##ARr_1^4r#x!=>txuYZ7y(;zc-)7ahn&JaDv8JWz{Y0BR>C1GC$OJDS77 zC$m2kzS-O at d;}&oL}f$N8Hh at Us1xy@)z&ebORhjZxO~Ab19&-n7+Bwj-%23mRLuH*9aiE!P*(5~$CW=Je#^zWT8~uk?{c`n$ye#ffRLk#jljLXR48czL zpMd|Aqpj&J8Le(z%Y0p{TMxyy%-2gD2Hf-kg&$589=c}`mO|<9xVNYtp?;l$+RR|2 z4up}SI!tXDT80lUrSLC?|4jJLfPX&xbK#$bZ7BUww_N(;Zn!FNRp8nK*B-d`!nGH! zeQ at oAYXYtbxDLQ|AY=?7n?Ua-lGISK(d*&g4F9bd<1*FO9c7!JK>t=D1z$6*u! zawK6x!fgYg4MhW5ALI}A!Kg3Jzcc{#4m^(aUU&y6z2kA(-ejL#WPM`8KH(mxeS*N7 ztq{zF|5Et3x(!o~w#+w3=P30)q15}&Aw?r at 8q8o{okJ%vrSlNT%|qY-Xt2-Dq3a%? zEl+qspbsy5CtTX#ABKM?{Exu at 6#Tp3fBtdWH at QITT)5`IH3zO)aLt0N6|Ppen&E1O zs|l_qxEkSV9NssKM&=FB-|)|ef8mB9ed9I&)f0d?(py*$Oto8kZ**k z?K at 0%G>64;O_%5>8=V|wX|ayGI6S6ax at 4@s?ZP|K2L{1xI|@t;>>JaG{iGA*jRBVp zPz5H3pwEGrLi+jNLcy5~?qh_53hLS+G-`-I-DV#yHse>u$cB8AmvN3q7}JWmKz0;q zyz~jlcok)o;Rp(*{ZiEU?^GNqWc~nv-3a0(=ifo~<^(gkhE(w_V2}7H{34ABIusXV zj6}%Ky3j$38$sRy6vd_Sn_9=gSOjBoPRn at K9$~r$^EU=lh}$F#!dMDOfdD!K8~%?L z%aU5wsFv|?wJxcxYnK7Sh{beLd`Y^7F at fwF&S#*2H=Fx~n=kCA7+;51K>2{2DrKcS z9`r$YXz}T_=VX#&6j~Ib{(O5(!DBd7c1$5%4X2+fOP)NdIGh|;)6M{Tve+9kD%f*! zL!aC*;J6@;RW>XDvu9kbT%f at 4=SW9E^2yoaw>*WmH{pyQ8GDpQ~f0W?01 z%rlaaj_9WJ4PzZ|)mx-Q#)gTTOidTn$DBW1J4U%F39g-ztgM|6lawpLD_icR=Mz|h z at 8hfQu0CGbnT+`hjTzvTHq=ov)o|@#7*_!qV)()9{oZ&SwQR&!ARN-!s!)J(%tKs$Q at 1TP=qrSdE8xy7TBp z8(gCRtMx~z#A39?@Em!sQpk!EZUh7ju0AcxGoT5l%T=alNP at g;yEw7N6t|Fcd;+WQ zT|ji=y8$jx?D5f~<>d5W`1>QJaIq9UAg4>mRW0q!`|zL=;xcgM%pTMVwDIa>3)^d)X;wg;9PXW^R#PH4Z>I+Azr*zb6>{?lg zoT6s0r=JH%fJz z#h`CB^kN~d9xMcUsEaQ4W`WRyP`}{_g!!8e;n^#syxY?{$rswFlU~^Y*>xMo0}$ozzi&ry3p;B);f89Jlc5q7BO8a&(X)z8ZX;K14I&6 z77U1%g;;GuXK8lRn|#ZU=jiaAW%1_5%LT%Ss4I(ZvACl(qj~d4SCFI9S)*XG?0rLu z6~wP^`oI8{3I(D2e%W~OdWciux0}Q~`aMen9-|KAiZ3Bm1D4-cWf_jjRRh at k*1galo3x+r%OYT7`q0X1%c7=3_SY}pbvbWq2Sm3C<%#tViE zH3P%?5rjlMCkaz|s9jS&yQ$?n^KSWcYUg%f at xQ@_YK3k1TEY1h^C= z%m&K83`>;eU|xELxCWCf2XIza4lhVIte|^_7lf0}EszA&%~CGm3#=R1sc1P~WeR>@ zvR8X;R5|X#({9phQz#%fC*~;QR{L=!Hbo`Ld)tJSqz#N})r>LDfHIa1M-rB2f;yA~f4NIL~ zURfxxZ*i`v at F{J0Fy(4pK<8Cnt!Eo$T?t3KrFkXR2Ec#*9*vE!qeXaq$`}DpwF9dv zp`;7!aFr`-jE;`_Y^9+zh13rUVd}dH=U<^vkEJiIrw0JB!bj-Xr(1bt<@f0J9w at KF zm@#L*?Si2p0hKJo=mrxWPVGtrfFlPU)xP#HrlPWfG3d!uNnI!dQ&PuZMcnlR%f6(1r|MK<`ube~)1{0Fi5a_${*J zclm?@%r_T5&i8vf)2(WtIxwetrED&NDa2_ at _(I0He5y?7>2U~pE52H-d~Y7o;${?1 zlRyXY at CuA0)`YP|H3I^kI;|KG6#5RoIz*4_3Yh(k`${-vIrLs2Lz#%3hyn$Nph@}Q z3${7DJL;lGX)7bBBdc3k2XO5Ge+f at n!a}xTA-N*mZtXIIRhMqpz7Hj zkY|se)uDajXTuk%x2}H&@Pzw{`ZBcoT3LO5e;Dg~y^(gB-0(EaI>^4y+QW|XP&pp* zqpX3#J^X<^BDYe3Xc`Xk2@}JFgfO&nmCWE z&r+ta^bv#U|AE{7(?Z5z7eL6atok7T<6&np at W z?6W5+p`MwG2Oj?sPe;yph06ov(&%XiE9HuGQvS3&TCTu-i|}YdXJUmB{$}`R%C*zv z+8J_fo?M$R*XGEzxmbotuFZZcqsA|qs>qsYCKb1TV;1vY%ZRf6<#U3 z)8P*#x-;Q#bV6VXxwi3x`JTFsouGa%E{5%Kr}w+I>4c0?`RL|O8?_sESV190H7|>! zifY;r14JqQK*;qJA9B46+Ej~H!XZ4v$900o6g9h9i^X$y0#LH6i-+Jn49;NiE(Rwt zIKe9$zmEbWS9a&g-u$AP9U=^ko#JTR#_7%>?tIyuo2+rikQx_%WsN2OOpWGbjXAP6 zx2WbttZ}Be)Ak)C1qceUfrbw>?Y+KO0LqO4i+}K{UqB2GO7C`~mWc!U$*N z29r;@QO|h2f4sqs zP2zL}y&gfcz#6}pCUs4Ybfp`NAqLn+0iF4cLYDHxT`7z<-HxNETP>>T7N_`>FE-%R zjUOVyFKGLe0~>KSO}EdhY-*sCxmvjVW;KpBkVJTvSv8vvL$0hrbw#Nqbl$1?s+8ksbSq(oN3I4Nx9m4_asXM{DCF?axRf#I0Pvn+!-Xv-au`pI)>g*i>j z%qU!OMK+BVH2o2po#lOYNZxWh;Z?er)i74eLy^3+>Pz55{8N>o1^Ff$u)D<&nRswy zq&haiz;UVAjAX3Qko1G}VZ?OwV5Sh<~#+9oYrF!T4eY`rzdZVVjbDQOLN4+PjE}AkT(U-n0ZZ&Va*|^-T%njD zhMiKZYR1^`@nW=fP7Gf-GNqFon9B94s-v?$lSHbY2DQ+b-+l|~G(j#NyQ=lo_AqUI z9c|gl!c at y1nn7E3upP8g;qP9h=-YtRE7(eC(mg5mhqgK*&}0`hIg2)#efz2kzgl;2 zP-3OzwEs6Z%;l7|>^;b&NMaC4DbGMWUj>pZWc{rGaoaTup&+Bb4C0gCQlYU~%J=U~ zHFm9y<3>i~rTuQRBoulT?nylKHK9EAJ9H)bB|Px-mpf>`1;gJ at gA(G`vHe>kc|`$Y z(`{PPN;8KBV-0ErTo|;1((kYd7L)?q^u at IMY(>2zRrA2jjDbc$)lOj)Edpj%9x}Fj zm64aw>Hv-3OM88&L4hxJ#ZM4)r7gacnjGkdG=20PThMjU(J`KgSyKfD<= z5Vnhuy3Ecp*UJSM1M5y&e&1ld;5OrSF5G9`&_~`EOa#<0R|0nsCMYMVmgaqQ53jlD z1Ki{WQ?mX9*3^X!>;`PxAA1(BGD||SR`77T+raeEY#pSK+C&zR*JT^=}24U z$KR%^QI=AM->Q}IotGgJpJ(T5Ue%q@@$nAK^TR}{L)msD6YiZeNnumX(AeuF#ne>z z*S~_4&ft~h=jh=M8XM%`ad7BgRP3jf&pyVcDx~cMj$1IO03BgZuJZ6hAemFfV1G!IPrH1_FFSwxw&f_fQU10CtJ)tNseu7n%E%a^0$ zy~@1h$)md#c at -0u*sB2wKg=BldHr&2Fo`#NmG>S*$YkC1FLb1HjSYQx*d6-AdYP*% zfyaUH_*0gClj9D9pd6zP;rrZVgS(- at I@;iF*5J^(LckmdjgA|2ZGrMA)TiDdyZV$B z*f24H?d>zP!?dNA4`90iUSv(rTt1}f4`S1$s2{MwMy)$C*r2jy$)?}$RYpC?nogna z90Z!OEZOQ?fUB1$TMaW@!+^QEemiY=Z?fS%UuyV6-(U?NF|^_N$%db?tBNT`_qmdt zw5J;eNDcJ#FLIT~mt#-=LU#2itFhkbke==dZJ<5vE|gupAl&I&(KWs5ngXR1v)PeS zv$4Zmy+%f=sLFDQZ>zh}C!kD3z}@uK(NoH3`mhZbHlv{pIeO)bWf*}cuAnDJIY%G2 zCm-Kmh6iqCJd7XlKvw+MIxIyxkb{Sk{R2<=TY>&EPv|wg(hodfKZM-5a!oJ3GbZ-Z z*UbjxVhM(Qbl2s+apQYf>GVp(^(dx1U zXa6taz6Lys>S}m5yGa(Z$t;pUkN{CpsqrTog2V+(fDJ(jE(Ugq7|^Qex?)9`;inRk zbapY5VTx__wY1fWX#H*Vt%7I;5`sw(s^O;^fnv1L-gU7?L9&pL`OZ0acC(4Jw$Jl@ z&zI-P?9BZ=_uO;OJ@?*o&!ObE4^IA+DcXgQd})936iR;8;N;Jkq8$v$r}ig5)`!Xa zplRAnNWL$p)lwQ!NUMtzz&tlg>reg%NM2LLXdAo}sej306%DNU4J(LE@?@BnzY#}x z>qmfOnWh%hjnvJ>x(&jm6H691$1pbSV8gmZ`K)=> zKh$JJm|dS)Kdf%l>^eswENH%2WbEUjsW=cn7xWe^u!;F{fmyvizMv7s`Ve(kd_mXG zt#{O?)s2{2XDf6zFaIWdwe#8)6Xt3jbMT-zlIK*%L0;&|y7aMg_y#hD287BjjX z7dHNe4wu9WwGtigQc~Q*MqD)}ZzUm2s6)fUQ}HZP*!UxguR?i$y+3)=;_g1 at 0bv8` z{S}7LV3V4J8HxzAPGKWj<_+D3;V8ZcbrX0*2)D}A;`FJHM$q8+1z7%;aaevbyl(Q} z4ef)OTHWWj$_>NsYq;C8J1okP`-P2TsOK!y;M;`2rSy_41kl%Gi4edsQX(!W5wD=G z+KU`>WftNPwbg6;cq5*sB}2MaZ1!8iS?Wr=+-DXxpjNTmH%{0nV=j~w{0Xvg-2*jFomhp|z>MK-L;gQh$Lw6QFpXRriqj(Iv5QE1$?6VA36JFNI8aP1WTnQ!6r2%Uf}^ ztFA1s;yNY{pAB-{cI0~DGcgt5 z{mrGxCR3%QB)w88JyEHaI4Xwhu?4D*9O0*;MZEInkr!)#kt7~VW+jy6Z6~< zaux&w{Z%{@))yRBTy3~7iaxDCtelGWA*zS702=<-1LTs`V%onS037CKKkejx1ctPj zP}GFfii=_1!$hQQAjG=8s96EU!{RJjK?$(ROtq>L=x(K>ex#aKH%w2OrKdo6by$}e z%lnr6ClqS;>;aT=&p at O8ro)Oe?_j}j at iS!sQ{OL|KG`gug+->YvsFHGx3F<74X+Xe z`^@D+;ID|iGevyILOxR>J|v$h73auj?i2z+g0Ev93qNlh=UgZ|%_}o%fOQA~4Y*ev zSoMOMRA=L_$$@9=Zl{zWT!u`Uh-rFx9rJG&x+hs#nm+&idCI6W{W~I%-U|N^v15Z-D)c9G z&t#yYEPQn={MT{erQs2=@Snzo&jxx|_vz9x^#fgM2Z)$85_Pa(gE2y93cx+T?uG6! z_Gi$*l`duF9o0%Zl!^$5<}BxLbZf}jBwfPZzAVOi- at MRdnp|-Lg(haGhZOPyXf#`O z3Hy0}(w}`dDZ1VRM&+o>M0ZI4px()ZDu$@Q$7*O9;UcZE9%23O5M4<(G>L1bTq+g; zV1QYW;M8Xg)Q-*DTU1cmyK)5Z`pKE%vidZ2fvs++?y{k6$gcV%wbWK;hR=W@@Z3e;>MM^5M+I z%3kC;16y#{%;RONeow;qc at C0ydW^H4Fa8l*eEJKGCS6C{Z1%Waw%}=LI2$=WdWxNq zNvGK3xyLfDrFf3J(?G2_+MZ2j|F{HCv17_2=iSq{OBrm}B{9UjJ(BOAmD0cvJ3TNt z!3-Qd#NylaoyN8$?!>Zx-bGE+OFPxBL3{OIk?SM1IexD`{^)7di-V7);`e1gec9N? zKmRU&(|4i=(aoekkQ^3EkmVjsIq8E^46HxrkN>uQ`=DsM8$+Lb5t}?HaQDDKhubJZ z^myzh1?M%PsJ z;v%p#g5x?WZE^J_5V}FqO8wQB=o-gbM9E<&QHkpezk2a})sy7iH1Yh^C;T_nCwx!!-+pkO>aCbz=D(=k`rlM< z{hsPqesCTV;9LL*E$_S}fYJX231IT?A%U*Ho(Bmw%y47g`H^7zZ;)X79wagHh&T_3X$tG9XmWT;>*}O28#Ks;tOY6b&M^g#w&i(5Wgl#UHo1rjG z32NdK#NAKPJ?b~kR&hk|w0J>IYgv6}eY&|W%UtIuoGX2^Xz_RMv(Ppg2%BCt;yk-@ zDXhdb>riyJ;|W{vu94KM9&vWBy4bigSLV at SoxjHhYt#hwxCJlFuMBf{4eHlwi}Pdg zqTpU}jJhx9eab(uex5MrjPvZO-!ERYME$JdyztbXFmc)1j%U+BUAhoGbh3oeG2sQx zTP|6Q`O%XJH(QZzl18%Q7sk>Yg*1zJBDpVN`Kh_WD<>`8EiPPm;SRqdMO0mF&Or|) zCky3>ZB>Sfx(Z&knSI73ELu<=V8ScymXFK4`hs-c at +)zprpehOUZTFAv+pKlL6@)% zTDc%a*ygB9Hw)Vqq|`ao1zm-~gVHCS_8h#jD at qMkXqI2 zDU0R1g6BIfUZnQq^!@8BfN$r=E3+(B4rkAbj5vV5bbh>Q6!izjRYg|W<04PwNDk-8 zm3Hh}9#s9Mvv1XP*vMvT;(OoIMCWnoVfEv%Y=MG~ugK!%W%QRPe(5~Ed^FXcgZ9*W zon0%1xacqN(#L{``mTCB=lz^^=SOREoXsmT)Y4N*fG!>@uWKgwL6eTovnvWz=(!39 zbYW;J^b>?o(zkiiNBfgDuSiqzB*y_=9l8Mbttz1QQzfu26Y5aWRDCpvdDK7<^C%0@ zHkR6 at o(+9=F1ntqvYDh56uMtONT-BIl^~+0;&7dCkTzn%rQR^!Junx02B>yFA61!- z>Pr`T*gvQ7+c0C~zK)gqJnT4rvk95~>d|-#&PHa&>w>q8Bwg_Er%WFiAN~ptS6jmG z`qO=P;EKq86COd?)E-(OuG8mQ zR}WRwgl*;`B`uunVNX7d&3AP`1=3JhusbkAIJGW$mQraNbHe&tji^BMK7?PA0yv#+3Fo~gH>*{1`dk1-Y~CM zDy?^)gZC*n%sVGtU+?aN_sedW*C$<6 at 7B?i>J9UBDMfbmS_`D!<-5aI3)>2HVcTpy zTnuk8jA!?Sr at -4ecsm!q4&Hj*E^?k+{uMXgOoq0G za0(t1hzWX|+-!A9 zw&h*%8YD1Q1em-WY8p%u3Hkv_V_$wEreKFU6|hXr%!m;}#t>WyFRW?6>zzd=_6i_j`%@6N^BH)Q!?fAFLQs>9Mz>gf9>VOlRpY$culc4*d?J at 8uZay*S1j_8a-2+~1g zz6r`v^Is>Yw!0Niho&tZg3N at Twh5>#vyBqQ5Y!;K<)Dz__=_R}$w#O_c32&6PhAsY~<@4MgAGU?v z{|L;|u8sn!Q%Z6(6S|1G91VhAt-4OAHg$+nddxkK-Sz@*!ZfM(Fx7Po=LeWWFg+@` zv!p&fdiMdSkzE9|)Wli=&=ArE$bNE%fCqYwIAI)+KdEl~B3ZmAoTU8*#kES|fh72! z>wt$R8y<^uD~0N0_`d~$s=W|Yy##_Ds4RrXkKOQCc?Ue!ErW<3L0I(z5LUek!m6v6 zY1?pBq3y!wP0|+NiL=ok5ne7I8DC#@vbNHpRXc8yzLGx?#PMn)UKUSPM<^q;l~%3V zI$Ju4Gq6P*f_4UqXU&$n7cO2>(exHx9L#CUd3T<=JDOlb-AGE%$OaTqBAqM`p^}1s zsGhM0I}@+61N~MCUp34tQyU2{Qnk8U{1<;d^FT?~o2AHYAvB9`tR*H` zfF3)#r<;`2WBANy$LE;C_{?v^=hXf1tlW?hp`X+f^fRWFeiHZ4&!r9YbJg4M^V^My zUEO%g*0iOQeyv*={Aw=SmQ(m0>;Rf>NzCm=K4vy;#>g$5Fd$kI+u=FHYHDanJZ5k? zItNvP?T}@2fL at QmtDbQfyI=z3gfX%Q*1F|5YqX&|XE#mu`>#chv6#RF|13Pqflc za1Z at F+dw~mcpH9xyD`{>BDl+{m0A_;6dnmteTYyc$S`hpucCG0OQ~Ja5H46HK?uQe zB8Edhh~OM?8iDQRs6#0PBy+pb=pW+z%$?;fVt?6%XQ^ChfqC!@qMK$|$%e9bJN68Q z;x*-__yj08`OP~=LMM3q3GC;5X7LQ at kj1gHkpX+myJM3~e1YfyphE8$ocJ+J9Mzy| z;Y!U-c?}*Ounh-sKNKkhMfN}_cvTgl`sgrWH>c2+i4s+mWQBtR^7{k)SNa-oc6xFu zKYwXeDh`w1T at VpK2^q9Mot*_78X_kLx}%dn)9-`AC?*_}9I)8Xk`2qVGhx-Lc9<2)&flgEn7HoppK zolW9JZV!9=MZ+XP02NoFF)-OI-2;=2hyAtyCKflVm`s;ecr-tx^>|n{M3xu2^?VFx zzq_9HmoOeLHJ9NZ8;Wk|jZ#zHYy_67jKKh(i57t!fNeA%i0b=!dyAA*Y{+JeyRTu2 z;_9p{7*h-%Vw##U9|I3gvFzr-zsBGTH$Tq{9|m(hu$F}BbbC>yVgt<)5 z_4=%5(P6Z-U!8gk3HC!YH(gNCCJiOYt8U?q;bi`n8JBOF)vx;&8aXMC1M{R{%0eq< zvKgVfQrEOuIpv44Iz8On at 7+t23MkDU*vKV{X;A7 at rC84`ck`$byPiyj|WY>`YQz z#{kWv2u^*KmF;`ZfKnV9a^T*r!C2HER+}Bc;l*D5p(X5YcAo zn_!N#>~4%CSeh-6;=_9nqN0=*NVxR3y1uEqM|Gv&*N~jE+v3V}F37A-(!``Q;RH*U zT$P?^C=^tkG7SKC%y+;|K|_r-k0P)`==F}T at RrrOnesoA!#Bn^eLz8 at zf;fdcP zb27YOdo5DdeS4=^O0(%X{@%Ul>fKU00gVt!BbEG2H))Rgr%6Nsd zv30=-y9esbJMBi21Wk&HQaAqsP2O>G;Pu1ilC;x2mj{XT2=wKl3$}NokL!><0Ro~nj4s at Yonj}YXz`HYGywI) z<%nKAVy&(AOrclTSJ>H#Xfffp(UQ^7>Mv{0ynk8IFIRn5=JlI=HF=+yVKJ5iqd_Yv z)@q4q86#a=1569eDwW#QcC`hq=)e^8OK3<=yXuO>c$PNP^3^6aq7}WR9@%uOoBa{y z`ka>0hy12L*UU4U${^@BFX435Wr+-1K;BZSOV?V1`ifalOl=FoATKy&Qd?_3K_;ZQ zY-wf2e|(Zf{6iiujwu1mr~+e$U)WOEK~-XZmmjH+lvaa z>ers7#?DseI&!S_ev?vchyE#pXlSg0Is)@keCvNICr_b0xtKk?-AC${w`PV7&dJ1{XUV(gyaQE?(} z6s?>HZ!qPV_z4mkElme{zE+Ny#VZ+dT0R1{ox%}-W=GP(a_}g+h7D&rU5=HB{)-oe)AUKGMa$M*MFJw(q27+oZrVPXp1JhIVq(n# z)?@ukD};!{i{vv`E&p08`BFYJY*m^+729V0%l=MWttHMxVLq+g**d!6l1945#2gOV zlu6p2`#BT{VNL9uU<6I%LH20>eMN|t}&EtI7x^Pr?8)3B9oFt?kagHYX_9F^k0`!94lp3d?~T>Kd+}O4=<{wr!-Wh z&r;`)cXYRRACcQl3WO=}32|A`xXk{zEQrfYX^=A2IpZ at iKY6up$1AV!dnjB4?-(?G$@W12w*tVKKZi%U0j&d|O#^7{D{VQ@`q6+5__f2YEYjL$TCrAayuhP2p2Q)i8EP zGz!XSLnhd`$-Ap&-1=k?OWW=}Sktj4VtH3f4;Dk*c4W at Z*0tkuTBpNLW=`vNQ}9zW zz9&x4X${91X`|vv-?R%^V7I;t86~jMdmE6AT3V5LN{PFoeDmP+f?3w86t#VNLDu7I z&jQdlDIVaOk5hJJoEDIf{mD!GQ{>8Q6R=Gbm>YM|O2d;0A4`B+-rIoO($WghQvh+t zRwXUU89hw1bG9f6?0($qF^=vQH_7W}nk2zLp4qQJIiYwa at SJ06@yzG}2}2WEaSZi= zzCjGN%)=>$2)Um$+704BLT*)WkE4swfulqhdx0)a5+P?2A*aU(*lU!b+d0?M$KE{ z4M3B!&Z?}lDeLTwpEyz)wRMh{UV7=x!p~9Cv_s;Y_jX}MR0MDo-Xe8t>+!b4P7{UM zNHd^&$>QkFR951Eohh#tWM^^PW~Ein=!8Y>E)(5t;fwIRhPpr^3P6RR{N8VlXpqp2A0&%Tvi^D=GF)Xy->O$mVp=>xw> zUuoBZy^sm&b9)V^<8)5&tKZ{ZM;U}eDA2h#7VU*hW$fl>k^9dy67wZfw*w$U)TR9qA zf}Kzd^6k96KcIK at F??!)G>o>iX}4v|J)>3)t(lWH#-Yv24yVdzN3F8sXSO!4qs|ew zG at DFC&i9u$M>oLszlU6s zInFN4>_85RpQ+516BSig`4p+snNP+5CjsGK=+QGy at EtgzwhyU9O!lz9{R#4K#ze|2 zpGv7A8zg1d_Dj}ubNgqo28Rkx{vckyg{4&)Y6ndRR;7&Dj*FbWK51-ABEBLQ(KAj# zL6a+bMVFxn6rLjYos%wzPtpZR!bj!4UQ`R}0>QUGGQ0=#CWBN-cT1c5Z?a?$*hVFL z2VQnJ4)aLfX{E~M?32>eCiYe at DXMSAyWvu2UPHn5WnbW;4;?S*u1>ijcPcs=UH*?+ zot?v*8X}~u)kE~|!@C=Aw7B(*h+&q;gNt|<1KOiOfkD^fg-;x4+KeoZo89^XRCsVY zZqPntRaV#w7BFEwS>vnvr-|P>(4?>G(*k>iKr?Bg6vIf_8$w&KamA#(fO9$8J-lyk zt|E14|69ZRCY)1Wj21C|AZ(i^Y-lD%EQ%m0YW3GQvS<8 at xN8~G;Qx_|+t_MCiHz64hnHn!5Rm)3zh4%oe_bWC6A zi;b~iYO!xBA7yT~>J{9cTWYQKmFRbw83v)1FSyfNMe+#YP9kk}OxY+{~ z)Mk9$Nrhp4<{^o|p{~bYi5 at lA*)2}+DwCO?bU#mv zqdn}OxbHU2RE|?<+X+5}qH9bveuIVHe4V{j*={^7;QtE5iUpQSUh zCOxAUes)_;QOzSgfBTm>#!cv&p$$#^Zhrksery&WMUwSsJ-_{I^c+m>iY2gKM+a~5 zYO{L&u~x_Y at +o5gOz> z at l;f^3JAQV`1Z^{K;lXpNWrs|b?M5wWzFkR*?30tdc62Iqovq~%m-M~%!{MQLuMQ= z#Y{s6YiE~W0yH$?vZF_)2FbP=u?+9}%B5^w5Aq`;2Rf2us~~+7R10uG at u#x+{vZoy z8yZ_)t`(@~V++*?dk(X<5iaNY(s3uq%>F!vY;qtG-QeLV2O(i7QwjEHD4?s>K%8h>&T&PjM*IDi)! z)#CAJchk+n&tt;kEBV*o_}4`K^*;Za!oM2%S0Vp;jepJLU(fQd68`l#|GIrDb`u7y z#{fXrw(RI^w$2BG>q2jw465_#!pq8^kHfi__fi#RjIKo2q2sJeylfdNayzGz@$2+j zod%#?zR at H>Azz-2D`YIKpUqe5Cv#L- z9b$;9OPXMkK{Z0(gv~V5__FYK%VDhN1D}IF+WCi#J_v#j8o{!np{C3iZ<7o_FIdTkOIa4rzr8-!`7 at 8XIQl}#NeDy~QO}sSyL%nTFl%LFu zj-&@KjE$t+fg|Zd8bzaV6#c1Z at F>b_C=4gF3c3%!cuBv>A+(QI%9#8#?zGsn8D^4_ zRtac(h;B0oZ&(+GC8fgFSY at -J;1AQor8>=T#rGMPNH3^&+58E0u1H^fsAf|C4ZeObD`%!F3er><9lhSTxif2qscAdIC*D!`8s{;9d8D&h9Paf`Dpw;Q z(`G|+$YA4=*oMh(09R_sGQa6ISQiVA?$(x@)de>BtS;sT4~lv6S+h7!J_{>m_V+KM zavtkAPI7#Bg#5|5utnaRpp+~NC(C4pUMIB;;^G<53b+h+&QiPn at RpLK6k9#)*)7Oh7G-g*W`OGGh5el6 z{R?B9r6QDvJIQum=5A=r=c55hMYvZG at tgfNwq+y$qfM<}h59$O!i(7dc0s7u~WJR5;dM?9n6#nw*+sP}%REkJ<`KndPi zX2 at 3eJ2WU0evj9X3^n))pPp{=C>3_5K96E(NTY*uyGfgpTR%=3DMtzg8BKT8^js~j zb)$-bWD7e{Q9v32kt=*PJxj#9a8yH_3|wL?TC@_p}XwbDl-R)op}y9TY0$Ek2) z=jFIzGsCyQf at j62*vILl$lry$9Ni*#wbj<2=lM=)N^n5*r4|37r)(-)8hUhEZY}`{Mcg!CU zJfGPp7`SQWd=MJvphHe&U5VNfzAdUluVAr0&Wy=6xnzTxTL6EKlX at km@sqDBNkAs4D z;E>D(Mx)i?%1P1C@{2|+QTr7#$wU-y6>TA<_Q4Yw;WKE7eoi^6QK97gSuqR>X!l!f(~LVzoMb zvlJf7tM12Y!mub-Z7TIo*iPyUq2 at khp|KsUum2~uqg8tX^{ocj;VDx;@+wa(>!VIa z?dmaj3K}WXg16&7wia~LcD782!kbfWfCJOj^WlOb1g{M13Q}E-f45qW>nlo(4D1Ry zYRpBQQ4&5B4IYkU(U9m?f+7~U-$4!wf=l~|B3^{Fs at 4yfhHk-vXd_)UDZvs9DN4Gp zA<5G0Pl6)u#(>~t1eP6ngiKUvbUSRGs)1DOT06 z5=fxTC=uSE_A6$8l7R_8J_5Vy5pL6e2LhNN1V^F151~wc7ONwNHxHk}(2ZRU4;cREJItS8S?=k;-F*Si9S*lmOWk5)3wZ2PR2W9>WxC-w9u(QXat1C0d|` zN^>ZW(=TLv998vV<&{{C+|qLNTb!2`74zAB at GIXn2jw0jtSB`kTK2Zk9-v}m3Y4FJLb=_Np`AD+%qTBO5eM zL{&V2E>KaU6m`XFCeIOqXj80awRwgRyo}xwmI%QtL}A3Y at M$!A^x{D@@`!F)gn&*v zSPGRV1n@>*jngRvmT`W_xWP zPJHY3&fxPZd+m1!L*D7~a%Z131giOOWNdNcbXLPOYqXNKJ3kb4r>?L;^* zLb7pq#6*^ds#8&}`kSBkpA%Hs5B;=j9GVuD9VwZi=D)?(WhDpb5Uc>mlI{Ky zca31h!EOzs)!=2Mq=pFN_z+TPP13GZ979q+&G%!zOfz=P<}Ov6*q^@U7ERe}$d-89 z53z;4WbheJL<0Y7$l>BBAF>9#$os-tg8-5gTERl8kEijK3T|d<>z0E2_aHR9j6KW< zS$Ik!-DsSUNR#yIeYkpLrC%W8{?nBt!HKJ$@YQO?F<9n6Q=#gd)aa_m&c at MuIIWDO zF|2+w!wLpoVeMc)PUA}^xpLW8u+sLSRcYLFbzBGRXfHJSvBoWU0ag>gdE%rocaO&%6)MtAqerNAqR9Jl*6= z2U&kt*I8t9|JxQ5}UHKjo at c}EUZ^@AiC}rW?AUuz8S7bnD>fOzT4P~9_c^l7Cf_43A at r`la9b3MY3UPMgQMe=o`K$= z)h_2ru~_cY#iG21di$)p4T&}=tFj<#mS`)Sic-RI2F%pTB`%C}*H!eeZ)|AG+X(RJ z86s}hMH$eA8lBi%*x%mgs24NfqwRf;_HhQ_EbQAz-uh!P4PL5jrzC{ypupzl5q?slKqM}J+XXr zbQK=&C38wu(aw|{YLf7Vb+sIsDvqs$e4}9fkDDdZ2WoRpBIap~By_i=l*dT9 at P2>bdSlrr#2Z$?g^n at CYf z!V0a|BRap7FGDlli~BtyIB;E_cUqB7kx}#V_87DKMyZxO+C-q zEMCL*!_eB&hPN$0Z==hVUgn_}aV|UXVH6Hr^`r7qffNyf4M1X0(rD=5dr&cc%kxyU zctpu9AoNSaA?hZI;sp?|IC^|y&kvioxMEgD2V2;{1yp<?Oz=ya| zMx2*Dxj)7dJ|kY(mA6;3&Z-0%w=`mD>i%f--tGgJw9fPD8Ow~#eYy0M&ffh1(SUBs zyi9rokL09?n1*Hl=n=9DSPrdooeCYnw#>E8QqlnYf+Xo=EiSQc6y&)$e63!cki#5_ zv4vrNv|~a!@CL<70C`nH_s80-1ZRt|AqXW-W`(xD#t#(5ud7`fk;XJ zc*4#NU&O~#Z)`lJs!8?MPn)BudM%sPt0OB at o{q#+jKa7+~AE8bjTOP9S#^6*CxcqOp|zA z$>jNI%#28gjhQB~Ny+5cS0rTluk&HU?lwkD&)QoH#)@;bi92DW9M_O6Do4CDTtklIxa)qDB5esLv3C6WFaY1-4!TAZEg!jaeA at UD{43SQW z3 at NWGnpX&1pvRG6Ig#NgY9!+5epTv42Zuk#_5q=}*@I?dp!SGvAkYQT2rpZ0irMpr zVX3y{G+SIJ>M{%Chv(Ax;hA%&e|Ubdf#ZP>&(;kFxo6_=#Pe;wllWLO9}dsQ;$b+< zj}3ovpXHO~&>=iAyNGBo7 zu;v64dlYkBTn^0T>u at ud)MKj5F#YuJ(ZYfl-LRqGU~Lv%blad3W=SsT>Tz)1ETvsE~{x! zSw=}|ZxT!h)RpMC=07a0 at jInOFR5n4fd(Zy{?ih7 at Dls|Ia#|K$;;CCdb8Y!8fSBP zfb+J45dMo+q+=~PjZIonU+nE% z?5)>$Gel-U&PoBgx2C`(CKnbtUH0Xt`mL1lle{kW=6WK{yraNovRO%6jEA}Q=z6>= zA*^4Q0ZE-ISZtGSKnFnV-YS&I!c&E92TsqtZj4pDu&~~7!y)ko;f=k*wu6nI*izmt zD78x|CE-!R8wUy&*u^1*!Zur_bDy*i(qLQ~RxvWF>6kXK!k8KE7#U5A9 at C*7LEh}Sn0 at Z3&ohz0}spt%+DAU5pUiOcN<4(<@H at JRgLiL-W@lIM$ywrG$ z3>EG9Ftf-IG`JOsgXu4a^r?G)|5|)m4Xz-uYQReZ|n(kUx zZ{9m@c>ZBP1M{Zl>be`Z(LsbS?Ydh@#nv;Dye$THepI zPi9lFP;{Sey(eLbvd1R*xxbf%Xv?*k!OBEVFPm-s=q?~Uo zC9(gcu`)A>4m8^>4KMSb3fs#3--az^{?mHK?YPoSR$lL3a)GjoA~Op>SM>SAtmRXZkUpXit^ z+GhU?C}evQZWCs(#&=^-?1fh)GkO>rGwBEfkjeh=EOhl9)@Dw& z8}2EQ&s+vDH02!yFrboW&c-tvwG}~+wF4TV%{1F%{wDpIzU|nG-vMOgqz#sW$NVYm zXE6hpu;RTFrR5Yhg`ltMMH^Ilp`bZ&xK7-G#o`enITe((5_29|kPQXeNpt&<*Om`jFF-Z`Lozi*T(bF!wO|;ZB zWp}&mrb6IHmYRJv5LkmR4l;c9D4D2`MnugDHniyEv71 at 3aP-ZbShKG%45Py$K_*y6 zp5t4$c67{>&ipMn2GD3aTMnM(77!uXntYt$h?WaDeHtBny5ul-n1)hPtfL6h1Xx<@CyjXWI!VZDR}tM3g!oCb)i z$?o&8E6>Hb`zrkIMUA|M+Gg}q<3$rDuKkK at kK$^O`-+7Pjs)DFoMT0wGS&pV457=B z6yf0ropPs-6dwL3y=6Luhdb#l3*L_KGjOx80Z+X&>l1V_t)y2qc{vg1Qi at D6|Hhlf)K3Yg^v+7uE6soGzm)OD5Zx77R4_o3(=z9 zr%xM{vCg8q4zuh=^z*#m&2HR7ge3$=(q)o8ZgyKVB#}ZI+)RpwoWzNFJze5PixZ3d zCg1(E2Goktj6 at Fo_TSr1{%Vujt}JL%n>Wd_93rn`*2e?NI9a;2+BHhC?r{wc$cl+9yr8ljm3LbqUOX_g8yO9Mn$BEyfUjqn4- zl25bN;YSqdM2TFLZ3c+|$|UbHnTqR}Qra$F2;sVvC0Fe?i6hAD%+DM6QIt(}?ct at h zsE5K?(LLmgK{RBwd*b#5Qrcp>ufJUtcTHrDhr13(du_-d7JJytZ*Uak?R7SC)+iuB zJ%W5;3vr8lhXdxSY6e9yE@^A zSlBaP8z(^X47R1!QI2G1~UAG)%EYhO99il6`3>)hEG|=8G?rfdL1=ubw?m+%Yyd$6+F4C6S z<#l+q2v*OytOBtHW)h6m=ALr4F8@@&p8e_}n2#@qB~^>HR!8Y_?VC#mS$zHv*8}L9 z=zEp~oq2y at TSQ$C9Y1Nvk+d_y#8f>04em4!+19cbWK>?rc6QOVd4X-B??U*#1D1_? z;-jahn+&h1(%dpHh|=rn1;tJJ*h?Fo4p+MR*Y+<`SdIW)d$)*{GbTBo*~s{auM20i9=sUNXxf#;yxdR&(DibLgU5NoXFvEiH8$OaNG z!xPZ#tVwXJ!0Z2Yd+9?33YqMS0S1-s$NFrqC1wI zL)O_j)Wi)D16v)6r&Dj?)sCZx=uyZ9b;vARyh&yjSQ;^#cxg$Am;qlxP=aV# z!}PY$y|H&|s3P`m4$Xu2T6)Jrs?hXUR6=MHyw{w)Lb_6Jvhto)7xgMnAS}+~f;O_h z#BK@dB3I0k#;3NE9Ed&nW??NH4HyIIx^dLWreQVN!IIi5nw%u-ar<0Cy z>w`#k<>JMvhNDd*f at 5=g(ASwkgy{0 at 6OE-J^t*EuQaV^B&=+gM``Wd}-L2kXW!wBRVIaHx* zpd!^08wSp1(W#bLo$rYgdEMA{VV8*;x)jqlD|C(0-5rm94M zwapb~yn(gua~L2*w!m?beWRi_N0hP^=~az{hw_3kJ5)<1wV`Guh`NR9j9w+U0f!SG zk~*t^|405u}(DS>rfa}W)==GF!ON`#Da5GqQAQ2P>k%Yh^LRxG*6 zdb%-N%;e}e-3Sttuxmzd*ovcO6Uap~dNI(l3Fg6r{fR~g4_1#{YYjH67}nh`A2f9z z>2I7d3Lb$zIig0SguJ5$?yBr at ba0_eytkX!&_J3{TT+^&q>Bh>O*+Y^5}mk7u%S8$ zqs6OKYWSvG-DO_(&>KLRjk(GboGjEM@|l8lNfyFpUE1964$XBkr at 7bw4A~wxe7luK z=nwH8qWWGZgz#j!A;I~cbTWs???5Cxfml`cAXXJlo?SE9 zBqkO at +HZMUUX#27N0Eu|2dD(b^M&GdFCe zOH+2v6CLy<$$}dFyj{9n?STc`Me$R}tJ$}(&rf0X_@#^1pkDp4x}$-bNZ6(Ffg#d_ zlm2a#8Q99j3H;3}jSG+BrGea`n zU|M^%0jGGWN|=a)Hv4AAPJRbkWF;nXxK1J=8}(zHx+$z&rMb91xsE36K!cc}YB;s4 zMD}^7>)S#t-=0^><=is1w@~;a+*{CQo8Cz)GVQS!nNGp~t*J$(C*l7E`2Pz2vxOql z0E1~Cz7`Xv4?jmr6ClhNI%osh)HL11IzK}w$Px*9yX-@^AE>(YWPirr at Qk57bkJ2G zIVg>IOsTSa*-I;tmrA|3e32gTa&JxlPn?3-`ym?g9N%w7`|lTf*~4h8sw-w3*{d(G z!MfE83xjWn-45O>&4)HOp$6!kD`VS&@phGcb5n{;>`3(1(s$!8{tLvv^{?agBM|@V zLGh00DJw7jp??`orQiN9qp9$z(P+QJmyP|H)d~HG9x(l8cHr;)pulfgqEvM_r)FO@ z!&Eh2?cVGdGs9Gn^{VJnt*@Rgw9BI4X21N2(P0*}KBK3voj}PT1+3NGe2;-b^og&s z8}CEwJou$#y*ewrc`#;={vCIr&1~_fF~o9<5XE-2wdNB`-qD&f2~yz;Xy`>OP>XF| zby`j&sIR-y>-MneI4`@I|7xy`(jp0vFVL_?kUP#P#rANrJlCEr at 6(q+M!C{zQj*ZQ z{XoldLp%)kG|I!*c-UHgHYz6Kj>_6{=F>kC`?l$l*QKP9YWw?tZ=SP?&wp}&{SKoUGDfwZcTu9 zNC9;H0&Njp$re6nY$%C#Hs`_UW>PAS?6jA;#%r>NU3wV1x!8_0=jCe~pdWRbR$^At z)VY~Ck=e>ztFvd_7}Slkvv3ZPpW^Bbm&&c#P%Dzp8gxy52HDyfWNVGUsMG_%+lX5| zHh^1Mv&D3OLRr~7)^N~dx at 0%ZOxV?zLap_swmMsQ1S+>{E*n+1Hdb9hRj)Y2z!O^9 z=J&dn#H?_tNd+#ORICdA1h=!)F6FRON9o83H^i)@I_q-qD=Yj)?Dg#PMO?{Wn8$v2 z%(&|z{#8jna9O`UIXvbwsWrH3I>5tRiH4$)u+wELmy+a;k7brz(WKvGT|Gn{O1_td zHr>iDDd at LZP-WA_q>51A!B|0M>H?ddM3(8*cC at gcCTweRvy&P>$oiyz^wyp*4cJ>! zOHuoeJioz6)H3m!l(v>`Y|&*Q%}qk?cz7Z**p?6+3o$6mm8HQ3FNw0 z(@>|IJ^4cr43e6Ii|A$;UCL5+;4%zX?z_`~O#6gw4Zx>1a5i?Mz7^Z9)6F$)D_xI! ztj}O1X*|-+s!_$he3q~++0E*CPU-7VIF)uXE)|0J!Q13nW+AXJ6{mA0m<8GDg4Ymk z=hL%pyzG$ysr<E5v1TPq7f7J7PVvMTguoM-uy}me4ODu>KZv&6!Ek zSZ!89&E$#F2%TzHBg$61=%;L*0?+XMHD~f9J0-bJvcj_N_L?(yi{6?u_lmdHoOwVj ztvRz=EU7uOP#P63>Z7KG3*;UjEPZ>Him7tXDse;~wKaUPHp^Tyd8zm~hoO&J9k%yr z^rhif%??ZnP3WVKyLgYzgdb^?8bs<7$$^6v}h?VzcD^K8ZOYZrxc$3_77Z764Lt;Abe1j%xQAH^{Onr=~g$R0`64oi#-ZA{&8K19BSoj52M9o6w4EhOItpFi;`z zH#CA655Q+93hMcg z{2pNUorwXPI}~mD{R=d34A*N*`_W*x{M(Wr>@OKTbPRy?_?ZD{NP5^ngS=xtC#ofM zQ5+N8gQSKpE+IJE{9QccQy6u>)pF0jh3Ml*45FEXA)0fhpYE at cu8fs<)!-7 at rv6g; zfUf%q?wWz1;oU%d3y&O7(cdHeP5-}!>%@MT{I)?YTOJvJ>t6>AT=VIH1Fz$fl=9H^ zS$5YxI;)EI#t2(%m7KRgsc>r)~-yrbzyvxC(Aq=zYAd;xJ3_`&J-2<2!8i+ua zI7jYTAq|%!L)H$FBdNmA3TTTnTbc;0QV8Z)aP#{K97K5saiUM2e&|zNds>8 at b5f7x z?Nf=t1`h}UlO+y6UnbzkZ5(q4;iE2?9Ywx%JooB1kR;kp;}m%j;*wwD;@qGmh*HXp zD5bsnGVKFra|*yf?KP??eNh zKTDf>Vjj%>PJ_khz=``blrUlqxfw4>&|JhPqR2#Zg%}6JM<*Z%a5TDK~r?`l&ho%0|&+X>(gq^REU+uHyl`D ztD^}sY^!?=f9nt2K))-ltS7R%Vz;pEtgx*Ob)S;emeKNsM=k zu#E}<`TLXPKba4H8cpK3?qGO~u&uSejiLtR<~i$=rc?;QyL2vIjZVZ3bDH{yzC%C6 zU6-C5>1s}IQYuV_L->?z4v!kpuMxC`(5 at IWSgsJPHxDAr58_hP^sE+_)buPAZLu~OZEVx{m* zx25rOOZaBL$v;#lNmHk2mNgsiJE>>Gxm4yxUZ!~8pxoB7#?P(n|Iqd}a8Xt1*j(1I>1pde+~&?rcX+Ga#kTWa^JZK>EWEyHcLwryYfZne4PcWt+A zZOfNlRFDF#c2}*;(k&{oGmRw*0t#_|&-0vnhZ(%EyPxm>??>j|`#k47=Q-z|=bYy} z_nhbX^(kbxg7eF#g22rEPg&bXpVi)+rpr<`$<7-%8vmh&oG_?$0?>MW7RIqKR){{xgTWubj=hE*}lFE+mcS&E$_&eAp_u%fwl;^FhMd z{L at 3$D*tq at K=;!sZZ_BXL(6g}$+57=lFhTD*x%KT?8ERpn^%D+7n|hO)Id8Y at M&aH zR3?8r4ts(|Tih#O7d4B at qibeNlIJQu#MZ1a-zyg=J at s)g$oY1mTmC6py3m*?Azsi# zb8YWn6(NtqX+3S09qLxp2-xg$vX1itFIT9k(92dfRa?eGJ2g9<)Gm{hfCIV1^Cn|; zV1nW!Aepr>^Fr<$W-+_V72Yy;u6-lvy?Y$bRx>(n5>bNSlVUU$<%acVZ)wWkda4*tpR5 z7&k8b#yQBc(ecgyPnL~`2MS-W6+YIfSvGJ>Fnha{TQ(N=M_4vcl5pz%NWk?7Xidi- z)W!pKE4D(ET|?;~uxl)(4*SOjasxq4RU~YSb+MNo)T|r4{esKUWJ0$v*H03BpQ5Fs z$Sl;hpru0_Oq+; zK%HUqPX`%2uz>$hj2?3}qeqc$^uThJc0Y}oej4I*qeqcu^l1M#Mh~pq&_<7<|I+B; z;qw- at KN>x-lPf8HuE?U%0|6mR))C$4 at yx9LNTWyWP)3jG-hZa~ccP~1RqvHtUKNcV zDj7YN4s at 7Xb)(19fsu1Uw9%s%jULZ%oe#NGh$vT0qD&vxI&fZ~`pEfMUV>M>Uy6Z3 z?hb?&A~?p+fQ&v8Nz-N z(NLXd2ka+#{r{Eygq8+F+fNqI8^R%tr3~0lR$v6tNCxhYwx9fcRoH$)M+_qDCn%o( z-hL86I_0d+rfxr}{12GDd%()^_VD%-%=B;9^bwRt4N&$Z4C3{kX!}XC{C~Bd(Cas} zpG0u9e!$9bIDQaEpY{y0pJ)`%wV&h+P=x!qUX$frWIpUmq2xAqffT(tcJg>aDl1m~VX z_LGi5?BO9QU=IeYST!(ZK$_1rrL3|JYK>D}QA6c4D-BfAO)&69no=f(O)2Vwg717X zrR+p`GBl<96OAaRaJfe#ZMdmEL5l at Vx6p{=;;@=a_`@sFc9oaT3)@v9crA*st6&?u z_$blhLruxRu7Y3}d-Zj)tKb9KRjl47OK=u4*Ftuczv*U_x_)j~*{lN|AF!*$>UNdf zShTAwj;z&9WLKdtP&6L|#h7znU{THV#j?GKs~H0(m6vCpYf^b)z at +js&7^X7?Lp~I zZcBYCR~9%ww25#9YXC&Tg14LY(=w4Hc2ZsA!r8{Ygi=E zbb_S0=_E*|6B4a2);Y}wI74A6|X*x;ga#$2;I>8U;*vNNzVZpzQ)Z8oX z(@Z8G&TW#)0k}TQSoMNUlqll*7KO)Quk@`=hSz***vjXokm%hf$3X6CP z^$)6Q*oZQ~SMXC)L at Vyny6SbO7ryYi)cW9<&aIh81cjtLD0MW|U#YiiQ;{SJL}w5n03sme4(9SSd2g=Ax)dWNC(# z*dooaLdh|BJo=ZTrd#UZbID~<8PA@;sb-``U);;hT+s%W at io(7HM!HIe;+|33y)K; zwAaU?q2)?=3BjjLx^AY1)`iD?6kMoJv(?1rJgR$s2;Fb2Uo^df?c74P657x at hmCm@ zrx+RwcwUJ}#)dMRV@;uqs1c_2l?aw3H&<;H})Xau(9W%>0x7!<~vYn(AN2`jdY^1 z-z>*>)zkt>vz+Mdx5%kod9%#Y7>|W5g`^&{(!4Al&TE_mk8xIQOxnO=Cn4hn&Xr7g6Ghr;)a`vx!e#Dt#hEt+00wVw zzdW98s^@3?>+2)@00faq-;p(Taf0RwV4ari_HZ(`bRBetgGv*gdDgrabZ{n=IAIsC z;cYcb&2IMHZe#;P2*h#E1`ap-sGsk{3JGk~K*145za84ftSaEO37B=W!iMmMEN$1_ zX0LR?X1g>_U1etvgOahK%F#_hCn_**fZbnY)6b&qXd4F%pLVHgl&f%hPg%I8{hEw8 z^qUF4IcuHdD*xqJG&{)?*?K=7`DS`55Qjg6waI0u32%m8le^=9kY_BaKV00*1nwLBv2HgRN=`+ zmts|?#3?7$WD}mo+=mBfmqKdsq~ypZ)`VIYe&tBEVJCZrnuIdrKAJ1AQ3{>HBNyYh zC12jxxYoo>I6~YB;#{AoY)z-cHD?mgC7CZ3o|IT?i+4 at 7NlLDFO{tsTSyyt}yENP6 zvEcsY&>Ue`ql>)|$H%Vgl>nBR at t(EBnbnX7!__03(7S>q;F|?-w~KxCSK3WRO8gU` zX3SKHkUO zSX);a@~HT*Qi=(hjyt2o7EiFzM;=53u(wzn{XXnFIa at KK@Msq8nINh$gjMvt-M)$QKIRv$FPi`=O;9LDlyXGZz0= zte-!CC2I+9Q3=NOVBoPTks1ls)L0G?wP<`wmw84kaQO+(eifBCmFsZC2XdnnI&-Kz z;o&oQCdZD;t&#Pkd78R;!W3nsf0mFPJORBaYae#aZ0wpF>6;n$8IwQ2NpGeN`uNs! zN}zB3fIa!WtgZ~|2mxO){E8(`(D+Bs%=bToFRkWmf}F_tXf}<=E2?wm6>aEON1IG5 zKT_IxmW+06 at 5%ff62$m5&Lo8s)0v5Nu~~Rjq;Js~G$4r3-ycS=&cR7x)-8hX at 6k-- z;VKp+DFB%9Gl2ftiOqpPeMBZ6v@ zd06}mR4+}6sP0gWW>=tgDrPon0Lfw9iV4Nf*1s2W at L7|0ZGbFNsG=EKrL*~VCaJe_^>Fy>Fi{3jmP{R at R03NeyFLJ`(R zzMo3Ia-G$iamGLLTEvY1D$mP)`*7rp|K#8q|4}X3if}S^@2dZ7#_!!eXvWu$54hRA z+>nMd|M~3v0m>7#`WR>c%U;tpfSEf6-1p4qlQ(F^f#Tgo-ZNuYTfGfw!nTCK1G@{n zDn2%%hku*cD1EvlqjB-M-s^g=qek%^kuPSCZV1o3emUBA9Tcjr53R=!T)r+jo!vH& zbTK523Wdtk-h$Ck)+Cwa#4E1{Y9G8i$HC& zi9OQC89hqN5{)qTZWlh`p4E^OgZ{kbOYwW+`Rs$5FgN=pRV4;0o6xsmTV?P7YR;PX zJN%BJdB5Y$0B~%D)7Ro6q0p|Bv at 3os2v`0jJe?TDK!h_rJ2}O!sL)7NqZUl8|WT9>Q=YkGKfourceJ<#wNKiFyiAU(K4WTtr+3g7W$+ at 6g zqd at 3Sh|NA1G$pEpIKBRcP?T1wCJbHXA~>L_$4j2zusRP<MBxpcD@$0WYWyVkx$vY;F5yuqoiA2yZV6O#U;RNwz`m{ibhH}190G@&Ck zkVnws{gs{m${v4ZdkD>sY0}yH*xcKsD{@y#7v-*&&S$T#4a>)t737z{2qx?|&7ib| z61^pT=1}~b at n{1o>9b_*%P*>rEvFso=o;vO^>5&z8s9#lHU$qB?`oi9TJL3P z++V+!B}%sxOEbMJMY__<5~K^g%*OXkkxyuh$=XubL)N_aoWUlzCVn2ok3L;Zd3>qu zeJ?NgXG+#i2Zx^`BcLhJD~Kctnj3R(Z_qioftfYEh at E-iOPcxYNj(>xjJkC?MPtwoUeT#6hpUXe zLg1p%FEHeGTj+LAHd{_nLPyYXHrp#=lQfq+_e7t6;~snnCXdE5aN?ARGjO5t;e@}{ z56UUITk!1I5{K9;joEOggPcVyvH6$S{S*C5QoT1j!xMNScHS2D!b>=RQ?sOF5a6cw z-^U2sEa6&-TNdd1}>Ffhns3i(YjqiSV+#586!f`xM_ at nQ3Q#fZp*s9R`Mn*We+v zW!YooR at eJ>$`bUqivD-=ZRovW2kl+Vg7WN2u{~=q+jNBrBTsdTy4;~IcdE;i!hU2a z4OGK#*@2#Vo8|)J2eZ1eRQ13 at at!&c za#Cr8mQlChQWdcK0I#aYcqBiM>6Yp)XqHk|x8GzUCyw)#d(!Q3i%Z zZFEe-h$Q8nxQeWXz}mKsKQ94AKu%^auL*blKi at -U3z*I+@^V`lD5m~G27=%(Y(2U+e&gaQOca!!8y0O@^+UiFajH%QHDO%0(Rmsc+Lkh3Fzc5Mckfw at F z4_yQ=XALN!t#v7(QTS%utN{HRlJzkL2CJA)g1T0-DQ#Swp6S+DKSbUzQjq7_ z>`F-J&Av#kU>D2eJJO}3lxqq9!V@;nnyyj}$3p9=pxK|1c%Dh at goJKfL#faV9DGf1hOP)=qAQn-O<0AIng z*!R&^E7YDa;qh3(_YGbxQX)Tq8azxZP&3@}v#;@GZ0=Kd$~i_s7ij9L6m^xojG4(A z&R*tIJ%x!9Y8A|jwmu9a&{gDkSS~FizhKn!Gt1a}{JvjGFE3-e-~raIW!mDEy$sLZ z)`=Ck5iqV|iFU}fKF^l^aPGr$+=jUhQ<}-NVO?e at 6i9Jk-AA-adb${?R{H$)Tw!aOu?0{FN)>t9}&J0BlRABY}>MiB@ zTFmj#cLdv*82zUrnU{zsyN)W z!K{(TDu4-$F0P;K9r4;N#a*(5Jc zTXpKAVV;`UWVARmENkMXhlZtC<6^AwU!R9(m_}i+Mw3au4LU9^5c;h`?J+V)FA+Z% zYFlVCW3o_7-#&ZC2(?@3CRV6 at iEacQpVQk5UB=sMlj6O-iGmNKiL$H>s>&_Szk_ZfJ`2&r#p&HB0HU4spJVKFRh z4&EDP=bt}@h0W``un{*>OO7E~+(?asaSk`Mi}mjYa#uH3xLU$Vbt_OeHL zx0kO_Mr?+T=Px;`jCcudtn`>ua&+xjrQ|4xs8YVjKWmg-Ej$|f7yHvgkwZeVMq{G7 zdYN0D-&zqG3yrC)Jq&|_Ny7K^F-l1j;iB0Zh2C*FPq9kje*f%cSqdOVdiw~~MUPeH=CEc!YwUzoF#LR7}NS=}W5l{@TAsN({1CNx(qbwg>v1l at ho=z%=*CQ*+L zy;qL^*yT&mis7)x#mdy_$&K>&vvmxcz6R2!2KD$f!Q{1k8P#wW}p5EW2wS( zg?RY>;vM8`_wfA|rODbPHmwv~7-Z;!-*V^3@|eI(CqSnYbf*TDe$=R1T!AS&v at w(l zm+i_ld{RHANLOX*$IlZpg?8TGXnj%Uv3b(iWkg45FN?@eiJ|wzcv2QDZt`9NjlLLN zxzynpn(;LBfE(ti6!(&1di5LoZJGTvYDtsl>B5a^x2q~SIqp7OK at q~rb}ZjrVA_R0 zJ8Pl3UTVYL at r`pZr{F)!jpTHJy8Ko!U|4tu63`lJwM4^ zCTw33n{}`}Fw33-0x=#|BucSEJhL)hSzxz*BKEFKDDXB+77wjt)b`QwQMl>1zj`yY zE%%MQ5v?CC?{WKpL*$;UcU)oD$9~ct at vhor$}_RcX)T3;J>~&lS0c>CF)qT`=>vXV zdLx_Iz2Dnv*4|TOOcfqPL at 7M3*s~69$cZtT8mQ(Gnkt6sJSRigjmw5?iaBz*ca763 zrz?3$)6!yoIaW%Zb|GFyPP+&%annqBPnqQyR at aI2(DqV&{Ku%i>?bGGO-f@~j#C-| zYEj at 790@^NJh7n>?@(K`0nUP{XidZFSL=$}HK=6GU8KynD~;tkf!B#Zi%wu5KRL*A z*?k9T7YWAY at t%#59T*V-^w?k<0bs(#r4J}=Ze{UO|JE!s9qGh-vAhd4UoFa)1J_u>+$)5X2-SULCMPHr`Lxi=XX1Yn< zs}ccr0Co9Ecx!@Lqa~&Xs!SnK8Y&jTIHJX_`!l85OsV#&p*G!9|C$AQm~NaSc65c~ z*p at 0KPIp#AnLkcBrObDdZw at 02Ehy1k};BeJ1(E zn%*=irlvPu{yk8#H5aH94;X4K)CPeKe36nZH(rh{3U$m4eMN}Ut&8Xk*a$S5LNzD|V&8$FZ=ZDD4OF;gQ2|tF zpL`PQ0xwjWPdwUzg*mzL(rlR1rwO|nT#)!;rf%Yu98n(&)#H^@;|6LP8o`cgNvwbX z)O<%#und)&gHl|x#e^+}8Jxk9Dur!Yyb#lZzNnhRK@%Jl|0idH*42Lunmdp9`y9;i zW$wBOFIZ6zeG+tnjVJ;BsXKU(#W<*2c8YBE%Y7KVu&~GFb_dpWGIWNDU!LD~Oj9vn z;*Cm4r}vC{e}U4|_>CoC6U4 at q*Sgpp7yz`rLhO(()3RIp%gd0!z8`b~#m_&DK^&(( z*M*~G$g0PL46_b%cN at kFIGoibenuM-R#)X at NluK&nUg8^XxH{~Wg2eVC at U+=Xev9< zljm}mmH7)hK}#rvSyjq*u|tp1T;2yym!rPe1G+{hq*6ZyL2;nov2{H6*ydJ~8I}pX zGhVw7YZltqK%Be0cl1z4bC>U)do1rwP}EgbY>`Iznxy#d{m<7zlF%JxSZ_6X4eHZ! zUzXeh6FAa?#jE2QemzRhFb6`qRw}nMtFS$*UF??QcHIn=Lrz}@h94O*YPQML*y>Dd z_furA?nC~mSPB_cy^}s1KhvbyS3C*)i}@|%BEP<))mcL<8y9I+t_(Kox?g4RfPSl| z{p0_V>FZn~uM@&KFj?}BR+%J&E+;#4D#@HlY612p^o7~GdNljZQhmAdt9cYM@?V(6 zR+kbwsLXeYAJFY5-nB`pvR59hv}c^EPpET at DY*VU>7twEj?e at OE15L1ZdCsDA4v9_ zr5Lp&N&X&*Sn9@#y|RLNWdY>KHhTdFeL%c+$OxLLTNS zmg~*(RS6B!CD-3(mM0~&NfR2G^ZI;?JQjeXuD{JHJH3rI?;cx1n|x4#dA{lK at eK!B zy$$B3?mhGcC#Bxv-D3ta-*_9%km+dm9yCu$FH|XjK>GgxXfx7(2k7tgHd;b;yjM-b zq1dDam8G73J1qL- at jPs>V zu{F8b)8tX*^qsNtR_$A*BNtFF4*4)VTk29UTmj2cRUUp-`cXN1HlV6`75-R^ahfI;I#$^|7cHR9 zP_9{r|D@>i6xOzl#~)3;MW15IFdA-`h{pG2VOD<3S-BZmxei3x;?Klr$NzGp- at jM; zX^AI(Ce3lP3!wbKax<>sR=t1$SF%*@0rPy8yg0m6O<0UeRr)H1%eM2wERBE?K$_3%ouuHyr=!MYjO z2hxY0I9BtRX8J~(jdMk#phHySI3L*$q8^HV}Nj6HNh)<7my%5xL at oi$P7hN z&n#ny(c at g6AKtiAx=<{1u8MCdY$FeoW6HRJo_*z~HiM#5{FUJne9I(;0mlEez(>tqdCn at Vs|alD|4rdS4Q$*rxZH)yN~dl`w{lQS16R^ zVdw!Lxml_b?g7#txcMGB0rh~_g8)h&Ev0Z^;g2e`KVuh&0o1AXK|8HJJyP!ZEQIy za+*unUX)pFbHXYqQ1}|?au}Y4wg(8lcP$hmd88lrMDE6Y1m*t157|t7Hp6Wj%hqpO z*_Cul-=h76huH;Gt8{&3eR4k%AZ2By4^rI2FrnE9&MC3 z>Mv|S9d}hMzQ8n}wn;`QX;li3V(Q)K(6f9)BQ8Qp%k#8+tCHMo48;;p$1IOg^rpi^ z9TS$jAU7qpXo-WiaN-|R;x=V%YoHE~BxN1+uHA30@{dyHANH5L9e4~)Q*}$$*WJ3l zZmhrLtw22j{3Uzq#;%)>RdxkRPWVgO>PNx!G)vfa1JwGUzob=scm3qRqs7Qy$f}gQ zuNJnxf%_PMGE4*hlJ}L8Hep+QPD$&!FW{D7ZP^v7ysaA92-G37rJz^E!K+;#_!%`* zIV+1pW$G|M>JS16W+CK}2HI$l4zfK56pQ2hFh`#92)dlU5(&E4+vj0I+$pphtB}#+ zVy_TrzxMPzMy}q5l-O_2BaH#N1a}wWrvjA12LB^_>E>-ekyZ-d@)Jp=aIc>Tp)vH4 zm*_+CQC4~$3TRX4K2`pZ%|h~W8_T6 at E1N>s!|aOla90bIHZ$}duLw>$S}pv~BEbJF z7S=*#?|8WY?y$_fSMd%DZFmjuuvEUf37hF|N<=dqd#)PlxmU@*M~vD0T>+j6OkNs- zCMsPHD)NLXJRpym!>SFmU2J9W9h~4y997xG77j<`@E!OK&DO-G4wve0l*-=3gyB*> zdIx?iazuxldY^WJ+?4K2+zY=BIUb&E-Cyi+n%v!AD2EZ-y(~S+%J06gey|Wwx{XM4 zfghWPVeM~#3T8AGS4Qi%{J6^e6dpeGgLM;eSJJyTWT!~>JeWbcy!%vT4`dVftTpHP z3t{l@$*D}26S?!-Je$8TU70$W%pWoQ6d0*-hlTAO{vkk4R}bNLh;~rg&|+~5 zfY;6Rv}PS#(B19rv8=oTt*tjgQa6H;4D at 59>;jdHOEov7 at 9!rfx} z*T3-VlO2@)kkwz=nN!&*y#$&@C;ym?`#saqXe!jUVxOG)A!yoeH%~y{nGfMg0fxdx zK);Sf`bwOzaw$wh;7caHt?sesIpe938G~q$P}cT{z3U1hn7Da(H?-FayQnD zHmySq%GruEpbGg|bsDX*Dgt-3p;4=(FYE7Yu00}}9&R7Sy|{PbCUki+tU!>GMt9%~ zyo-HJAL-MLcIK9rM$dHR)C*E0dqL_zFG#~)kVL(}InWDIu@^uWKrL|ny4($FyQ;2V zJtgwpZ%8@!-LD^cPV=G3{EdKZhRb7ev%kd9OkS=T_^}71QZtT%+PP3+RFn79XOtc{ z6DR78bv)cy7seShR&D||RysA-pk at luZiiH(X2PYcuzf*6nQ~ItUOdZR(g&(N#Vb4< zXQGuP%-Wrx1h_m`y90%t9y5&2$55LN6xm&#YjoHafF<@|96V2!4trXIIbEJ9I;`#( zvf at H;lFKty2d~hQrno%U>aa?Hm3gjn1DpeH(h{Y)JeTW%XWEY>9GIR zV7V?&p$>aufMlM_Q>23*)RN9}d1mXdJ2hCb%Tuhw+#2jAm*)l at He-OK%jLOI2T#_L z&U1O@=&&RWw!r1NNr#y<*dmvwM28)33zJ;x^32u2AGPtM%UqtDby%YYt9E&^b=Y4t z*gY;!jt+ZjfaG$Q=XxFdu$EMEc|;v{uLfJ=^5p8UTQ%52F3&U_Rum at r2HLZl5K+!_MUhqPgoz&GjO6RjMa zMBow~e7H4CK7}xIb<8d;Ln?u9cJo85?2j5ajlkJ@>c=&3I)QU^@B;(nClls+9kWEs za0P)y9bBw|GYOolgRj=WQwTgw2ag*dpKTr(D*$8CGUS>E#tHxjKj+{)^T1dE;DZ`? zmU&>T0PvfihshV42gVA(Y}7K`WF8nR09>zuUFLzY0>Jlc;CW^~R(LE60RxNdTL%hQ zV2&6q05wC)v&bAVSOEOe&oKhpQh=7}BLz*MfN~JE+{BgvlQG|>DAeALhgw(J*c?zz z at c8&lx;mIhS0~G&YZA+#YYMv0CPKI2M8dM^7AFsOCEenL z!7id(oFUlxbc?eBbI>i$1k6mgIQp|LE8gO8&q8#I13YV`TO88aM|6uLGkez>UfAxY zTO5JeYjlgFE_;z~ahPS#S~Zq&bY+hd0!LKlqgxzB*-z;fhfQ`L-QrNmmeDN^kF0`j zaY$ry>Gn9)pKd>-`qOPY)t_!Vss41^L-nWIKB_<6;=sksbc=%(>$2c2j!rCO(OAYo ziT#TZI1sUebc=%zYoS{lZP;6Miz5tsg>G?FVgF0FIFhj6(Jc-g>~Xrq;ez?-7KaG- zQ at X`rf!#;9I1aF7bc?djD(DvFoz10NlyNqbZc(UNw$3ujGP|4*D8FnX-J;C0B)UZr zW$|>2Qpx(wc#ERQI?S|3SpWV at agx02(oE%VR>N9aDyUwD`wq=aSjE4u`c!TMy+LVK z{>g6X8Mv=G zm_155-(6O3&dq$tnVYlTaYbgGIX`=p{N3V(O}V1nsWjFvFxREzWjp1r&^HldgjAu# ziZO>z0Jm{4!y*Stkxh&_szF9^h+T|n)gY>gAemx}y`4k8Bgm>L;#3Dg%GeQvM4m;} zT~NsF{r&<9oOLO()4#UQzqaR1EIxP#HkAt+>r07moDx6BxWsuu3LZ&f)cOO>Z61qi>cQX$b7&-u at __Kk$Q2U9AjF+X7_7Sc{9+%Zsq`g$WanBTe)Uy^^OZDT84?Hloh_-AHr#MgjL zJ97%G3MsmCp5F{>Oy54q0ymFfKT at V~6P;vrsUIt(XJWup7k!>gQMVz0jaK{h5zG#^ z&|rmqexALs$4{C3&%UL1#C`vljwsZAYoaamVoaOX(|*<8k3G#P#xM=y<&Y#X=C}q~ z!67MPOuGhI!Xc?*Os57Z;gB>jrbmN_9Fi`^^l6aGI3!z)acaH#d=AMKW0EvT42R^2 zF)13P;|GGw5 at S*|$QK+^EXJg1kbe?n)lK5mbWJ*TBE(2K;FW0tl7a$~8Z99EEt-Hd zu80;8!AgDojumQzL at dBULaitcDMIZOZp$xN5f+D0ZZ`FYev*YNDd|Cyg6zOdSnDV2 z9em3nE(oyJPtsveAL5-J7W!j!Se*ugh5q?EOga=61Xx_B=-^5%DJ=J0I_w4w25bFN z9X3^i!CHSD!C>Wc;Q-0YT%NII9ut1XW(iu-%Uzy%deW|sI4r~EnXkjX)L>V*JY_oU zA0LHDUg`3b>)`EL(yLsaTXfj-8tg|dk6VX5ropoHMgviQaDZg4-fjS1rX|hO+YMkY z4K_<}H-P18uwuP|05*AmFwBr7PdO_;u`Ny)b4Ju;gCDWra!{Hp6G^5|C~(C?Q0$mL@*pd zZ-s7d#wckqc;FPqBGhcemaw&*k3;~tc;F*KiZ%rK&f;i91Jh5>hDW0vLykr)qZH~~ ze2+Lnvv7|f3wJSExc at X)RX0usfo$5CiN8#B4Py^~Xf7J)QBiBscg-m!_OfyqP_NjM(^8ci^KjE+*wERaw;7U6+tZ;r0Ghb!`k#z#va-kexN^)+pb=x z6gt&RcF!(t&uoHH;`FxI{5he-2V&>?Wk<*wSZo$69qV>2S)8 at c*C0IExKL at VY}zo_ zjtZih{61Pci&FhXDVp&X^bHrb!<_2pcH)8NZ$Hy^-dW{`FRxGhg=9d=3*}>CZQZf|Ev>mOC}$U_+^^th at 6R!z z&A$sJ!@rAWYs%ZmEVOG?cb at V}d%wC*KWJ21rnK{>RGKHLFr!q%D at +@K_Hb8ZqlPXM z`f&|QA0 at 7~EbS?X} zmPdAAZ^h8->rz6ubQRex^39-xK*}pzTGDsD`lb2gvc8h;qD$B$us$!8tz7R8} zDrNSrJ!Uznoc-np{u<)F at 0$H(c1WwtweP?%L>KQB_X at SY|9313wJGo>wX#pVL3=Kc z(M(_zzsQ0zp0n5~C5*rog1^WfD$ZH#ka8jM(;khdAC-B`p$U*mo`Sd^X~h2UhTdDs z+)4|mGn()TNEuH`Eym4v>r$YE$gV=4F at 4`h^c90H-7qKOeeURs=+*|c)cbVog+=zf z&?1dJtIl3RPLWf-8tX98yUuBnGrj8^Ch2l5+0oavWMj)*P>UHqXthXyS7QV2vBje+ zfPMX)?>PV1U!=Rp88C&7^_cUj8z0SwhD=hE-v+jz3)o~EcC#iZ?1sD0j9{bG<3Woq zak7UEqm_^-g>d-=bvO95+zR zm(^jKc|giJKdD6_c05gUp`E(*%`^y;BMyI at w;?aE#OAk3 z$@mr4>Gq7N-v3sCiJjn{%#}Fropu~v7b3b$vEtDWyp317*=h9J83#9R+ylSfZW4TG zK`Hm-RquTRH}C4+(4{J6yzdBP6nVzCFyk$7GY&Gsnir9oh|F-a_B##U!EF5<%!Ue% zMV3ONTV_X2CbLugvr~zO+7Q-NwkyqER at 432_^ylF*>BEJI0e3(cn|O!`q>ZYw0}3< z2kHJ*6K)!5hC!`I+fah11UzPSb&8tYpdD19FRX=Fr_oi)%_&uWJ6uw${Kb|k|8kpB z>4d6OD^sx_zn)~r0}ggMt@;I+QapLE$h<>ukqP=v=9e?zJ?6QqQ39|e{4RKfCl9s3 zY74>mx55-pg2(9%)u6KuR#`(E9<^OlwA6UTqS#nS^ce8I945&OA>+u%jHunjLe4vf%IV at cOU>t^ zrUJ?WD2s7EM;r|-6d2{+#?in=ffdk+I$AQJvPP#FU;;r8 at cA~ez$UFGJ_>9Gr0(XV zVgMaufWC>NV*wp&fWDHW;{Y8uBqMfW#4Z-tbw=z4q`r(LQt^O}H$XRWbON9g4A3ud zbRwV=hhzl9c`Er1vB04-;xHgp!AXq(^aum=^&CAC&?61d<2hOYv at j$iUFfGg-zgS2 zbw->9r1r-UDd at ZfqYTimaP)bAKFH_{hZWyfd0+^J&&Wm2lV$w at 1LVj0Q$s`j5vvrcCnycXQbVL z)VF3LbrR4g4bbm#^eI4}GC;q?(H(&97?P2nq18FRQ!MDz8R;}2bsHyj8qlW=&;=ab z1?VmV^u-+A4e0J686hwA`8{GmkIqPs0V(_{1fCt&ucf5_b$kfv-OABJN$;;YT9;m9 zMph6bC&YpiIwL0xNX_A-hLYYZIC?1Q9l_DM^cpk5(43jyAr^G#jC2@~+VcaE>KsCP zpXcbIq_>u%b?G%`WC=0SEf#d^jC322%HgDXhLGNI96glu_Vy84mtJE=4&kCZzgH~i z)fwqEAhm^)>eD26F!~o9txNG>^h%D_CE1vf5=x}Yv`{+ at o+IQscqK9VrC9K#&ghp0 zMaA)=zS6{fFq-ueS{M1j=zScmi at h zZcggN5aNH+*1%Ck}8Kg9Zn7&#>toYEOFn#sRBL!>%}5dWq#!;1e4XQIS^i1iQJ z6!N>of-apAqnW&dljFy|zH)d{sH at 4E(V!_vXD;eqTf8wNu(%qHrVI}^a?kI^jW at I)o5)=!9IwMB2|ApOA zv;SbUrF&S3|EeoW;*A;E)rE|FCl-9CGh#IR|F$b?_8*LXpleu(zqKn$;*A-ZN{pNo z3r^~c7|s4dSJdo37~Ot)ScyMyI!fY=8F}e6GIClhIIS~cH2XhtI%@VGjK1^quo7Q< zI!fY=8M&AkIU^RF(HSwC{eS3;n*9f(KkFP;;&*pONxU&5|I<0_wEtjdJU|37$XLlyB;JD&O>*XYx&}H|Cpegy;L5(ez}leo*GRaN$?E0C+*hY zHE6)d6t9*fVOyrKZEQvdw80UqU{gREufmNlgUl1l&BC?{vjN({(H1~k4A9?^HDI|F z&{jYT5omY^U6|xu97C7e#1%F)fiAZ}Qkwy#=Q*VqK*t!MYdJa=(6I*SJ2*NH&~ZcX zQ9yjy#T9nq!wyO929(BgO7Vb>H$Zcn#qtC|Cm5i)&0={Xpc9AS;|;U~EO&@29K?qM zk~$11{gP7}0q7A1Xo;go0(ztYdOk-BfEI?};~L__DXwrL9~DkW?lhp3$SIA2B%=(_ z$7!j*{5(LPXMp}YM~?>d=pp#{6B;CzCy6VPs6CP(X_5gYFQ=3Y=wt)*GL9Yt=rIQ9 zLXJKk(B}`q$3?_Pint<$_(*}IDF&2!$)vD+ETE0V=_p5!1N1lp^iGZ*59skj at PRf9 zWqGQ&B31H0(o{&AIw+~HONMcE`2;{sI2W}DP!|B|f^$*%fSL%XiH2p%7g_gM-_1CS z9wwX7zSv^@C)pQY;Pyq!P8f}vgTF;VaB27~(s@|Y$50Zi zQcAx*7xfmPKtm}#b}niopg=n*{bmqKuel1AoLNf^_Rn3V~f5g$4`;-CN$8X zaCM5MohUS=pr0)7G@#T>c7WxuA}Kv>fc_&#gGy4`Wq_{ZXi!N?yNBT84&tLnEbY;o zqsM^I3{D8vBc*2y&}keE3Q6f%1GJf=K_Mya9fFO|&;;P>6HEJ~pKvz%B2&%-LI>q* zfe2_Mr9YgDf^lIvXd|Wlk;M~AvMGB)fX-9#ApDRf#f8D&VI+CiS7PZ`dP{s|P?xD> zg;?IE3GZO^7>?Ejcrdz~*8YYBbI)nv+<1qp_e%!HiR%g);p{)FYk>K zW+OIAh>eg~8q(Pa84$XZ6FNSGFxz{F73SdCC}B2YqZwEIt`lPE37w4-285pDgxZG? z<_%|u73LqGjS^-fHf9hT9b##R&PIm;p|PA$C(5${`s|ruW%6bd2Um6s2J1^*~Aq0L_&#(eNsV7R{ zjo7rHoyK)cEIp>Pam;|wQCiuDC-K4Po!!F<{IlIr0&m2|gJ^$neJhrJtFvJ=kfQ{nxHx1^)4_D1kR(<0r(% zDY5jF&W6!MKD#SwA|H&N+%>Gg$9F{uyb&A6aKZ2D5=*;CqPuVaFrc)Xj0Zys{Bs=L zgFaXFH<=-iVElJJFKp>aP+@ z`-R#nk}bG{VIbp_Q0qkbj-1rb)QDd|`Y#O1|0ys3%OS>rg`LBW z1G$}1ua&}YrPSTbbyYIC>>xh`ooT4$APUKQR9FS8&7l~8$q!&sIy_D z1KiUwtU_PXG3+>SRY%k~V8liuvGJW)`kl^(kq+?nsbLlR=2OFt1AjafH4YfDQHycp zT_?rTlhip*;<#Wysq)mY8vXQB!wv)!Pely`Mtt;POn295vGlaw97amOp_9WZ^xIEH zDfENUzdac>@f)!r6B}p5(la_6MmoUFCx=z&GfxgX4vab(H4YfD at qK&bSRm9UpCj6} z7M#8J1aC*7DzPiFL)c~(wvEZyL*)(ZB@}#LkZm9zuw`Zg^d6430NP at Jex9SP!nV0q z)FLpE&>&$WbJ7 at kHNr!m(|t|IYdO^JhV~> z@=Z6xb2dB|!*kaw`KG;F^G&b3o^NXWOTOtoc+Q9C%i;NYcxF(>8&JmcJMv9UFXfwV zgXb)G9uLpa{-6G{^CyZ*2TvUO!IP7LA~oXViT8MVWN>o3+h5pWZ@%gpz^L~2Xp+7(00C#v4w|d7;qKL4!0Jaf-loG}r(uJRRl34=M4F7uNMi#fM at u~zceK=FcG0Q1 at r&4_o<|G$DZ5T5Kk+`l6 at 6y483%;z<|@A}!P{u5 z^3i#v?_n9O%6lLKyFPK?#L}O%n6-AdQkhi7!%Q8Nof!R0_sfcYg!KbcYJ$$p5B>e* zmlbjlAC}Pm2(B!l50yRMUR6#}PGy|r%#75SxfGZQU8KMeFKlKB2|3ACYn6Z2jr|LP%T$crY+=h2!Zitcbf2{6wBU_lri=T- zEm(+g7h=(A%tNad&#!9%oKE(D)7$_z5mVS`Tw{Oh_-ZPeU4(}POoV4*n z@^eiW{|NrT4#p3}Kl!0w9f(MUjVaM2boRqewlY_HZGxs_zk7K_WAnDm6MW1>@!HT))h~BLdla at Sc}{W~ zJKvshNZ4+>#@my>a)h_%*41_lT)cg6$fE2Ow#Onk5y7zpZtyl+=12+HUNKeTUg;fS zJ2Ycs#-7l1?lRm9PaEf5tm_tvW(XyuvfXwbmYDMs4o-Uh`U-2pquC=erP)BRf|mu^R`H&hDdLy9Bxjc1!4!(NzVpRG<>( zbE?{CQA?ay*@IZw{ZbP&i?Dr9Mq_AnWMH=|$i0^{>|7x0NKU1lj$q}Np^shm-qqaS zsHKeA=3=B}^ds6UO$1z7Im`Va?Clns#KB#nUfSEQYNDvQQ*&z`fXT6|5?d}dNiJm? zI#6 at FJ*vy?<}R(9qcWGm+Z*uIaY#XL_4~u#>c^pvvS*-qtGqqjU;Wpama#Fen%w|?0n$QJ83`pq`%n6b3K;JPVUB3Th8%Zzw1mtx)s*liMMC% z6Hns1TijHYGg5OWZr9w2+vRq5Msr|+rQFS)%OXz^FkFl%)7*l$ELpg?3D5W(eHD-L zIzq>E!LNcjIApI9-<8e-LOATenAu*%gEK@$0w)PQ`6hJO5@*&C at jZETWbAJkDKIWC zcCSlVbxgR2-vO04Cq_8M*37G7aB0`lyc+o25IH37Q}HGLV+CGW7%Q0Dc}G zVNbb6mzHK}Ciejk@^T%ff9uC zC?A+`mX#|f;iX84_&P3!!YY)*T(JaUa5D0H}}ZmTr-Lj|geI&KwzE at zqf=)@L(Yh| zK^YaEZ0P=U{K1P4_>=Jwlokq9u-BZmFDHg4XjB at b99=lFj^G{*u|pmu_O2qY=S`9Y z-9CpN2>tYTqQQH zx>oFv1R$SS?uOp{H|j&|F%!Pb%kgE_n$WLq1i_Y0B?z-)LmZYF$YSLO5OfS2aI~$Ybs<+g7H)Ek(OCv z7vGb1`pu!&!|}xgA4VGzJA~T%@!Bgqf^K54DmT7DRS7QC_0vJ|Pk-4T6$|z_qP!)2 zz|3*hv9(_f6duQyuE1hq3;7K!>?3FW3;Q*%-*OB_p}?>hHEVlFf9i~MzKXOc?lH^w zqpG^lMQLH5i={?or*Udu)BEq2VdU$?26-|%4TgJ1*1_(Rnxo*8O1sk3y$s-cm1ewJ z4}@mJ{UU(OOLt(J1Hl7F4t#syaN<6>v%5oSN9V$jVph7d`%8??ZTWwz{h>&(w z{M-ycjGvdDlywB|>~QDk{#Cml&;=jTa&1a zsY0PvHDu7Jv17IzxqPETH;_^ak81N@(91{ztM+6 zRHxdNPuRtf$jSNC-FYNJv;|)IKIXb8S0K!U*z=%gCxMh zB at o#114f_QjK9wu#$Vra^xICq at 6#`%-~IIa0{!lVU-lL#9WZlbFc%c8jfEvA`_-DA zZvh$u<@k1>rV0HXRk!#=3Q(ITFD_%(-T)2x2F9AjD7E7;Jna}5h`*Sqv^Vz0G=33l zb!^4a81&?KyYkc5%fG{PV=-NlK44?aT3bL%wWljDy+-h1#A6K9Ak?C*r2c&W)}vIv zR{CwA-g>AL=Y=C?0jm);#??bTIEYxB+Xir>)*eLvLZ#?e#@Etsy57Ur0fUO8k z_hdvfz8}%B?cs(EJ_Z?~WG_pTioMJ#P047M(u<3wBzS;20ycgtCJ$D at tv7(Tw&1Pd zdvkCu+;5lzvFd*Q2P$LRNjPr11|V(O#vTDoJ-iY$Hne{fRw3vA9ltH=^`b7 zau}d)$nNch4jiX-&DsW`_E%^IjZAS9qzK*~$NNgpGT|{g`&PRegCO*{g~vM3o>_}Q z2D~g^azY2HfIoY2vEchz3^d at Lv=-`(I8kwd;Ek2%-AV5>u(J~`JJ2VAe`gzY&!LdJ%krBd(Q?87N}&$nJ)_DouVXVq*Wn4BfQ;xw zShi5R2_2yykrOwjqfav*0u}mgA*sPy1n%FD*O3%gDJ0H&6bp32yBpeLddZFp3b_m<#cxZju-t}v_#pf(l3MoiMP zTzHH&57r(=V@}T!R{&_<$(gro9TN zcxb+o6=s;Zx{zz3_M)?@%Cn?Njw;26-41P8c7E%R9cYyx9wyfM4{w$P)LIG9-H1Xa z)IJLdt)D3~dlYwH at LhP2N7bCYQ@)+|C2HI99J*f@%LjxF)DzJ#ziyhcl_1TP=;@R_ zkq+WPowma7dx^KQlQ)uoD|S<*CzQYmV|K;L?X=z|yPtMLDKq>0zDH4*xIn5~Q4~Ou zR4Rry1VEprB$%VzrA{rzxR;02{mL`#WJ5{a at D+}*(gaOpU^UIjm8(pxd^Zl*d?^Add+3Tdv%IjxTb z_6lh-zq82`Lt{BLP)RfAus1s+=^a`Bm3JqNVhZsj%>y1>3bm}TJ=W!kMfcGG-{V-! z9B;FQ&FavGTRBY$AQ*-ebSOB%BA+Lsw~h zN|O|7i3o1f=CBdxa*N}LNgAz^j>s}!0?m38!73D*hU??%Xs)hpkOYN#d{$Te{@`2G zjx at _lBlu06;QJcr8>qs3=nQ|8nZ1dBlX-Q2zG=%p@=agD-}Haxo9f~3*YI}~{ze|q z&M>&^E1jsn*B9AymkYIM!>{Run;+oy=iV>bbKR0H>tM*5b+DkO_kJn9rWXPG0I)9~ zH%YvRt~~b%zI|~0+p_ETNF}*R z4=nC3Id5QbS0VnFi at T@)v&G#?Zt|%05P!AE_s%KA{nNj4 zyaF5gIv1AALN}$oSoM*;xDjh->_ua=7wr^aFV3{9mE>W9Qw=ZgE>JdSniX>umG~?{ zP2?Z1SD1%G;1^5}*xkjrptC1PNnDPDrD!D6UzVtUtcy14pU2;T;mPu&UAL3m5>k=8 zk9ZgUvg~RdNrWi0N5y5o0;3h;ANc)KWrc@1Jn2NQ&-5%<>eNWVmiF9X7FHvZ*nZerbGq| zPQ2W45bH>q=jCZ=s;R)s>wpzmX2e6yat|4 at LKnoWkT7i_8LUFW#)X8X3z3aw%|>Vv zRiXLph34}lG0ml{z#1?m%F;O_tPb;YWyjRd9NBJo);){QvaLpF!QdmYp9|Hw*s at hd zD09c~^6=wKj)aj!reZR?I8yQ>b$L(T5cVK+(60X=G(%!iyv%K)@3pm(fM^NnU;9J&WL at jm|&D3sehJA#Mj>J(Gtj0vPL#sCi`J`>h zS!|lYLy}j78OwD3haljSR;xACqfYK_SJx}WjZzMbGsKpmtlAlZl~cyV86r7L1o<4| zJtH$gHbY142q_}Os5M1L$XFevBLuHe<>j`rm5z{sI!Z at K;s at dg;pL*vi_VY<#2NAi z at 2(?yP)#0%O97<9N-sH$zN^c`5G1Lxz5glpQs2wnNN*ciY8sFHh^=$mv_2YYP1!U~ zPlDLcf3z~rmUYB*C$fe(TX422oh?My(PqY6HceY4lUx|wiKB&JYxnAP72|3t#BovfHj)%NAa|!Y zk{WR3!{2l0$Z;g4v&*H$_^a{;<@P0hAk^VtcKpcjh@=?tkT%NKGs`Iql{LN{Bic>( z3dChvle%yi7m*}yDq(pddKJYe+IVF|qAEz65J!;=SSp~WQ-~-J=oI=(Dtm20G$!*UqTVVpx~uNIID=p0)1nmC6t$<#pIiij-YJ|Tn?cLE*pGmM($j>UxO zMM{Quv_%QW!R(q)C_u?n92tH`1sD at rqZTNcGB=@jg&TTSXxXbmEv)dUMt6l;GCV;n z{hAp*WNFzfNPbnt=jDEfU957UW-;xE`u7%$=RoY=$HLt$59-k}v&<_-}_!!Y`h(bu#_MT2Y zWMIb0ckrRo$%kuI4<{e8G~?vU!-|NXk6=#xe8l)GE>bU2cz-VO_3?7iBvX(DNlHTW z_sPmxO7(?)i|-1_2utgxMB*QOMp!V8NHikGlF=ATybO%cF_8R-W7h4B z?AA)r8!5o=ixbOQ?Tz##BS2VzGy<9srqk)qRCO}mNMhD7-bhSmypjJr?O7l3?-5l( zN)S_dBgy#p at J8CaR(T^!ntOO7F}m9uNsxHJj_h^SGdDhpl812XvGo>5%6J!Z9dcOCfhImotUX+;^W#mQadr>?uFJ9g|C(C`h5U}Rs-jb?aB3bpl%y}kk3Xw;tS!~ymAPwk#4Q at s)d1QH zH3+frJxi+d3Su=V+W`7XABgi)n3ghk((5zZa3q3OIY%sPWr?#|S=2yUcn{rmtr9Nn z*^QM?t3tJV%Rsq%>qjGnq6&HtK(D~IR67UpgadvlMbIe~7>5K)1n=oUXjgnqF(1Fh zL%+PMs#IDdZII6*J2v0@kz7i_|@12u)sANJ8&PLR*yk=q%`hyTp at 8r*z{`CB4DWyL(gJ zAUZ;sZ>BmQ?S2jDeqDO8;tkN9IP#?JO1krSW!|tt)Z|uZZFn_<6^p6}?Z?I4 zcs^W-D;KC{DE2bo*0`EslDrT6!6|e#fh34R1xV`36^CdLi{N*rOrh z=9XvvwTCVGL!8Y8t1g(vPuJtO+dQ};U2!&tC8~9iXe*2mQ>iwk>tIIdK!p5Qz8O at Y z at PHZ6Ccda4@i359S>ZN0`4901vH8dqyYzA2qocrpw-IkgFr}lr(TV(>+4VRM_k4-B zb}^%<9Ja^?~ThY^2 at k)m{+3hN9)d0I#06j96~;Ba1+1L$hLCyF681y}g_ILHV?tUg$L(=a{FYVk)_8eSa1}ZIul>unx_a(k_7^(`KA*wr5^2#Q zQ0afdKk!|K&PjCUz?^2GfWYmATz`-eCz;RVJcGDc^-c+=3^(&Mp`n31jgRVSM0xTrp7J8l&zZsa(hmeffMO#H?iE32I=tVmU zxXcHNP9pX2&vawn2?1AXh##W at 8o9~`^T=g=ELzYIW>n0-a|$JAA{i)N(4e> zJ5>8Ym8|rwqDPzJCpH0gcV7vNbAqMqAV~8=yCk8VHG(=6qms~@l&&PSv09)omh06B z8p%GPP(`8Oo*!)sv?JfuxexaJN%T4735-R3Uki*`E;=lcmZRVv#mVte=`Cz?poLCD0iiOd{(V0ZnQN zga@>A<+I^|G%&-N1(qr`(U}DlfufbvXnNL7RS&Iis(Lu~B6Bzlcm#@~aVyt>2ckF& zjB5n#=sU=(f#t)n2-d3C*N6L<<<>5PJnfhVRPw&7eDLF}oK-#@=(`pBJmKsm#G68Z3XjKbhSG;`FpK99di at QY3T7zM^Wjm-k}X!AJ9Tyd zsf3)`&TM8 at i0DE=ogbbn6m=jwHAn<4P+O|hrvpDIRgRxA5{-o+)1a(Y2|LgQONv7& zDEse%lco0mrJ{5(>Wm*f2ymKDKdVQ~K+};4(Pt%UQJ8LE4kx((pLIyvgXx=4em*JY ziN#)t4$wc;W4{fN{yW5-Y>_r_tBYJ$+^H!-#^qved%98^XrV2w!zKEymegb;HZmWU z>iGr0+_f6{-fYgl(jmFfoo$)J&&l`skR$xyneU?zWxuM(;pOfI?g0X^sg!tj0Mx(J zQhhp0G>{$yIIVI(E0OYr#3LSHGvaqPak9VnQ`lDv-m~b}y6TTk-0O9Rvfu$?dV=ULy6 at a8N z9$w>ALAg64Z&9P2SuXH14E|y>f3carI3VueFVHTAfKb(to53o1QbYMIE0G?=vE>{T zx5~N8%f-9(?G%8AizKU+m-i!DnSu@?7lv0jQ0fIGpbE9c=#8}5JQz&#Yk6*A-UhdMcrR_a~K$@;*`=Zc0BVQ!A4K0a~- zr8qfUelJ0iO$5m@^{iEil6Xy&B)~dWC}7A*6;lUtctSK$B{f>Fb}9a|9S{umbi5|M zKKL0g46&D9?a>P&KqMR^P~Bv~ZxssW#FuVmm*NT-OBYdhTFU~GfrW?PWo-eSE{mKB zssa7j~qp(xvO73CUMoInd at tLRD zZ6h;hONa>UX&ai8Q+;Nj;%Sj%CFFn!qdRLrx@Ogq~6-V?iNc)lL1bKP6M1(OapKP6m>XhV+D{3B?UXDkEx@%=l zNk&7~5NQ^Q{1LQCckVu)%sm-jaDbW0E74W>7%K$uaQ&4#doV}h(@6;t at qxS&-Ya(v zhzafF<#iH`{iWtJJ4c_o82$oI!DVR5Ob6PgE{W-5_- zPt8Q6pvm|0c?AOi=P5U+7wWd5;hB&r+R2kN>q(mRB+Yt~W<5!>o=mgvKi%y6Xem~4 zRWvjjOh#R3kCz9QsiOA?E(!x3%e-9N!uG_3cI8khzb)Oe2lt=4dgu!rwV!V<%k5}$fpdeq>ae4oO{?JHnJ at pdo8!~j2U>SNuJ5`AK z;92}1F()rC6%E#P43SBr8skY9XPYzs6JrI-ZK${lm(VF9${M4@@ff?T7d^SIJf196vvnj&6d zIZi=oJ5iS7mRc81Tq-pT! z{Qc(551s!7exI^V#hw<@AhHcKzH1)XIFg`Nr*@G!eZPir!d2Gv^o?eLg at H$KU#{Rf zO(O2P&*)<{XqM1h)EVhbXUJkDn}Z)PLv=a?)_!5_h9f=wS>r8Yksx zUVY`t at sw6k%L}};a^C1sX~^bOB20yxtS(l*zLZz!rU6zcj$F07k(M6iC*>7*8(Cpy z0m(c)pDX3LFeNZ6o5^aWC$b`0M_|@LB&&%kD`eATvW?I~_YLh2-SU&_C?;wvOwE)Z zqg;mDW_;+pT3&t%;CS2hPH$1q*)~iHI at iEoEmxJ>qKf97idf!#JpylYDgL6Yr44tjb-b|I^N;w zbTQqm&{ZSHK~JPFu3$q_wWgk21oW3DDFnv2I at 81_q3DgZNKfUL76El=pbq0-_oPg6 zvJ`sMscKC_sSemu`QF-Eax16Mb}+;+VF!$pB3^;xbc5OULZUg4-wkgN5E%1Td!X;io-r?uT=YtZ{s?!qgnmGeMf zU)c{DPcxbg($yvBlpjn)7DX5IhlCWpiTkRK%TKygVsmR>{Q7 zuXKQ2Ef at tGD>TcYB8hi at 8+kSGgnqR6e=`MtW%0yNOycD&=wj}vk}d2amvw!CFIkLZxz(VF2X}O-USXNj<0~0)-LJBzxGw4a zDr*p}qs;cCLfxdS7^GnRf4KT}6R!~q_JK>hCLP46Pw- at Oklc#G+!^r`W(4JRc#y&C>%%YVUy>MNj9Nc4=ygw+ zlqGfH;9~EL-y*krh1Y2SA9oT at lk}p*rvo%ayz>ZWe6~P&69r7uG{-`BU9K~F{xbU0 zdvalP?m0D6w`w%6T*0G)T=^hBdgpTJj8iqGTf at 44A7ab7(ndKOR at 7!{ze3azpww^h znj3y_u%pOK#0d_TYctkIyaJu#oy_TeX?p;@NQ!f{x==`?rsMP8?sr;{uD+EEG*2|D zK;2xt6lg0lD-^V=Z5Thgi#bf+>;58DNxZJel&(IfUMs7PDer=U8ezRtUg>e%2FV!D zraSiceE*_s^>0y^f>$CifJt2tWRe at GF<3N&EL43#ca}<&UV7KzAoa<8*%Th<_!K(0 z$PyFGfZo#U?iFQ1Jd0k{J6=;=Aof!UP{6NuJX>90@~0A at z-J$|9IJz0i)PAb{zn=V zqq{yz((EpFOxB|w409~)8RZBRSCF&$smb>KBntCn%_LkOawJ%&5; zgK~8TE;3Vd(MJYMk2`(1^w!?5Fs23&?mbVBODC5YNd@>O at iN7hXgF1gtmvbq>N#=f zFdAQVSn(C6V!L{oFYZAKHK7c|Stjfibr4#vyi~vi1^ax6B=iX=mH9r3!etubGUjy? zOv>|qFiRBiTt9kf9keMrj}Epz7$;q;nk3>Dd^5={(8(7lX38r;d$E>eb&9mbK4xq= z>NsOTFVL9 at agZV2cs`&YvVv$EkTe1leD5ZoT%a>`8D%(i9*IIFR&FWrF>&-U5m{hP zQGb$wGj*QGpkStkxP}c?L4{I*$(Fg&&Ja|fBtebz+ERrAU+ZtXNEYOKAk`&7G$>tQ zLjtO9(mL at Y4#nk_Jr_T-kq at v!rl$M~UAIpi$SbSJ&=k}B!qi$Pkx9A}+R#2`Tqhqo z%|C++N{5r6HEkw{e at DR+Q9pZB5 z#*{V)dWlabS}=lka$TH1c|*_`LLZ34<0P8Z{jL-H29%S|0+vF6l#&Tx^vUf~XV6c) zha(yZ#zG+2pOm3vXnV%MG;ML#6IMna&?TlhirUj0GcZE2)Rx{0*261-nMMt37 at CxN zs6~l=+7!)BIkE%J+!q)>7tC z)dRwg?s(s;B8^@ZHS|jK$HhLF at uU%({AMxOK<)TC;g!hDQShGXN3TBBh0C at coq0-m z4ozC!eMKj6jlg2d%dKXqFZer}LKGV?zDCk+r_|HU<-n&L7-Xo4yMwAH*9SUg88015 z>vxyqeq2skBM(Kl&N360$O5_-96(<(B7QiM%~j=da2VUnE8*DT?V5hH at F8vnfHM*yH9YD2`JnRX?^9sy?HSXu+=l#kH07I)BLGx~1 zm1Ruq-n*f)sen!QP}6n2gl#~u^f_AKqW<)VlPaI9<$m&_6KN6R7|PA)N9(E6xFk(3 zva59rHO?Ob+PkZx4>v=X{_6x}8799AGY6Dz at ta{8wbHA&VM5>Tu3NRXb>SS1*NxIQ zcJ;4C2I9B6OSN(;LqNf=w8`(|>V}-`6v|C|h=EqMHcNh}T7%_PFaQjuK3 at 4cGo9X~ zym^i0Hq0y12BKwYxIiMhYN04v z=b#O$ucRa&)>73$-|tQVrOvK4*y#-rN#lfy5Q=?-NO*6rqmS{@KVfiu%<_4>jpZ&N zL4Y8)O9(-3fW#A*cZoZPWmJIpN57lI=e_hbq1X@&EX~I$y%S=zi11?&rw?Yfw z at uMPzmtXm*yw-$|9szyAlmx<5BwUZ=svgO(T$$v($~HvZmo@^OeExhXNHB}M@@##q zlzyv^aWLry0VDLssNilvVQK^Vsl31R>e!1St$6l4IerYTmbV2z;-=AknHyKRrBs`o zV)uff99!Y39>8%uwQ^%r$g at nOP0ZGcTp}~TeT?*~ zwDMC~+F`upeZ&ey)@{(@@s<;DmtsYSSlGxCXIZdBT&X5l021h|0;cvWULI}`aq0rC zggsAo246egb#r=|ts||H9l-bd at 3J}Zn(|gOMin4WOk0_ab2|Y^YcN0AX%BOnEN)91C80O*7GpEWaSn}=Y!}8>d5N~l#6ov- zu2T&N3PlFYit~W5MGXrL6?q>&`a at C|UM17RO6j#tk(Z0S51+?qt at 6szfgElZ7G>Yf5K9-k3&nzQW^vc10N!Kz4nP9%c$8WEvD|U>E`IOR!5KP~1!@C;Q z)DKn!0T;FehtP}hZ2NhO-X4P%TKWfi3`DKLbP1)lM%Bp0&e3;e(UH9jweG}WzeA$O zeR5^R7>(kvi2I@$fR&cun{piyIeWH;{|S_k(f06L;fP zsrKZ7QPJ5&>G&~kuzT#33$eQ!uMvQji-b6t=w~BV89gzVn24maJ-}3TN3tP!`ddXW;3QuQnA5cI%%%~`G-8s3!6XY?B-vD~= zA+=k4+acUfL$sb)+`NUYglpmgArW-uDOTvMD};&jg?2oImmFw`^l6Jjs_i%8tDtOm z$j>^xTe)NfG at G6f(BpM$y>gcZ*`MH!_b5QDU27NFn7s!GjxVNPH+pUXBVu@^B&Y*- zLXM`-9#mCNUw}txyK?WgHsCs3)B)=UFZUHA5 at CpGtTeG#Q%%HuC&M4yfsS)ybBo%2 zXH2IYB#y9n-FdR3y?u5==l~{-c7We_T~uW3eZcB>fNVEV)(Y`GKFjCluoxGv>Bc<}_e0#dm#UD_#D5b2JTS2~Og{AkYuSOF9; z|L^_jHF$YC&^;FE{@H^bZqwKM8G78?-_vcn;bXUHoibaoIvag-$N!7lG=QG|=)Xw& zs;h at n^o#DABlrKOQ*=+WipXC*QWF{UQ?lou^uN%A!9|b3Me}Nbt0lWUgjbTu;gyv$ zM+vWYu6lg2`}af`|pP zP0W<`{!P6&cx^{koflf=7kdRiOJLf8ZrSqg8pvv5-d(^PQ~tZ0H#(v!-t at vV5ShsB}Fj(3b^!RA8Ba6~?5m&IC1O{o(L#wVRtd_wnRamVc zVGap%NtjQ);_mB{m*X|ib4Z*j8T22CERKF}i7e-~9=)$!34_(B}28#^O9M~!7 zuWtk2x%koRZgnx6HGvypGT|Ekna%)9TL5J7Q=SnN(x^roZ za43LIf~t6a>>iw-t6+(=dnFOwlZfghpyadZEX at j!Stc;yYS-FJfdieT6nn!;Q>t37CMC}6S&Fz2b?%rEoZjc&44 at xcon(< zeGzd7>oSBcyM>Obdxh>?l+Ad(I`1iIN(z=^BN&9a1z`4pWezJ8D4QYCB+;%Gx0qr| z2)zR9Ds*=M73^jKYwAK#O#H$Sx`B-dI0|l3nE|BaU}ed>PE}Ma*%&Azmpf;1ow}$# zpy-yel_=-p+lpXsuo{F&!hSX+y0;y9a14k0CVGDf&Uv7x%=*x=` zb7?i54PB`6$A2<%)1Rmj-%{bY;8JiAS*?GAawlWF27MVhSd#S~k!*3A#J6^1WkvjC zJlKs@$T{rjKsifUuUrho)Fi)PdPFR?q4fTcJW|eKlFD;jWD0X zC3o-$3i>3W(M*M0KTjdo#J||mH?Fz$qRS3JJq*PfvMo;Sb0%80JEQBV^gMFWy=V|E z-HGqE=_NZ={_i(wK5CD#XxJVN zYRD^r0UH)+`<+MvEwb+KRByq*Zdbmj+u}l;@G9r|uN&v1`pNqE- at a>XRxH3$fM$TJ z0Hpv00N(=yUt^PeGcK`NHkX*^F%UNhzzBd1 at Zu_)^$4I2z(JY+;AN->;0nM!02<&e zfYB8;YY4yufEfUD0ipqx1FQx38Q?g;C4gptR{(u~XS4R*Vzaga?0`D5;Wrsz0l+MP zi2%a at 3;^EVWV8MTxCw9`U?0G at 080U)00IG~0gM0`1i%I8yuoHY2DlAS2Cx>|SPeh{ zL;=hNm6} zZ-5+tuK|7mCI6TqY%Xba#0 z5DbtAum<2efPDa!09ODS0saPf1;7D(`T|%0OaO4X!Hi*-axDFT{_X(w04HIL_W^7G z$Ol*k5DTyXz#Cu+z$k!00D1tOQ08xd+W?mUP6PZ3 at Et$_KsG=!z{1~|w#GrfT>u8v zvH!)Z9)&Kf8E0Hr<8HgK_AGW~jgNFyr|lRtgZ0b`j9AF?@jor=RX+HOHAVxpm$6yx z``9eEG+{U;bdO6DMp7whnfy^!>7y~9Pk3r at oG`;T+9NJesElRuVg#h7#wEx6E1rpn zOO8&22tjfbKTSx9(vs8pR#8x=GQL-&GR`YGj+)Rj!FK$F at wmZqAwZHaJv}@|7#5MT zj1{HAG%S*|iuFcA%RT;N#R#dew3HMoEH*)ysr)-VRTvo;o){LLk{BgS3rh{BVp&X) zu=LoJG%8X=vD^Z at +`Yp*eCGrPD4+f2`p%r|>Jz|H{_W=L^9fS5BlpVaCH~V4Pg0sy9RoD&0u&wXs!UC zy^__NRg;W4D z2p%NA9}IyjD_WEsN$O2bq4?oTq4MyEL?M)k6(%OyO&A}Qn8 at -VP4cM}J~Lu`)rj#& zTBVQVTl0l!X(?%Zn`KtZSOG#RBqc2Ym{ZNuqel14fVc=LugH{S at 03W=rB9{1rp1Vo zgvnI;$BB^UE=(r`WQsEM821ql*tt(9!askJFfG$7nG&W&herxWdHD&`(&N%8oIt%= zb4y`n7NLJ~r0`SKrKhK_0Ei}$vPZSB6M^=O=E|H2$PAB;@ zy;G87!aUMal7ds>qWq{djDw6}9w})_;S`exNF3%Do|Y~Q6s6*bV_et_s3wZkOa6BA zP_jqZ9AO6h?HdsfV;TmmE6YGunKsbUg+~kGNz)Vt9s{!UE!w0RQeb12WUY z7!F#>KR`jlvX zk}wH4duVrGs8}ICHBD$8*K at 8aF=tr8P>=9Pc=E{J?M4H8^eCw+G|DP!G(#&YE=kB& z4l~Qv#)j_`9wp?%^qQii$@tVv)&z(rD}Y-{YNj$lRYslWyHuE#kp at zU$Xqz}UESen{N%@U$o>2&7Vx%qpD^gv?A4rST(El2S!b^LV~nVq9bbe~xe&MI=`W z&@ovge$QJJZPE>v20a*U9bN-|kRfxti!{VyC) zjwtyJ39hV)#hR0%;=5k8tMNr*sBj*y)LoPXmUj0qO}In^;vK|WMr<6cKpElbWL*De zHL7}`d|Y=Gg#RfVS>;MO9tI;3q{&C!PvMKwg;Q8T$;xQugdYZ at F&8G|QlV8kvd%ER zwTO?AR_WF%o=i-M!97B(j0hI%qwFl3i8lPX!Wh2$3_cNiQ}|zy!l72_&b{YIx)8=k zn8{yCq@#OWdTL^LCXouNej&|~)omuI>zpmjBsGS9a=tO at 5#VHC4G(vcuukML1{+hO*pClBWnCx-V#jar-=Ab zDay_YlaS`I;Y(q;7ez!`y=A&K1lF3=0Yn%vHsC`?|S$hxxd=d3wzeu>Re at Xh0j3k^k%<@>Ta@ zp%%HyQsea)F at XH&LE`ukB8p-d>Z948p_=`OLmI3s$~u`Ur$E<0uE5gMy`;}$u&@L9 z3UXSxo^_A+!XApAwR#2uzKO!{bRkR{XddPd2<9~9Dw6uIp5W@}l^&EXOmj_kjY^73 zR>?;A?bgc(6Yyc$EJYn0mXj1ROrru&ixVspg07}g`;n5cvOtUBC{*L3kqqe+&Y5BS zm=vgNt}qq26NnoHLK35q&QsK}FpmgNjgLT0qMMH(x3HV1{}s7MD4 zYCI!^Ju8L$Jz0P(co^49v_NckoN|IQ`To5;_lQ?5>B at F`F8`!I|9{L|^|*XAa}nPj z;;6U&qnv-PX+m6lp*`h8MtCw=bQ${S^_1 at XXwXV~FV)j~%n4YgqvO(&Sggq2@(F|% zQAt=tpBc{&Pm94t1kpLkLU5q zU;d~xv}#5(x}z_c8A+fydL)L&D0NFvei?NacpOXMyk%GgdJOtc3Q=giLBk_6nyd{f z9rsiDBS~WSToxrSk4yb%b;j&0l^v+A01K-0&;QUpS#yQqQJFmiGnt#cG@}SurkMr1 zS9zcx%yGU~^hYDQG)|a-lOi$}^$?gsnV6Lf=tt95NP#SiNgoH=9kw?E7(k_!eL at 4v z=+?bvfN~6reOeg9wPC2crKKdQLnx)(2{x>)t&`H6kQccJxBd_ijoIZe=8Yuwo%K1t`Bj`-9`yCP*fH%4unkbl?cmy`E0hsbWVW7x~Ffi;UyETU{65N?Q{1^YvEEsWWeKW`D>ttWPM` z+x2!&@ub9}qcd*Tp1JGtrgZ-wiH#FP3m*us8Q#7(-}(A)`)!&=Okp+q=lC~V>>plt zuDIj)(BbEg1#j7S`WkQ7*^}E&vPW_AwZe`z8B|-!^pAYCBIWZw-m&w38ysHYY#m+l zt?Rv|+Dqy|-_O8}*+wE?iq<^l}SvK(vi??=&! zCp*#i?~`TH75S&$KNx&J!pr)O>B|*2z7~4ld^a!rsLxgZ;wcoXbmt?RGdEp#J($(7 zvC%o{{Pkbnb=YORW6LyqO8 at O5uSpW5CUe%0tr^P-~KrqRQS>JA^@(@-&|$Q-ufi=UTxj2)9sDqc`-U^{X$q; zt7o0tXtMm|ql06QeCc3bV(`P-`tJea)H!zmdvPnbPkz|BvM=P52ZX-6;A*XX0zCj2JuU_|E)MMAjXT4MiY zkMwptt2b;26m#ZO9 at BIT9}%ALpO{~88f*||M*X94XVr^Xe}sgV_TE8*w%dD>InM at RRPvxITsS61RWV! zYj!UPuG!@3%PnZS=yj&@dI8<`_Ht9l9|pd~`+c$x7O%AyZ at Xqu^p$_#%2~$4n*wg6 zb}akOwJkiT;ox|a$HkKyii<2Z<%+fD7n!d%+spdl?py1_-(R-h8ycGN*dj4e at nE{^ z&22^te*f7rcjF(X+rQ>}9NitBvA68khxGHm>R!^8;^r#h(F=F>9SjYXZ})H?btNGs z?nCO*g9)~dZ41Wm$LZ?mCplR3eQEFU;HXY$^^(BUr#8Zbj at K{8oGGca{aLimLNalO z&bRMMw+}d7m}`{Tyw}R1?dViR=F9XlPdYx!{DSM$G0pR|d^6kKvm<0*S^HL2TLj+K zC@|gNa>l4oOb`FHvdQ6`;e{Oz-W_L#ezSX%-qlTo{d8GZ7JAw?2&55jlP?84%m at rU zbJ{d<$Ijc+3-dP{ZCdA7)X>~#@0FVRw-2AJzx?)}g$)sDgCA!mG#3ZDY|r(bKd-M* z|AE6zd3RDBEPrqv?z}tUgYfZ!$1ALKFNZ`q)Xmv>aGl1Z?FD8-uk5y4{GoKrp@)_S zp4Cl1ZY}P+J at KgSn%^uvYyUP4s2lB({Vp~`_~=#U^v_RtTG~_Qx`QW;>C1Uh8Zi4< zq37JxW?`mnTlV6vmyiECSNWl9#k#s%&O0t&d23%FKBKel`(=TpM;wK__slL5JL&B$ z8dm$ZSU3OjL1W+0wlJf_4v*ibHzj>-R7tt at UGS1U-1YB@)WnJ$*Nn!Q4fdP0A6u`z zP|Vtun`>S=sK9l}7iSj47SS1QO-+dlhWJ{WhGp9uY_&EYdEbIHtuL$SRDi8`$F~s& zrPl+Bzw3XY<9p-3I6tCkL4Lh zLnG%jyuHkO{ILE?@s&4)xeYC|`ffU;KfJKyV(N|`C9Y?3Jwk_T>LfZ0IzQdiHqXdt z)QlqE7|p$b+2wCDgH~OR at c!(A!>UCc!;600ZFKD3CewZ9tiV4P*!sTT5)skR7?62& zfbT=E;Ow`48?76 at ylHVIqF+Iw_1rU?Ca$B;d{)=AL;K0g>_rDEg)@`ac_x0oBS1vk z_nop=M|XI9pe1*#aC)EC%-x%Id6s??ZNBc8kz)$Zwv=9e at l#=)JfitS`S7;KO=lmL zn!K;uZ8%+AFe3Zty6LAZ>ry*SFUL7~Jf5*UJ)WP%hk%PJ? z+qd`q$?nSZg0v5oc!4=H4{Arp=vFK2_+)cAht2k$pZC>__8sdHJ={q zvH1PyC3 at 3FbyzI1u3CC*-1is%8GqpC$)A at OexLgKuX#%j&L5J##qM63h1L3uvA+IG z)1D8Y1V7voExRYl_AQycvOm`_YiPu^6~9n9nd^tlSaxX#XZeRq)n6VSUz+%pdv;Ru zTZa_cw{MdZ*Aypw at gyUjJ=ZpNlEce5?#e?E(@m2iqkkJ4?q4BWe6!(K;U8zCqE2fL zi!O|7iQ!*v at Eq`ysn?v(0%m85*3Eh!+3b5+*J93hCl+|`x?ki|^!<5{L+#o#U(In5 zR9LQdcc1XPYx+E%%b3SrGX{Sxb at PjT9vH*63z}9c3emlNBKYg_&VV!frp$e0vcm6H zc9}oz_-Mg{0R9(io<`3<^3^Z%Ca#l*YQ7u2aDgCYQPSrJ!g9L;;$_ng%lb>A} z_jmirejjS;ufN}xxVdYuc93G6 at u0Wn%NyU#IKSYKTDdW+mAh{ANtSzKW9(A z*JzN?&=$S-c1dH~%~eOOZ*hK!sI$Ae<9dAR;~SxaEbEQC7F`&*Ve9$qF?XuHT+C{& z1cy|;=hZhVHqw2{_Z;%My#2yAFjBP_pZC$PrF7h{xFxOmeb9~aYu2aOS6wz8 zT9@%Y>D%!$#(p<&lx+RhX}@mzEih{Hi@%3$ypYqfp|hrR`?Ukv+cx!c*!olE+aE1c zii`SbWo(&s#`cG->o32znItLH37h@(qKAfS{o59~Kv^?di|a=Txb28n)goql51`O%#_Ub;>BY2SwxJAd3<_H$kO z`QpC at Y9BA#?NTE7ef0^0yT2cGI>I{^!Sgy2B$OVG9oBFr%+vI=_N#!Cwp-VoI$qFR zDsHhjduP#tb5AE0mErss#+06vUew+9>`-yvkj)X_OlWVOd at n4)>Xbvnk8PulUnub9 zW<|A}P0{#Dqv7Pa+q3RB#=o%3c+e7T964`$$UwihHoIt(?Z$7Hbnc&VvHZ&i2X@!Q zxN*}&BT}yZp1ShDMpLss*6&XIGJRW}*;ga!YlCKdlm7F5e)ZwnnajD;4o%qc#l^K| z#W7BLb*!(B#yR+XZV>il^P~3pd0%b*)A{;WYlO#JrrclP`^~lKqwF%)7`OiYN5;Il zhK)~MV$b<^{?s|P{rvXLo?~o=E$|K5_UKiL*UI(We`>OJyWBD>f1fm`Zu_LMCx#bZ zFx#|!$I3Ay2hRL(dIjH={oOYm#;Z~lwU0kJIpSokwi2)Xm=bzl$G4+9|civx>*IRP3C-#f|sbe$mg&C*KM78F|WRl#5nLb=%=zcIF#c3_5&w)yjq#$92o< z$98;{yk7J52&d?8zZd6E|9sukdFw|9E_Od|tJ7)lV2{s`)7PH=`sBfPU6PaIJz at s@ z5Xep)`Q(ge`;z9*y=!f9-rNoPOAxtr$Ml3ZHR2lsV(lx^cm@Nt&23Ld9eLybZCG&Y>M6GKrigXF+5I@#?lW%18pEVt zrxgG4(B*8!n)h0tkMAO5B0mE zUE?hlZF-&QIL3GLrtP6Go)7<1YhZ%U;_QZh)?SbJOJ33(Hg~OVfZ0XR_ zy1#87)!x?I!m=cEl*jJ~?7&zdh!P!DT( zzc(3wx2J6X7>_;!9fmL6l_QF-ZZy_dzPRh)wX`2<(=QEs{!7TrO=fL-9S?lCvZ#+h z`zyMb0?yt3UM{PCbL{J%1o{z1?E`hY(6R(c9-}{?aK_9{6>6-ji;xkLv zwfxcV)xs}6%$Io;O$&NHRC{%zd-$}Q`>sl>ukD?j?clodcIb$z-ov=s$Sid{kks3|FgY^ zuPnc6Ky3&=75!XWtC{#_b!;|0GYTKKMc4ndPSW{-sqr1($Rc-5+7`8Or_tT~37Pj! z{?c+wHe_>sQ@(DA_t at +sE6)CP(pu-+bA#6nK4Bacf0+N`<*6l}xn-`+gYMkSO1j at F z at 3>j)FTRmi(=V|oI4WUJ`G<%%%L|0HPfRox`bKIeHofIJM;3Ao|8Yv at U-XVMUUX}* zYwOQ3OVXxlwqBpjxjD1mFz>@Iz2byP#e3e)I9il=_e|~W{iSbQCNw7gA$YJ*bnmv| zwcoBg&mYlbv){j&HRWQ1f6lqO at cu)OcN7O7J3su|>5W at Xp54V8#Xh+$Oe>#TZP0Y| zh`!A7^OO}|&5QN!QxQJ+w~}aU=cV^tzty&?VXx_j0>G%7M%8E<%oo8)Z0E-G>Jb at sre$uj&f4 at JKzarxP;0LC6ti8UzvEt>so8Cg7 zqv7+W6#HM at S<0erp0Rl}>%lHp=f;f{O3MB at 38xZD{B3;mP{SVcHLK|Z){v^z+V#*TWrNo$vbu``ljyH at Yd~%n%@|W zZmKOhTvs%#reV+V`Ny0Gj6ZI;>crWFPUWW)4?I07=6`?gSczuIBLnJ4{r7+0n(6ps zea0cq-4Ukg_xg+fh}7 at 9A<8M&Fe!f8^7sXNT8*yhuh&)lsK+`uGD~OMk#^pC_pi7+ z>xXE(h>g>(?0Ov$5}G57xjZn at eo1nI_Fr8$&6i4UjBPQ#vwT6!{aIJuoO+P5wyf>V zfD>hIix028b^G>C`lsvbvmF{M&-*@jG57kJnCHKihQv%S*1qp~)P8oO;n+Ke^vu2O zHD|qYev48=dCis75Cas z=-+)Xbj^+Wo6m1Pnh|^dSm$SV#L275`v3mw)QB%q4re?xJ25jOpS$3(f)}3}t?hKF zkB0ujZ-mA)!V?rX`X^o!?9h9(tiiDU*&L2I&{6YPiW$cFI`el==4A%a%K|W#Rx~b-3QvvsS+}b|FEHA+G1v0vueY22vHPe8zie+t_;dQ=#J}a;gIye!~SJ;sLs)+ zsewy65`;Eq#=Ly}vu$OG#A2Q3Tb&&f2W&5WXOvrb+G=le=G3EY4(Ts574fuZnd=4f zta;62rnYDLYRMw9-79^qzq%V}QN6*mK%>y;jLWaXY4JISrb>q$7Yv7<>G0OuwELTW zg`2J}yu#8IG}wA3zm1S)JPf#W`b=ox&K-%S`GwPOuiIp_xw)apujb0$K2ILLt^eok z<@IS14GR-89}jj3EN-6fo4dWgQQvty)8PXx9a8T&4|n}R_#t8UipL8chg{aRnp5Wx zrLpedPP2mTkL-3|89Ju)!{P&$4-XxmUiWN!U$ONX-J^-Mo|eDW1(^Q*F56 at DBVk7D z=hHJ^*;{&^7_4hfar%y#G&`X5#az$AW0}I{)Wz9twtqc-+12%-^4zVubt|r1-r+1R zuz&mgI-N5|N&}be*)4Q*5*N)LRe4*4lH+P9^!Jya$XTEUDpoylUEX>!41l?1V+( zo~^dc33+4M##~Cse0n3*bAM;3dCEhNG2^3~?H{hZptA$a|45&g!eQ*AFaI>(TltGk z?z))K+jop;y>Rg4hvw~XZoj-T9afIBusl3T$MpG- zF&-0iY%|h5Qy(7pPpJE6xrf+3GW2N1<+lxU>K{Jly}43+rKKUa at X)5dvq}nw>;JeT z^(?li8{8X)6b7GGRlkbEt-)XxK}eM^KH3z#N}1194>rTG`wTcF{9l- z?lawV at 6SM%`Fmg61q~4qTdrmXGx~gtEN)sC7WA9A>CD{E&d}?$ zcQn;4%6|F(vG*QeO*CKM at X!PlkYGWu1x3LEA|N(Y5^88cKtM$#K!8Xfn1pJhND)!0 zfQ=$eiik>81nixrVn+}QcI*xHJG)6Jx$oQie?8ClzR&wz at 3-sm%x})jnRd?X>@wMX zWlBGNh-sGO7hsn?XOV(l&s1s2A}Lk-b%bT~S!snKj}z+5^7E3$d!CG&srLR#UFXY| z9XX9ZJKXL(eLHn at UDrw3!j``2agocGB^}-D-=bQ}xH9G|`Kig`)jxwm at 6&xM&uw1y z at r|AI{4Zt;0&Aqpj^rq0^~No`s*|Gn6Z_K`5;?tYzS!0qexfGzDhmOVT2Vrw+S|FmrfaOeG}X<@a!R(^2IAA*Q&dzx zjF}l+p+4()$K)A(t|sbBhp*RIKjGu-V}WNhKV952Xa0dh{(E*bu6KI&g)?bo8T-D@ z?x2)u69Si0XK at wZu>)@IHQv1Ke()BHD(WU#sj(ZI-Bd!txOu_kNhzV?*_St*zxUci%C~XtPQ at U7w#?PA|B1 z!^7ibx91eG<6fPN9cH(#5GiAF6fNu~Tbm~Zgit%&`>ZEOU$I5{~>BJ#Zp3XGf9zW6kowv;j9Z at gGfV!m))$P)DUmN3X7Zsnd z**N;q^7_p;S3O$Tvzlo4aHZ$#Xs5iGBWqqJ={nE&A?Cs|UbXhn9N(^a`)BI!Yj=XzxZXZK-|=qWHo1FCyBBt>|5W$zSl0FjpH$lJ z&$oDT%SYyRdy(hc8*gt{-PAZ5-r|-g-kRN{bN#9Rx;9niHRoJ@$)DYqs&@YF%*_|Z z8Bk6;I$S-oOaI5I>k$VU2|c^6SRFoiIpJK^#Y-E`Um8JpchyLedo9}6u(|QNa+7GS zM$+LlgGArHpyXL(&6MZrN@)d4_oaK-m+YGI;(cmo*tx8_3tuxgA8OvWU{u=v?;$xE zl`PfWK at y|(&OKqi=R at nJ9oyz<#apbE+$r1TlF+=J5f`@q)pqiid)ve*5wYi|Rz~je zh>dWPYY3ZE{xtml-PWxsSM8&g7r4hLj$0IclPz2Hs3rR#@pyW%r+8CIp5M2!m%$qk z&rq;9#41%NJ#>Cr;k)p01v)S1p;)Opd1r7vz*s66~8!7bf!en+qNG at rHi_upDjd#*zL?ItN|9P4DK z$1RZ<5%czjn)mB&Kj?fIq~qi+?_i_knAMZ7_5Hhi)@X9+*YyuKG+y+&PF|QT}5>@Fyx#7wjxidj#K38N%9^f4DzCaVdFyl^5wxtm(<5S=D z--&NLZ8kgHoj+c#R?VtP!azN*{O$P(GO at Yg_sW$QdfnPGt1UPw#c%S*#nZotMea%T zOq#PSc1DWR>k1=Rdzr72b0=9Hd|2?V`S`Eohp$XDYqr_%RrGqL<}bRw*X+b4%Q+qQ zzJ+PI8$Vm&vn+ex^~ej~PU(3ohQy6zKVCEcigTAunYI0IgU>w~)5^BTa>mYoJ61fx z;A`Ddwf!p3C#&vW5lq_NdF!x_bNS`hE2|c-c+%=(YO}fg_ba8FZi`izcVkSXFKR!3 z=D%}ig!=2u8;Q%m9f^4Cuy&Et+(m^6(vg#O{GQ52pOUIvRN#Bkpes+JFZz at sWyYMt zpRCQbrv!e8%Os>_%&HG2rr((u{PB`Sqgk0|+fR|kbtKRHFKI3ls52LatjS7Ce=_ym zdn+F$iBGpSyFPPk-MO}->g8$aowlKs&*yt1lRGVSDs{0B=f2Q#cSxAh{*AV0U8cC? z$%2y&BByR2s_ at erBPDG&k!`&vziGzr>J8C^kr%qS$?|uu%`B}yxIl?u5|$r0_4aws z0M}3vd3JNzugjcEdmZ!MO?f*m&GhG?g+;~$m#cwRZ-zC!+va}XX!;J1ucV%Db3&Gr zQYPuzO+Rw?<(~G2W8cm{A7Pvmuhc8&mSf3~)Ze?jeyf_^y|m=r^E5So*-W>u-JRLf z(HFmFy at GDn*q|ak%_c$|r9^DmQ{xkn;l%FFq`=kApGQ%iul)IL#nKFB#4wc`OKC>u zw>K4Uo?q15zJ;{F at 67Zy8w0l;JA3&}`^t&!tgf6R!#|9k^w{EHNcgBLj9Vo^az|@V z=QxXOKEH5Z(XTMoF}t6@?f;0K6PEi$dyXw!dUyTl*{qJ)sn=^M(&FL0M{1t#%9W*T z7=J`_l409YvmbsdHJ;!5d}g^I3G!hOb^;m)I1!DKTnyo0paplqyGl6CUt^qCs6c1zx_$%ZWgRm`-0+gQ%9|2)Epeca!fQte}0FePdhWyZhQmcTJ0jEOwh7b+~S_Jq8ls^i>>wsngt^khp zXB?0@;E#}B0>TbJW03(gWt5~2gad)}KzVkpy_~1fn)t04P*lN737zOunW*6 z!26(lcL;9=S_=3+ls_KAen6Ul>wwDv?F6z0+{YjP_2A#~-X&Y8v2T;8=e}0T}~+!5{xMKobG);gA0&pe2Cs^2gs7NCWV3;FvzR zotCl!{GC7kSe{YP{xkgX=K#StNT27AKh~!ZFI at l}OCJdY<1GD at KmMzMpr57F_~X9; z2>L;~oj?BIZBo!K=_=ruzU at F3fIsuc-w{Z0(D(-d%?EiCfBe0G)Bu+O$I6QVG6npG zKmKchVBDlL`QyI at Xc^!R{`j+i<^Zk-j_FGPq5}T)FaCc@$p3TDQ2*}|^8X|u|8EuY z|08Iq|G)be|Gy;U|3zr1|34S<|J_3Ve at DpwYtc~u|MoBbe@@8%^U+ZMe0kW+nvnk=LPP!kwUGbs7xMoHLjHde4fX$@|Kk5=g#14j4fX$SA^%Si z^8f2X{(lS&_5Tn5;{R8K{J#VZ_5YVb{=Zkq|L+O;{|PkI|9||8|6dUD|3Wm>|DOr@ zf4Y$W-xBiwYBbdUzx<2;Hw*dyVKmhL-wOGEmXQBH6!QNDG}QlpBY6oCq$nXGGD?Dg z#!HCE6C@;%l7xu(7zq-ZC?R4XFCm7;Nr;G!mQX@4= zLjG{buY~0vN05-j@(&v$LBsO9%1el2`Nc*{%*FC+DM-j-`DMmRoZ{t21cZH0NeW3K zX*3KCM-pfR5=Syf49Ox{&nrc!S<{U ziXXa;;z;FUI2>&ME#1#UgXO8=#$*lE?Z)V at 4IAGVc=G9-1fj$%D6!axeH~)uQ9Bf~#Ko7PtmQCm2KN9k#bG=!-?e>T$_~9}B zqhfqJJH8Q}ICtT~c^cYUbFrVav3-an4<;0ZU{u9ngonXsOTl;#hq0E0 at g<;9ND+-k zlhIT(3+bT6$Pn2fcf>)FC>NbU-AGh~SDw7kN#LIf{Bsol9L+z+ at K1R}LD<^~M8Kwa zb-?UR7IG>f6*L!-5DkT+Q%FQ4Ttq}vL`+0nWSEGQh>VE5$T$(Ah?a&b`{L>vIJTH zqz)v{mxXzDn)F(<5+dKA>`Ss2DTy=f8wcY?`$GG{xRcsKe6ffjf8e$hnx&<+Kg at 1I zOg0(t3m!J;UF#8UGhRMR3KgR{yR3=CS1Ne=2mJI0)TZFLgNKhN$Qn;O)I!KOD24RK z6T}in^M0 at 2$TI_zBq5wEgj0lYsu0c=!Z|{?MF_VF;WiRZ~7MIXU*6PCVhFnQCn-A>$^buZp>w-Pu>C z_^O4lLmuigQcWrBmx3=Lq?xb_mg$YF%SOm=={29*)|o`2COG?(yhLv82xrTlxa at eh znXsD+?Y))mW?(*F|MBr=Lc=DIGfdu~vWDgY#Q}SwshvPU>sko;^DzA_Zsl4zK|fOg z8}V>9NyIdIc^lzG6>?4AU}CA_yDKR$xs{Nt4EW*d8}35+J%sQ(y+*Oyw| zMyQ&@!v^(fmd;7g-s_;xyl1|_lce(Q$Yw&}C|>(fjCjE0w_qQ!kiMhz8+w`e(LkZK zA9rfn*oJ|~+Kt3DNA6$|nN`0p~VFO&hU at 81noYrg;Q;?#( ztCf(-;!OZr;{HEo55i%LkV)tEwGs|4gZfQP>eXxMu zP}z?8%eWS;chjohnkviZzY}$h&wN>$GqGm$JdwFpX?K_nm%NmB%Wc25S?|lpGv=-?6DKezikp??izZRFtc zqse$u8zFKJue~Qe*l1N|G!srlfW4e-8gWbrR|sMG9bF>Zt=b4tYw-T{LX}+>#xaHWIls&PN(iJRfWmF$t>Uz?1VC1`BF7t+2r-biSz4hg4>~ymWcDqY-tV;9d zDt?+cKNjUO?)-iR{=Aqszo|Y7U%2wqb;8a?pwD~$&1ph-x)4?q!X?LEPLSWYhmxn5 ze0l8IE0O9#^6oqpllESYY1}@OXB!mF4024mZ`ys)rc{U-bHn6RGxEB&icKA}&oJ*| zNs_$nr|98y%?-qz=G5{`divoDbIO$@KBwBKt5S+rwYqGL4qKRYvav?>wX<>L)0+!r zs6A&D-xk%si*ThTZ>8?2c3%8EIHqNRkta z`F7xX(>Th`*Db!4aP%5BAH)-gjr(5LN`e1QpGjdh!QTQWwDdQfC6~VLtjK?^$aw zrLvW9tOBs#&u6K7)~#GB(n{E&%d>~aAD4E$hwEF$SYG)$q94K at R<{vy7xU)3o)cs4 zTJ5?{E&n*VvUY@`#dk|L*Py&3rg1wLnJZ%HzV2(I!jQ>7B at _rl)cw(V`Ss-uP0_2N6Ch??DX7N$PLc2lCc)2 zq-`)LZg#q-L+evVDe0HE zL0fNatzJM<8F~FkqWOs;wJVM17VI(p at ylY9?l6P=`cj#4hxN&Zd-kXs)jJyGjduzS zy!GsxiGf}9m8Ih>>#aSmSys1~&blMRO4n>Pj{RNU8eP-zpgMlaPeNI at d9>x&4 at tvo zel5D%P%-T6^T4j5J*H at UU> z4C$E5k!33ioj&%YXct&}-ZRS%c^Hr>A^m0Ei~NXdcg~rn&FES)XT7zb^^Juhzt+8{ zL?k&ofp< z4(Hi!iQc5WHtpOlwF%nwuiOg%YnEXVNN;jum8s`Kh~mXnW1xk_Gs z-MoKI;K*6e8`qN(cS;oyYN($V$KAiPwOZ4#Fnkq3t8k at zko76$XQFGYtBo{|lr7Jw zE}v`L{_d!wSzgn at XXjsRQWO8U{e$7e_v91_uZ|JweNz*nm at ZS~Tut}LYoWHZwsv+s4 at p59VVo*w$ zZ|^z_qiv44LCZvma)meP?y at 7F7{`2;&G%VH-Bji7lGt#{nsRg>y;}Qvo3g~~cVB$7 z4wx2~&A6_3zSr|n*)3uY^J=b4Yuvq=Y2<@n9{Ve3 zUt+t=M>8#_bWmzqjby*PU2?zW(eYCc<#i3~AA}wlF(q`re2HzQ?AM2s(i%gpPu{^R z*lli-!_Spl0F}u)MJdxW8P?;qLg;|xSU}huJk@{ zb9B?EF6#pQ8FJ5BizgdMB%TeK8eqBA!sF at puj_qM4`oJ0X&y2wRF-C3aVWT!*xbg@ z>8qyhk$G9(+gG7~An at VCnHSxy64yBxl^S!RN~50CRr at rH zvR!#|;P;I7$LsIVI_g|RskueWh;1&;;)#!}<}XvA8z*@zJe%xdvSF{K$C8 at KTGYM9 zpZ%w<4QUi#G;!03jxnTN&2whlok6^-(wk=+u%XB-%f}+-fP7toy;-osmGiSq!WpsM zHl;NYntE#r`)sPIrLzy#7tb|HvG-fJ;any%tRJo#@v=;Ly56*gj)Pq*EvpWYjH6B0 zy`Ys*C2m{An1)qJixSUPqu<)jmiteX8&+0mu%B2L=PA!VcX>(Wee2{~KALf-Qgz44 zy~@ZS8d*gfd8Vg~IS_90So_W8xyQ}JsrfJ4e)_s}-mGmXI&W!k^k|uH)nSVF#*s}Q zL?~Cyqs?yKun>Qnu*P0A_jiYdNl6dwqQ{Puy{+ at blrGn(kO~(1nre(qpIO|fH(S9e z#-gFcvgP5Cy$d%Tk=@X?FU34v$K>iZQO%9ROB7VrUHnDO^_G3^XDXtZRhC$^I6KTb zwQjefoa9LqLx+#%g)gl`N9_pb9=OL+*7)dTSeQ|5#a%i5oKKvsZFlVh^D0 at V zc#Y#*HJ;}`c7FMIziCa at C>haM+KT)6OUK7lMw?c=Jvs4=c3IhouXoLwpITFEkR0Q- zb@$eiT?;e!O&&$9Q8PPg!CcQ}O{=W?9P-ApdfI*6$D%(?GJ?Y#sqt<`C*0SIPYpXF zU8zoWW_;ahz0>vG#M+I{7bYopY?-?~pORAJ(`EUcVz{TodaaH(jk<0B+-8&X{gmmq zD4SIDC8)cLf1bW%YU1D|$2dlNzL;DUv%s(6w)VoS586|`%>zie+>=h`%SQxDdK9e< z+N^I at n!=bU5hdHR_x#9fkJdjiNlRRPEz7a^m~_IOv#PXC>TYs`$5<(iBJ^|qv77tn znH1c(tMgNSR%qJlIa|2D?~)GRo)Db>q3pnuwWdivPRFfx1hjH>Yp#8MW1&7~AzETnMw&{J8X|$7N!TF^N&L9wzaMW4<`8 zk(254cO6FUkpG at wk(WAbJMrjL$q%XXWsEC}4RdFl;cA`RG4p)=hS^3JhnpvTZ~FXc z-_IQJ&O7Zf*Jc^*cXS#4lFDL_U&w90V=HMLY3+3>TK>cSh@~oFKkKNLv5F_uTot^E zW~pACwsFsLYFKCJ4E102}5Fu>q=tjw(a+lmrChKJwUHubS-k*jOn>DMVEwpLzo ztax5#nnOJMP-kApqwWvqUz4^u$C}!ox+GPN8d<2^m-lefgYEa8R~*+}Xjyr6Y|hEq zqzTKdoYMlgJ6eZTJ6LJvRl0EV^v92$Zb7OUrQCFR>5|*V&J873ovTexSjSw6InnCY zHnuy#R&Kb-zDZ{9IXC=s at 7iT2GiIn5G^j1N?9()7i1BU<`=1vziwwo0Lh^}1c$^Sc z62ip4V7Vb!MM#c>%9j(8iweo73t at So^fE$nX(2pPD1D<()_WD3CPMKTgcu?-mWc?Z z*ILApnJ}}7aOerFuZ at D1$Oz?^6~ZHgv5>yu!dNK1n2=mT2rCGsA1Nfa5yI1i at N(h) z7Vb|WJXWYYSD#Ne7q3*7uf(2TX*7hk%%!eW+R{Qel8Qf1Z>Y)=&DYg$CG6V`_Zzht z#mM2vv at s$rga%pYznX__N>SNP7ggs`Dk7HMo~pBms=IEezCIz`!WfFP&q~RU3T!6q zd54IH{n#Iu2-SC~5H=9PMnZVCaQk~N?{*UATPH1gE1 at bE>KCx#+ugD~HVYj9=kRcEqQb9}&CP^dEf}9uesryy#Yi$A%rg;3LqvQf=oeQXA2?ShL_*v>D0K>b6W`8Ch+ukEqfDr$FYS_tIflYgs^{a zQ01e|1Nx8`8ha=PumKOhyK?N*y4V5yUI=#!>D#;^-p-{B>Oc&|#rCvYQN~o>C`tN3W=5BT)<$Eh3`!KJ6%A=CDBwsma7*>?57E0Yuv3=zyp23Ysl`4-ic&Z1sNRTrDVm(JIE0WMy7AC##o8RW#B!^)SASom#IMtoU% z%ysK}_Ds_UDLcyZzxgPc9P70%p0ws#wU_r1 at 8*=JUUw8oG48t+XTEV+l{4+o#Z>J# zq;UFrMT?dRjwjS!-Cn$mY;a__dGj6B8+M<=2c-534`SXMUSS+|Ird{iTVJdyu&TRN~y*z7kR+6M)iRRvMu5)ElLbji(8+&|?QP|nIm1ks3 z7VmjV%de>zMM}!|IA3>JS4$_+&ELIS-8|n*wmNLs(_6P&Qg0US*kF9DqG`?X(h;#@ z<%iJoljn_h&S=R>vFnoRo_t$F|6q|-u9m6le%;kM^(hX&J7=3&Rh}~l-=uu4R{Oyr zvwVG3Qb~7Z;k3C&CF!0ceqHXYrQ`(9a<15soPYPHcijESM9cV>Bu~T2f at y{C%Ec2? z>x|O6$Z5F>wvT)ZmsUkhW*O(~GaHlnJ!<>1dd`-RANrJn3!A&FRh>vDZtk1#JR`}d zVC3B5tLz&6b?cP1C%1pFNG}^*KO_2tUe>12fIUg$NV{*{J1TYYs;9Ks=RF=y(=7{$ zr at q8X`E_qIK9b8#I!M`;J1nPc*51PHLeICOzpU;EH3ht%hh;Z)My{1{Cp9R$9_30* zGAOHfWPIib_}3iX-^U_n+;pa-!hC`~FAh1>%O?D$+<)O~lpHn2!>+(^LJQ}|sYS02 zSX3&+-%E_xkY at u^D<|(J=?SpiNw{`vWg;hF->J at H@OuwHg(MQhS zKl7(b)y*#)A$`sgk{t7+K4w|d#x7kMs$LXT6Y~D~@FQ>w3 z6&`7e=ATus`<)$O?`c at Cwlw_N&S9rF(lk#HrCSMmMqted1 at EG9X ziKTth9tVB9B58Ph-3doEt^@6{Z)?b#5*33T`;!<)Y3+{W4?i7zf3^^I#ex4^%1+!x z(QsXKWG}hEPifv`s-a at i59Jr?nb8)B&oi^)T;3kexUl4G>#i3TiCQOiKgw97e0NW) zW&Sj6^JCSz8{Vw$_E}lLS<>=^Y<0MCxyo^}^N!Uc(_-h4H&};_;*jjZ&zwms&}_UK zJ&Ce+DtDo|xY0q+Wj=DP8I5KKru^vOKKgO)L`G8atE(EO^{dZa27KC-gv`a_vh&n==p7cdwfML(ZQ%H4G%Q{8f_ zNJ-|f^_c|UvL|U>>n2zv%A7ZoD~?sy+&p2noW at Fn$Vrn}5jxJA%WJY^E9jeh$V-fnUT^C4rH^jaml335M%Y_svhCwPQ$&1>WjkrV6I`v6t?Bct#wt9}d%r#YmGW9j zMrzW{jr!g!HFjm&)FrztQW`0(|iVl zvC!t8{Jiunn`Rkr3*a7fQonAmxBM%4^SynBQSTm0t{JuV;?!$(TRYa?vn`}8M zxFnXn@#di$-lp}U`_p!5-*HuL`}uU)*Z|7D_=2qQx&FFjPlDd4Tj>^iBe`3PTEulO zP`R|qs3g;(aYS-x>gar&(kPbMAJ=vbxc{9>61Y2p>DH+ zU5ksd55JQQeX3u0B<`Kj4#T#-2A>HnmzO1O`qnOQ7O9=e6bX7{nmS>X{_;!JmM44{ zr+koUO5v^_u4>ml(Y)aLja2;~zn0wG^*)HDp=4cCrafmVTe;Ht?rVwM3`Ntpd*`0r z-970@`pTc at eX?TBV#HE=dzn96+5|Nf at Qv&tOMC5l65%r;;(P> zLX8ep6Q>#_87Q0dc=_&IU1PPc?m^cavi-Y_&XTn|Z!9w?+1-92RDNseD|!D;#kxkL z^m3C6msV%q*Lp6kyKohZ_jlfYuT8BTq+{(g^6pKs=jALWI<-8G&z|s|T#T_qX-X=8k zELTkPm?za}nDFanV6>f_ho6>#(Vkl^X0cE6rYEcI{ZaO#t$pmfc;k3oF^7zx18w0M zBmEANXHwI@#(nIZen-RYwsLES=SQms=41zz-Rs^Z%YK#}=iP2{%&DE`|KPFbTFK@` z_tt+m5AR)e_UHTjnuZQ-_sST5lf*_B#|o*u%z2x16waq+o7FvAw~uk79c58h>T6}? zn5OT!)U#yC at L_2p_w?v#ttNX5ulr}d`u6(Au%7jAcJ!Gv#0Qxj%qbhyR<(`3V{N8I zb?4M;ch+x;KkMUhD&u_;^?>+GjaL8t%6D29hZfB{M$Pm37+*T?QA?#}*O?ugz8Y0M zkPA9y<@;EN^QO1&>0Z;UX$M_T>*ntK?pHw2T%c^6tUF0g;jLEGk>`arZwKvnK*Iak zEc8Cq(whiH$9elLTxaj#?Z>;t+fOGVl-^r$vQCl21FIUpyWLjzcgNXnn3p=^ae74D>ojiJO^{~)i?PF*awO&)EF(I*|MGy7CYICfYf z?&Xg+^<<+kYlHnv<1x>Tgs$If?28VZ&aNP*OJyHD{vhZg<(=BaQ!CW1Qd}G#Z!EjR z`SI58>Sx1qCTU8`Z>~?Ry?SEm zl_NxNMy+-AjRIfPvhhun`?vM&53ZYKpDG*HQ at -NI1Zf?=uWbgVl`fiuR at 2bg*)79A zcRjgcT&di(I&1q3-TA6UPraG8)YJ#Ff3@q>$bbWwEXwm-Za!Y&WlX^GHEtX^~M1s<9a%*@^f6j&Loz7`S7TsQRO(tbjNWWmrEuuw`*PKwc7u%+dRpx z*eBw7$g1HB(py7 at U$n~Bc^x}@PL4&_`VSQ6_H+N|hg)jkd`VSXVNe-igYI zj6QjymlWImI(NMaeQT74+b{=jSEC(W2bEMRCRn)EJ7kVL*G$+m8^7K*$tut8RjIcz zj4kJQ^`*Vl at 0EEMRJp{HQc0{nN4 at USE@p5l+Q;gHbzz0XFwe!B-cwH3N59wV1b=dE zop8%pUHo`ZN3uS_Dkq;jZ>C*m_e7OrceXs4ZdCkM>)^0M*VCU>E>$a!H8g8@`{?3C z!{R5Wymd7S^{Na at Rj>EXx#Jo-{;FlN8$HT0+Oah#*>*}*NxVvO at vC`;;W}Yk+H_C9 zDWw_ot{l6}yvROiRsNR7$TIl_>AQEuT4Y-JJ&)gIdlz#$>=6d$h1j!WaUj|pe?;@0 z`EVuopbv{!B(%U&zRQ6+(6aepW0$ z`vAHl-NW8Hz=X}P!}p+@)BH^6ZdNol$)9aS3o#GyGY?>r0=(?#{#19aH7n4Fj=wY8 z49-PRk}v$vLA>{kd+^WMh={ECC$T>!gnuGDehwZ#haZEG4Z=Tzg-CpE1T}XD@?9yCFFN*~c6_{9 zf&F1HJ{A at PJLC!?!7KwfP%*GjTn88{K9FF#415f+w_s!Srn|8NXuQ|bgMH&c%#1-l zrWezR>B972Iv`&NrUT25<;C(K at Qwhs2MyN&&Vq-)Z`d4u9JrAmoe#jP at DMl{9s$0_ zf_|#~4{69i$CjYXl)n-Z(QkCTuz#<92i|?<-6YHXRfu zF_|pfFD(t%+Ec8IF>bxW%Gj1-h{st`t&QzTwkxr)q5Vo5V}4pgs--2#-WU&)EP2Ht zW)AN=V{Kgq$Q8mKFUe?E90}R;!>TM2GUJCkqe)1gA3hyPLc08LX#@$0h>D3z43m_S z9zH at wR&Jy`L1EPBF=G|SDJhSiFmcjkqRN!1s?(;csn3`>Yqo~w9Id(9I=b`p<}X;d zXtDm1rOOORWJ4ok6H_yaxrL>bHPvRht)2Y}2S=xst5!R&aarq1b948gdwO{@*7-1f z{aF6%*&J>_U{G*K=!T7(Hg7>|HD at F2#qn!_76UE8=1Pn&Mz}ZofmJhLo}k0*gv}Ie ze9k1|ZI?yE`95U{zHA5Q;50m`9iqU9nf{Fgn-8eq4}^7;POqRs+(J zphmp83!B4;_{>JcXD&KEr(z{qLI|7PJ at 7bBT(2*l)*D*Gfe;O!k$E#9HqT*mZ~*SR zelQ0S;eQ(5@<3d}fG$kVz$G-u$3UU{beLBU$Gx7XpMlQ~49H2tYs)K>2&Dz!`Y|~+ z-?Q*iF_}M{%>EoajhY~#;H~6o^@Ugtj=? z*D at MjvY?+d at U~%niOuQQTt!6caLsWC#6~ml-ovcGy}wR_`;+#!J>`ej5wjlNb%%}D zg*_yv5nd;3CTHO76pXoGytVts+YfSZar^MYd&>*jN`w;N+KylSFs(f8OyIoM3Py at 2 z at g3Bo!sX2U7rXlFc+&^Vfdqxt{E at e9IR_-8-+yYlq@3*})}>hWJJZ(e_S z{`g2?dIKRn8()E7I{wac1im<+QJ_!vzfk|RxK=s}#%n%@Z&5sijhtW<|62dKXyG5n zn+2uO`8DSGGm9_BX2C$*8vkDJP&>kEKxW}<^ ztsebzfX~0`|F77~(2_jx{-*J at 3-k{7A=alX+#b~NdDI)f<`D4}H+_gT{M8?|293{u zUOy}a&jztE^TjcDNd2 at 1jn99s7h7#(_XYxuoWIzw)}Z;?6CVSf_wcSb{(u>HP9lDF z^2cM?I2P1`m&apBUtkAzKNnU^#$St|4jlX3cuNr(PZ0|o+gGCnoPfn2B;&tzjs-pn ziwBPF18OWJBW(YVKX7GCDe&>Y5(~&^0&oN1ldyQ;lYuSBC*v!emOL_20p59ljIfWN z)&a-XuGzptfo}!g2Ye&&- at u)LTj9RJ#;?=Z^%rZK13vc)W(7ku3r-^R+|bpPC4{g$ zsDb;Z;rxEk#7~6u@%tYZ^eL9gmw)Z$<;HaR;Jq0H|1af_&Cn8z`#nMh*KIRI+akQp z>i8WSW|h1h80vljOeO?}VgE$1-{*=AL&HSn#f^=PC9q?j7Q#OgtWI2D<0L7C=4)v= z+DIZqBw|B`q+GpS;Xo+ZKNt=v>~#W?ND6;T1@@zKERnlA2d%I-(O3XsjL+4x#Mj;{ ztSN?6BV%M2!h!o4!RJ)9bo3B*FK7h)N`kT}f4LXH4ha}`!5*iH5Ekc$(*}iiKv;?& z-Z?0oFescjD4aAXoIEI;GALXjIuNcL6vm!ONb~d|!QQO at n-Ah&PWArtud=_MW`Fsm z`p|Rh-<(5JgbzAJ{=;){{)j=R=zn+$@)G~2yZ`@yArxAtQv_U44aXt3-*ZZf~!L-Bvw-hp-t$MANrhJ{B&ZjFkLiQN{rJ$}c| zgv6xel+;~m=^4BC?A^CNGb=miKyF at sLE*uo;*!!sWrxd;96eT1Syf$Ad;CP*$@+%I zQ>V|IJ$L at X#Y>m3T)o!R+|t^1{l?AqTet7ry?6gX$HUI9N8OK~Jbl*l{Kd;xuiw1w zefR#u$4{TXeEs(QN8it1zyI40VE*|5%YXC$=6|~V|I_9FFMj~`&+`8x`ai&r!KHg> zaJV!s_L)k=$36@{FAtV4LfDs at 86Gqb;&dXHn1#rDJd{}HcjUT3YvKj6) zB#;pY$%unwOjaPx2iCy>bT*fz0nu=u$JW5UV~WfDu{YK5!+xRIyG?>LLg_Rn&CdgQ zv;4fENbEE55N6_WUf7qIiEeBLmxg~^m+t3<$GeBp at n^~cWr7qmUpiiu01igbR;UXn zh=D)+<^<6_7#wd6Plg|^gX2%bK256;NcW?M2GE(99zk3HJHRV|7SfM-?IGgr>5rqc z at o$^x%1MZIl4X|FN z4XHDoN#xL&fiw>mdmzp|Udgu}s((U7;uG9J+=Zn-`N1%hP`Y=a%SVEl+<1&dKN? z&M7DZ=jJFL=c^DG=XS^m=k~}F=cdSjuUD7PRe_t>lF?|K8zO{rOVnF~aXZur+{l=O zuHxJf)!^I`9mKgE%BbO$9}ApfZ-+Jlx2D=6Z$7ujxi!)UZeveI>R5U^J2VdGWF&=i zOZ2fC<5bj%b3=3%=SHXk=O!o{=f)@==cXta=Vr(o=T^uG=hnyw=MjJm2rJ&h(eJs!f;HyX` zNFKNa^e5uukCi;!3EbYEiq{t_ucea58!LJBtl`&JMn+jiQeID7MoL3mOk74 at UTUHg z)zAi!fUNuHPV4^p)RZpRi{OaA4bF~>fB6}U$39rk`${&&&lCHsF(z>2<*}r3xFmNj zBam*x^2a`84{-cnMM!T$b1 z{{BOr=NKX?vIbg#?2#&9dn+5bTludaVO?b8+Caviq1f6P+0mCrO3R)knru6ML3i&# zqs`cjgyAA*tlv1!>);aZ&T{r=v#=iIIP)%~&hEUAi90hHZqC?C0Ry-UCdb*GHL{vK|F%Fh0Ykj-)t)F~qRw{`pV`#1LJ58dE%0e%=`@JBf{mM4GA z$H7AK?CpQfUmE{s`Ha**%YW?pvpl0>&AE-TLSDf4KSQ{6TmAT)&5R4f?}x28D&w<=h{T z9lHO|>3(z$$RxWA{;^(_gJh=$g at xPK^M+S{?8qM!u7309c3(;Nd8Hb z)L+(I2>+9wXJVv3mZLImsJul;zCmfIT)6!b;|J=|s{GIOa2)^Va(WH^EPrqIXZcZ^ zq4L4w-r at -B7RP^<6P-v%)#=arAN-5larIESu%CZ+{_{ADr2TXKPPma!liQ!m5Ayx9 zej~p>%g3|+EdO!w&*j&?`LmtO=>4<)`gebp2YvXn{+_-+%PW8Wx&FJQ$$ykzQTnr- zGV#yyvPplIpCJyF3)|15X at AbYb2?9s9qtgWxiD}YcDXEy)U`xW&!9Nr;wml; z#GP#tMXK7O=^?d}?0vi1Ed`nmqzohl^!2(ZdJ5DIR1dTh%7_5s0(k)0 z0_g*30mVTXlYq+uA*@}{CwGCa0#yMO03`x#1Y!cEfxhFAXD4tj&?+EnjKi34fx>{| zf%1Urf$jsn0{RZ5&?<^%0_g);133fv18oM{36u>~1#}VUG0<0_(QVMTKqf#AKun-$ zpk$z8pwmECfo=o60Qw9h4)sw0ngFB?WN at 7~hQIh at X#@Rl1f&O417lnalnN9J6b$4I zv1=L at oi`os9k6A)A@&@PJ|x}-?jb;CNVPJwx75+r^k6a(;)vVv?m&!r??K+k&uPTK zUUto5hd_=eB5+4y!eG)#TrQj87Qm%*Al6aListXYpa)SsF&Wy%&xrw$_%r;xNZ8-2 z4Vf$s-3(UbkY*iL8kWGG;Y&x4kr9hy1X(a-&+3mC6*V1Fr`SQ7NvK_Xg`e+`lC30| z94?zl$1WRQVpai6E`uBbT3L<^54xc at jg5>&`S)fd4-YoJS6pArl11~dWVo?ucpI-H zBRZ2VD5Fu#mQM4)l_O6fKK&>j`Kih6ILr5HiN}xa6=54G^__2u~rxcu-SCK{w?%p z2gM2U?#A-+fItJv8?Y}dAJkyfK&=MV9YH;OS%E{WX)$js7=gU}*h{!6eqgkuzsB2P zPwFr$8vR%8aPw?oY-?@YZ^?3^1NX@!G#eiymOJ(gP+KgB;}4p+o+OkY3av3>dQrG^ zUwe8mlp6#wejWp3Ko_+IOQ3P+MutcQ(*nE<88JBi*h}IE()EejvuS=D>_zVUNGM6v zhEDexNOK<<`+3;VplF0PW4d_T9<1olFn6e#93s=b7=HW|d%*@hdH4Ldts+DaTjB2k z1 at IpPpogM%-mD-2^5u^L4`btQ0d at C+J7GE-A7s$bBZApE3 at L}jCZX}7R;>QV3TPiz zBOb7Y;X(66ZCIQ^*64xBZD^P=AU57h{Eq8SqK5YmFB1F|>sww?Xoa1ztzcyI1ak_7 z%;19SBJ`B+ZM;V!2o+#CvEeXeF)@#?5yb#C0GrFUU^23g75055Y^<1&Ly%8jFf*_) z3$o`UI~J4SL1qVFPb5u^DEw+LvA$UzKxc>GyT?h`vH)W6>B)i~f_#U{vF=3HSe&t6 zfG;G#B3v;{^{4ys at g@ul_NL=G7T`MZYVgx6!D4vLg%}bt9l-pGkc=EiHiBxRNg^;? zGnvN0ba$9(NyyI3*ivBROk~Jf;m7b}a2Yh-b7Xml;T1>m<9!wZp`{Q<8I*>_r1SHK zi1yncHq(+g{c~=!s2QE+k55Z*$;QIGt at YDH1WD{!0~rxg9Td--(FB at a31-JZPrAq< zg86TU80I0E1AEvo{ORa}AhkXAS%x>@FPQPdB*Ormc65Aq5JC&ZEa|jB`d{LA;d3LD z%9}``|IgzViJJsJrVVe6EuGh%al*4F%p*!7gMUVJ8T*X{7 at J_akH+Uj-a{ozh98W` zbzCD1`=A!WN|ra%)7abqe at x(r#KkBazE&37gpU1^0%kTk2lJ;!aeF%3m*F=siNZAq zu58|Tr96y--Rb_AUg#S9nv;*s!v8FWl8oqX0bX8owxEO;(3gYTL68t!4((a}*GQBh z=)qMiKl+gNu<>@=U~%ZJCS}7`=f5r z0iO~wM3SF}9jtc at Spm@aR{q>3Y^+2P6B?JsB>DSe)?=dPL*dL{GN0~H+bHS&zv4GlluC at 6|ldC34_+6j>wK at H6Hwh zC^8qUGog8ymcPB7{MQ3+lYft!$NQ#;44;ehd7myB^#b+i^045*(%;bKrN{WcrMF{w za)Y2@&Q=U}Hj4wunYR+)IP*t|znpYlfj>s4!PNtMA6p&h!S-O5>hkv8?$hP%!`-OM z+qdhX%iEu82^{-OmOgMr;Hto}yOq&cJrMS(GBWzALq<*G3!4 zP~a05ufmU?$Hyc-HsoU)ejZzXyd9rA^7XIem(AqIW4}Eo0%6lT_FDrszplgh>BIPS z4(Ia-zC4mI-^$mM1cdF#&*bAAetq)z&OG<>MrIeIe+x|2>ENKOQ_e z at gI->ZB_hVdi?X|PoDgrHz)qj*8Bg>>3dgp~8fsRSU|lM!-}9*u-^d zst5-`S+pD$F|`&iX>8JmCT&w6#3F=^52TV-328Lgq-pwKQj!uwh#@}MNKyh#+pH1k zZohwK&YsKe0c=Tn8}iNNKQr^s<^Ru~fwLbcJ9&B;^}p^N?^PW7Jr$Sz%k-%Lo zi2C36-0OLs{n#_vQ{&wK$xA#}g%6Ud at i)g6wr~8<`1;iPKa5S>eaM*aq-aThhoXD` zWOsnw1MUKMfH7bc7y-TmZURFj0B{-T2F?Q?0_T7Zpb-cH z+kka|0;~Wsfw_y&0Zak+fIGk_a0~bbxDH$e`hg3;Ip73vRMxKtfSQ0A7GXJ#=dNMI2Jw3j zHy{6M94qL&REm_&PDjNt!&J}3xrffB$TJzeo7xRIonMBK()ncsDb=4$(~nCeDRK&V zriIhx^x3r9LB7F3UhW_dI>;L#@9??#zk!vc+n6KfBT&oavFJmczOzHmp`)p!jg5AD-o87o^gPlElmIVR@a^m!16W>FIP9kW#_^UG1| zJ*zxoe!0;opI<#`^?m}m$Ro?r>EmlCwU*0#wojK+?6d1rnAka*CH4&aDf2lVT~2Y1 zZGMl)6oie0$VLE}-&?KA5eN3z)>D{XT(`+M*`>@6Ms-`I*rpE#KL<-sx*U~sP$DAQ zNvpo3N60k69YR3&3qnjOu(cDGucva3rg0A<}7K zspfqYW&QSI(#I`75$7q7W4g5p8!~J&oj%#Cp|4Dj4coNo^YT6FBM;DZNlm0Rw=Zd% zHhtOLCgAKLU7z#0{8hza3g&le+ z&sKR-?K8EV at OWYKA>>g=;}6p*?c|4z at O8>Zhpm1ePx^wTUGgK&{9$L$Pp7tf%tkc(J8U_7z;f86 zo1P(0n;7KwNOrPT&O&vJ^Y#(1P?O}{tCi(dy!H_rpPbJ27vW4=t(;+StK^p>)~sEe zYs=uj6Z~I-%PGQHgajwlRz8C|&OoTwHFJ*%emrCT)^QhFCYzZxfcd_F`JQ3F^ZA}K zE at sf%daUwEtY0JRWv)!I9*IPY?MXWWee|M_EPfcEI^slN-Jh%_-Jcc7{n^b|LNJsO z4T|ysun8zU&=Q_?j_PUF4cJXok>^RPgEMOXEh2wfGJZ5ZBX~6XqTMvC1 zd`z8eyJS^VIG0!>-!Uc0nw4q;OX;IA*sX2@^Z606z8#e8j=Fa^*@a;JY)JYod3mkm zPZPbhN)|p9S9Fi8lgyI`dEb;f&U6k?!~dOaQRC~Nv$koRkGjq at qX6fHJDhUISlpe! z+55Q_VJ*9`md~=E+&VXR8~W4OJ`?Ae$~jx<+pNsQT_&VHTaPa3A2ICdl-wU at yR+*s zS>3#TQ0ceZmU{_p>w$x9>1(=OvQ}!Gx$gkKr?*+|Ec4%yk2&qhB7I-nw^#G~_LRx@ zi)%Ga4IgMeu5^T(TeOn=NNdX`t*%iG*J^9S`ujC&>yCss)oS6wc3-{{u5D>*P&NG} zo05EA;kx|I&n#Dz;LGb2URV3 z(R^9FP>X at QrnaliN;AbJ`L$X_OZ$<-YHPj{Y4X?6i(4i64Ykdhn!mZY$f2>JyvSL5 gagk-L#YM?Uqg-61ujl4Uf2Duhwu)V4!Jy3i0g*_Gf&c&j diff --git a/Lib/packaging/command/wininst-6.0.exe b/Lib/packaging/command/wininst-6.0.exe new file mode 100644 index 0000000000000000000000000000000000000000..f57c855a613e2de2b00fff1df431b8d08d171077 GIT binary patch literal 61440 zc%1CLd011&_b`4#0t8tS6ciOT)ubTnK?6a z=4^A$+#8IXw1(nR6vYEDn<*-nVm?ypAAC3z<<#q_6LrAu$2W305kI~Wt(u)7N=u(N zD}CBr(Tr)Ssq-|V=}Dq=ZK`N?swiZFnfjy`?g<#Tt-n593J)AHEEco?hYm3*mG3ja+4TToKh!w3!7R0j57p9>rzH3k zNE3@==vrN^gF+cg2bKf2&$DCDv%p`=*V>lJ_#7l#m4$<8`AVh2taUI~>Ke=jS(8Bj z9+~4T^wKqOwcX5Gky$GQ3{xkw*$fi_orkOc1SDO9Tw^C^$f+6PuN4Wh?~@@N)K=yg zk-h-dJD8b9ZPj)bZC`?ZkU>{{2g|75%J#K|zHxEYA43t4G##*xOX`fWdbwHaZq~Y) zT`Q1-OPjDtE(Z=?hO)obMQaE5RY(vpUhAS%^OR6=6DoicRfOw61MppdWBcLc>tXVm zeoCcMZKW`~<^qnwAmf`WX&GNqs_lY!xO`O>!|NCk at W7{FO5)^G443_MOND#|oxoSd z3iKOrv3^Ebxtfxj(k4+9Epsr)%4wO4)F3-c%iPp{Dk?)t8Dv$6^w{T_+>mfN)b#vK zKwavtD{vT}EnnuofWZ8Q{oGm&a0| zLvb1}1|hFCLQNN+XZ~6t%FzwhqA;D01NoIWgu;qTV8v7DQg%HnYCSkewF|6BXpG=K z at CWHAAh(hG=ZX>XaE_HgFSDYk6(i;0T%JJh5BGu-%AUG{!A1w9%Me*7I5AGd zJq at +)+zP>o(eB*Pf!qs%6XUya%ej%YhL}6Xkgh!qvYSSI)hn}EZt4jOVeZ2WvIa}7 z71Yv^4Y0zj0Diot6H~9^1Lx(Y+Y>1Yl!-w#yB46PC%I6 at Y-_AB$V?!4ogbx<7-aRd ztlsQx+7CTI^Xf>+>?#L))|CkL1%N2XzK(h;bD<+$jJ$H_2feiAKzcXq(L9Ta^l at Oy ztN7WcH1=7IL$usdDqgC6WTAU3k_Lnms>gw_dG!c5)ewO>r>dDt=aDyv7>&Vz}{|c`p|M z7Pum#z5zL?1`M1L=I+c^F?5mj!JMaXJYh2}HM_}jy}(YDKF^c}ZLL9DXVBg^XzLBy zCWE%Y>^c$LjHGm_y8mYfY>fM=o3hO8OYio%~n6@M*U?_RuvCcDp#ZVDj_b&!TkuF)&^`-b0&~c++dUd zv`m%eF9U&xHqStb~sPYc9=nY``3Q<*EZLZ6IY?G3bNO+aY6$MZMopEOsJ%N z!+?y!JHl9csS7B!iUWfK6+n;qD&WSdtXfq}Nvz&T;YNX^$eHLyZrV$s!>L)W_GTJX zbqB}-TdlKZI!lD6BNA|vLC9j9xq2{RSEj`>hpVcv-Lz%`MJlv?F>LA$v($XtW|)$; z!*C{^DpsmNOgT_thG>$mGrLOR-e9vW0E8B22<62YeDOB1g||KhN`DzYA8$3ja$_W4 z9t9x}s3T}izoo5~Fgjl77y499#3oFz@ zmGB@^?n_-G!X_G*$i_iZ-BJgErVB(}OuR at Y^25jupUxr?@(dU#(1j9!$A2mmn2Yv_cfQ&G-l)zyqHHEoS&4CEb1>^+f{H&9(PLp#K zuw1TG3)BJy-NO%8a!Ca%XB0XFd0~1eXK*^GF{U(MB9uZ%ilRV+hC({9i zC?>?9Vi*-J9;jQUazHKPiKUvia&O^1Iw{R4T_6%nY5kR; zcYx`R^Ve;|Ry9S-I~c>9xD`8Uw%gZU~Q(?mlQT(71)D?DXQ6X=)*&zL%H;e?Mpi!Ok_lGS<28n|UliHzb#q`>$o za8XLRng>hr*efLu<+5P*G$yOk+M$1Pr7+DYfIMtHYUDO_N6LKQe-`*iX&`pdI-7m~ z=73xCHV}7}SPU9n0E|~{I!M;!!sxUq2hg5ZbuV~c#Vy^=VCpi(Jga3kxnWQ$);d6u zZ$%1At#jS5F4qCf&a`D5Y(m*$7r0l%D0QZBv4ZT!FgbldEP^_E5URnTA`rjE6TI9T zT!QWaO($N#eX^uXpm%_qLK8Yi4$xoy(u!3p&?;dYtx}q=9IFF0AYB!NEwLabAyKg_ zRwTk#s5ot^^O7Z^gsLQO}=%`}c-5H6 at zvMqEmOgbzp5N8336~=6_ z2xnh(s99T4PqW4DxUmsMg_(%@LJCZ2gUJ8`ECYy|2N?Fc0cxysc~B2RsYh#2GSZ-X zp!%x0tU at czmsnLMYsg_K#k?{^?4li~=KKYb?tv7Y!2K^)^@z}TDOOcyxepOhVQ at rkF&QFoV^Oek5q_|}Rm=kELz1ut;A4)BB{EaJVzAL3Kz3T5 znp0z?=EkzjZtb$BBqo3}UQvPu#(3lvwLB6s)+>B&$W>h_E6{%7Vc0Jdnuxy_F_E|} zl$1?l6K)(xPO#T(7b-l2xGWU0rL~r65RnGd6jKVH!fC4)SWy-%Hk$kEC^Z*| zBc$`hZbCflc>OM`BHJpe?ES;9*;K(xv}~yrfI*0YLiJ+~Suv78OZkCAfj62#fvCR% z{gu|vfTgpImR9e_-ro_*=s;}nd1e at d;ipnbI>nS(4+G-y?2W`6*a at 2EU=yi8?IV6f zVHy<%PCK_3+{edh9Es^EO#Q=%S26X)#;w>$#h5xZf;O3E+fqzUDaiIh;kUN%QGfwH z#%&u9V|7U>!-=>P$O28bEI&%)s at el=h>d~3*%y&aJD~}aQw$B50}j<@7DLskD~?Q| zxAC0`v6ljTjmT8=5YHMgWw2K*0#p;md at VzKgy#=|6EWF6hMq_>LKSZrFw7zXOR%mm zO|YVxJ);Yrq8bU;|%GgDTs`wWQM|2 zIRU&2>O6RtZGKFCj1e>XPn?v;MB}=?WYW0ph|+w*O8f34r;AJZs;XQmQK}NW(p7Mm zi+6aMcvZE7xrJCrwVt_cg4=B7w%&Zz=b1l=@U?iPHdb;=6YQ_$Yex8M8#Mm at +9u5~ zOgD!>FyrZS${%uwsemikP-x(rWB3@$VwPrdp@<$p{t(kZm)3A~gRrIyEUu07j8#BtjV>e;Z5!TlWAzGzUW~2 z1|&HN!^~G{x)`zImv(h0+t3fx4(zIZ?W8*rY2E$zyRhxXOeExACm6PFEt9Jk@%$39?bI z!Ch>}krq*q8oB8zId~L;dR1F7yN=TI3atuM*gjs|v#Bn>;~GhrcagJ5cx z at N^}_kHZFAbd|2eLw`f_HW^l7x;Kj9E>B|CHmDJ62PWWJKDRha>_U)H4Y zlGJHDh{+Rck2Q&y6A?3{Rd~v+H*2iGdxO!JwHQ6|P;PDLS$&kDM|0FdPyEqlA|j49 zlNNBa*+Y38wRk9%8*^I+w>;*y7X6k%W|G_zWPeH?*zg6}ACj8}LAHV1Gzqe^$W6Uw z2_C5}z(cqBss at ziCAuL_@=7yORf`OOwW;po&31B_8G}be+wuG>znmOnDq*>D^Kigx z(3J{dyIJuH^TG6AKmyzGBnr~V?GEHxyB$x=Xqjm{o=AaRaUsTN;fgyjg at -P{$E at bW z#u{b!A$LU+?1hJyW>-Fm?C{P3V|NQm&5dS at bH}UzP zW;wyclPRWN4(_droTi}msWu%WaRsT-m4xAOadxXJ)+y at mgZE_oqEfYpp-)#LVh)2F z&j&HGoi+?6nwi;UyF+%iMOds zAfE1$iiyXu;zfX^LMb;r3}6qFfqXE(?nWavM3J3OB|YBiFjg2F`!^e?1MW~5=(@<| zD(~a%%(wO4N-!N*Oi_DGmDO^RHn}#;)#bH5S!Q?Qn$DzMRguT;yrexY?*Dd&RxvxV1EaSF8RS!VL<+?H zj?Xcg_fZ!-`6GB+2|eCfI|31f#gsE~8|>ScR9Sf~a>l*9iD8Jz6?9=Ty6&1qB=z%o z1~IFvT-lQJk$oS-R)1eqEv<`*B>2r^lYkKNEXsmQ&Tu#r+nty4{^NOR;;ELjKx>`5 z^|&SY_j~PDUw^#)2H(`O?KiaSt at V~2mu$lx&HHJqT^0iUNZ3zpV5$C*u#LXNZ8Q=# z)_QUSF;WfONUjO8eD|v#ssHLCqx()>OI2+h$dSt*}MMnl?N~4w6Ivm?kyXC at W8tD-6iS zs`-}ZNN>_hZyHBib4$fdrc8gJs6JK+VO7L at _EG3EXKtyol>t|#3BD;>H#B+ zc~%rxW2?5Ru>!Fflk%oCzpCKCJUCQZb~s;Vhif9IF!(K3@$%8D)wkQ>m>SF8M%K#u z2eG~&ktBa;1aWM*piwAe)%I~d1;(W%KF^+hYg}4y(AItXE!|@#9-26OOPbagw5y+f zdxGLahEXOf at CLRSmX??=8D!-~S%E=&6Vi?}l4Vrg>W+cK**O at +T?JX=vj at P1D*TZQ zAlUYll9u|GmbpyJ#okOyLrY64)6y^)TQDALg85eu!@*(lO~5~cY(2OSgX}w_Y&Fck z2E#{#_JBc~XVC5}lkFhCU2^rnH$jlOZ69d6s)pq^KhV|}Y?oq|%JnHIHs2xKiMAZ? z`l{-fl!!g}YChh at XS?L^OZFX}F1MWDGf59VWNd0afMR94o;c^_gf2Px8`E4o9 zQVUffSf^$maGfe3N9Ii2 at t-kE@P8U2C8yN-;r!zO;?cU9%S*F{Px=^;qn<&lI{3((i99SDxP(-ffOdB z9?U}&Tj-L4<%pKDJgw!N8HI{kM9UnM`hr-^JbI~+*7C_qJIOk;)q-hRjq%!XtHL8BX{n84XpIlKl-hI%9Y4ONzcG at p=Hr9Rn~cW`=%BU6 z_VGD3V4b1kYpipeLZ#z at 7a!MfVXmxxNDT?G at buFZHjL!=&tmC7^f+MNRa|29H at VIu26xcVH{z0m8RiN4eq4s*y4!I&^A=ex zag&$v>=wMnPC0WTt5hhMK@@UDvLT_$?7EuqPQkSA9W>F$cm{t}Eik)gr;*bk=ABE| zEK+jKBoEwcXCJJ>%cxoXsnO~VvA8G1NlN21+$<6Eo((2nN`>W}4b~C6DM`*rrfU5L#G8ae zu6#^gOEukf4OW`YO4Xece?@Kf;w0T5r>Fm~RuR~;iuC`@DtK*I(eOW5g;M=C^Vpkt zofl&AIIUG;@irk8Lv?2m~~6}Tu6Hj5N|H6H7so^lQnd}r*Dq2v8rK3Ktpu^m&ErfZz!1;@Jud)*{#wJ zP~4%i=7!3RwDFm>pc+7Ut;Kc<+mER|EXSju5L$axT_FyKuiuO! zuSjd_U@!+J{a1 at scVPLd&4uJ`9XWYAZ6naj at wJI06Qx^PN0nKl$H5?$yiy=|ex(2QwdoOvRxv6?ryRlTQ#?o|a-6C&2i!j!7;RQ3x7iL*~O;T&j zfYz9hJa%t{cyCl|43BmgClEu_8pEYEhHb2gOHSiuCQuC?Ei*}Eb%NE4UlDl|txsWg z1`!f7L at k66GPj_er@`}pbVP>Ofqgk}eHF4;x3r0Zp4ujc0NAa~+IrQ at f>xoBOHFsE zwzSu)q^%o;YAGvOuYy)dg~|L3-(V*D3LPTmnZ4oL!R&2{8Hiq?SQ(p7auy7Tl-LR5 zAr(G!RWeUjw_{j~8se{ z=t187>P-hW;C5F@>=pt?EOnaD^wh7U~&r7^}5A z(^C#Db1}FvsSxVBt17QWb4*`e!NsvEdA9Y3ju!KLPDw6kBI!}?l0r?WAU{!+)7rYg-m7u7DyP>Y?)P%WTt1{HczlOv_Kq#kXLm6w?u6q2#Sp*VCUyu>NRau^&& z73)g)hGp)FWCc at -b6=24Grtu08!!ht!Ce_k*U`blaA{f(I$WHKoVs*}j`RTHqL?2N zNy-et!?YbB*(0r!i~W~)XgdM&QG$HWu*BQ2#LJ-Yz#KH(!}B>^Dk)4K2(FD at GR*Ta zU07Ic_4G at +Tz8lIbO#{7KxM&r@gEa-|jC&=m&YzJSG7 zTY1(&|I&p&$ch zYFgnXsmQSAUN9)Un54S3Mxnpc)%xiR6oTycTmgHcI~qkM-iA5oPYJT;!>!Jb(%REu zJSgj at VOe6YwJGB|Py~yX3uEXx0ZQ6CmR`i8gZ*G-9<;r#(cKU&78x{RHwaT*@cj|E z20)!Rgs*rYMlEn=#Fm&aSy$p$49YDsi;b7#L36_S`cqnaW{zr2Cz$i4FvDYw-Ym#2 zfs)`*XZpuW_r~i^@^Nr(Q7E*NDPX$vYtMrDRvKAgFB&}R2%m>BF)^kIVh}^Ho7xJ3 z!C|EUz2M82ro-LjQ6^ueQCH$-ND&Lm at P`u=eX_c#BV2+-`hv1xA=0a{Et7f!!Dbkr zBgn?rjZur~!oFs>Exf}otmbnIeJ&p91;yu&^%n*D91G5ctb2m27ko`eV0lED)GdA~ ztg^6r9hpL0Sj_{j2~p<@`MQTZN%;a7=oW!*O_T+>g#mK43Q&C>vbqRMGALY35j~-M zwAdYRCl)^7KfkEEX9b!JYcT|Q>rUGlI^lv~DMN7{W at c}k8OE*d(ve|nf8=Uv$G_!j z0N)TS)CiF-pa~aHec73!o|W8z%4nz@<>rEwC-CLkaFPC$hF at sn>+W#C-31Gul~`%| z;=DN!jYBvkP|H)$OzxB-Nbm9Q)APjZ_&Q9BgF3D z%*YkJ1yOf}NPkfiMo$pxFM_rEX#$~!e#eE*kkS*}JYN}y`AeQG;CWWkr$KA{U^{VR z-Ct|x=T5`Au#Hv-pOso^dI0(EC@^J|X{Cr5l?Tv^wfK^iLh9MbeGJ<^x*Bvj3MmkX z4r_w|s1KGhi?FdQf-lJ4%JNeK2tKD6{t6Dc3=P7?FdU2)duayIQSR(Qdc!o5C{ac? znB0$MoSNUN5V2Pd&)FO-1zP-|#S0Z5S0Fi`{sWoJO4F4XDM(u>HrLxQy2?K-^{l9{YFNjdr at b9Ef~C at z|h9 zP5v?d5_~1&AlVg^aqV%JadJd=C}K#O@*hYNwIT_e%Zj at c&{TL&$UW_Iag|2gvG6YV zJU8xXZXvo!W||hO?m$*g_SIa6W}@D6BTk$UHL5L95O>L~1=$xIupjKd8aMh!-Cf&D zCeP|Jt{b`#XkxHblk-IPhw%srY*a}Tn zWn4#gSlvUb>KFDDsSJ(~W#IK_703R+bjuqO*dnbl at O zM{akDU|HJNW4mQtERQohjWfkWu`k>Iy(lW^^5+*B1pzM)X at F&yIt%kv54Oi&Xc at w# z7CAUE{tMIZn2!PxsJiMPpAuG$>}`f(7s4vug0HjXeeLJt6W_F~%q) zY*0zU<1;2R{tvZ?kTc~!kYiCIg-USPC1wq%fzPQ`<%K4$?je_m^R8{OAwrP`!v-11 z(COd8eQqaA)XFmk`kbnH45Tag)03QqYjf5V|a>zV+f8guB(H9 zV1h9?S{_wKq5o5NG6tvN53eT*$y-A(`!Ib0ZgLtCEBrku{GoQu%C{QJZ`ifsfHUF1 zR9Z2Ud%+)Q(RIYPlf$FgD2on{7~7|Uc33MobVYIn)Iqu+0J#%n*UTM2X5x{SE}_V+ z*8Nc4(05 at 8&>;o=OxC>+W=s$q`cYDiDwfd?$9%|d851hmAO|p5kD7ix8M==`69I-M z8=}J*CZiFAtE$6bdaVk^G)7rT9*|)@X)_MI{4g`Hm-~obG7~h4yJRZ& zf~1nMg-y6!q928=kv7vykdsT&;5vGYVTnrnI|(}!Q|a)T+|&NyD#5$I<1hCm-N8b^ zOT1Po0iD%L^o|pVT5?QG|KOmEh_6OLI3_!^EYn|C9ebx$a zO8ClfdIBP&-y>0#95+~RLl|!D!U+a%!y=yC5bkG~6JW~ZlR=`Hw2$^?5Y-6WodI1BtlJzfJ)sxfk6>g#_dFWS{Nv~42-ESE at 3UN6@SD2>RN6< zZ8N{6KtK01kN}lTpy5JBoY;&Zf2|O`T2C^uoe<^!S%^e<`~SznlmA!YCAQ>C>$(3c z`N{v8{6Hk+Co-16gO6f4Xhn<~Nk-{}hY$g|HVbHsML=lU|5!jFtbjsT0pYyFc*DIs zPXpJy{lh~RSk%J=TWj?oE8OflGiMPZ3~82I5%=Tm2`dbNXeYq)G_CNKkdSAA5DUY& z3J)xKUZ{ceYMAE*uELve2puP+5hx?S1zqXWHO?@Q2M#2~Ht6H`*D%Tx!yysodvK?a z*4QxeK>@CEMz52Dqj&|8vm?MCHHIC_U3-H~c~&2{^pv z8hg+3s0pUuA)KhOBe(k!g#oEggz1mIMhk9w-hhOfZQbkaJ+j_d1nvF*io~nwsg;0G^UZ zj}y`<;sDrDz3EWC=L1^l0>Su6ZlxiVZ&13>;gHbsx#wZ3aCeQb-mDo4g2k7Noas=I zm78aoJj&D!qRScqt#p9o*Ryhh+;pu2dsgUR2=#`fjOISS*8P;vMcrMguEAcgp=j)i zds!HLoaTlH=pP!!d1-ktwk at V|JZ)E+gsB3(Z4JZJKbwh$2Fpok3#(xdDjzMShK`X^ z7XZeNl~O+fObM4#;t0?LfG;DZlysbw+73_wa0B4zcq!#6mr{EH-i(q`!zM_n0WngF zA1kFM0qmM6rQV2x{s6*BQtBDNCzGYr4uD30kS{-9b;3+XT(9WRa^Ym9LIlUBK-dD3YPv{Xo!d!89*%=R|J zWZZKY4$(67B_VXA2b98S*)TdGfVi4SZ>aF1Wpd)OA|s$AHlXE4MmIkqm`E at 63&WEV zw#JY`wk{W}3();3$Pft*jpB@=&s at 5rE9TQ@xDBKXh=9axz&bo`2@#9>oTqs?f{Lg{Bb*2bvC1*fg83l`gZ(3{PZ>E=5YfC9?MKk& zV_+9rXcFewRDZ(kIoL;cM}Q+~hD)k4ItmV{35~xHs$L>h<;Tf_egX98$Ucv_Khh~A zQ-Qf*;HrPRv;df0{FzbtE~P*c>h4oMZBk7sx^uL7oK z7V`SFk@@IqSjaD)Rj at W1*Cym*#UmOuq13ZbV!~r1!Aksd2c9NLia1R0UMjPrc%jE0 z1DqWQHy)lRxkMNelR$?*uJk+!bVg&ovnq%a6dIXhqkUGBAvu|$08GH=mV2gvHjy3~ zGgxf0-?iXdCIPad$3WKrPoyRqP^Gk~)v)d at lV`XwL$w+Ncm8vpq+QowwcstI{AKR9 z-+c4U^LzAz3lC*$2x^Yaswlj42LH)));-`te_&R$_9v*sTp=11F_A?FR~5}!AYV0x z6Pn{x69&9G$>!|%o+Z?^y`cK&s=2yGE7YBZH}EK&ZDK~UStW&$Y*4!-u=8a^Ni^bN zf_DqSVb{o at w;bkogPjLsl`@L#Jf<2iY+wVa8n>Myja`|H!U(tqAEC%0wZX_2>Ii-@ ztT!Uw+HJ+*%f`o>p zep3<+2?6MX0~j}?tIed>i*tzc(qm{IfC2&tK|cZzp+Jem(BFwyGY4MrO8A<&peuWx zd^kczC7VMc!i*6SVNyv^`a}AF7=KMk+Z?kTks0E}ZY+P3b(!&Dl-4F(_a`UgiKG~t z7VzL(sK250r?bVFzS6>EsBtOWX*_s1b(NIO{AU76x1Hm$i()1A=j+P;}qfqoY%#lH&9Vx=d%Hj^Z;s zjU-Id8Do)(Wm1ezyoJl96b79&{<(6f8iYSo$GszWjip2m7VvMQbOK52V5Bz;D?2gw z-cU_s%O_h%gxJNhV?f;N^U&vp&df2&%_Q|`rk-9&?; zjy1E3(x24WTrlZRYF~isus4R8`}_!=s=CI?=OK~|T9a&!h>idWMMqGuX0f&>Siid< z`wp^bwHSXyKwlLcwh|n63BtotXmt^+w8PL)BPI_c`uriOgPvi6?5Fse`VB2^_~@-f z#D`~!-Hk3exE#+jm|hUVj4t+e2YVQyxKIRWz_z{}7ok%?S}ZvjWg0!2BX|UUq{VRx*qIQBqDG54+HB`P{(wLa_^7 z0n#~n$%I>>!C_?^_S>#`4ga;@;=*Wwkw?Uc?wwn15CFrsGI6rOne__IFFIg>jkhAi zJO%Jr7)v)6J`yq~>R`ZH48mb&hBReG<722xw^>n*S8n49Gh2RySGuh5j&O>7;pAcr z6KB4xsBo4KiZB)m-$@G$D8NR5~ob2i(oAK!r~Qw z?tzq9 at a}0CCHIG2sfo{jj-ekEKD4LJD{8PQcQP6!7wiSn9PVksAti^~NUm1wmCIgv z?A4mR+OSt!_R43kcI>qSd$nh;4(!#Dy*ja10baR{x>8}7K)(<*7+(V*D|t+pogiz2 z1n>FtNcx399|{Nw_?|^ErfGi)1 at Eq9_b}f7rwh>42rX;CpYXI3RhuQ{H!tZK{emt_ zv`GDI+YkN%|B3$D^9oHrBA;i4T#Y*_ z%V|Kl1Uh7b-nZD^x8dZK-G>fxhl@ z at -HN?1e~P32no>N=cG?DT>&?Q4$JIJuzb_Ug$znpwHl=B-|(R=6WTEV33?q9S~$># z47$qa%3qkk%zlOT(p#2r<-ZVtY-s7;GCyhu&VLdIDAxTh8ZXd4!1MT5y!0^oYT*Mb zA5IHZ3_mi(9qEAMEMYHOMr9~^=@Vd~NcTH$EM2BOu75TqLDQRwKmLnq-cNj9F*&ZC zf`h-r7nSe_c;IL;w&Ydw at o=N>RD1=n?@aQYLcY_;w}yN#n$P6aQGw)FYcNW>%Zh5e zAB10e4yn(mh0wl4&!O+qd|Jwr

  • fg`*uRce=rl?UnDe6rC5r7jw6V%lLQ~{KK&ET27pr{vLF!w1?7Y(oqU^74nKqkOc zfMG1Y7sTX#0Am3r0;B+B0;~e~0w5pY9Kbz*X8 at f6dVWb!-TR==I1 z!T{>Np(rt269I++m;kNEdZ~%7zCjcHm(=Lj7 z0`LIfIzS at Sr2@PI at IJuj0J{P50L}r7`WEQM{&4LEAO`RTcpJb9;2exm06X5H8fC_*TfCB(K0X|{*eGYWxD8NouXM)p{rfHHwW~V33(9BC;Eb{1^ zF#zi$r==-pCoLSG96CECiLGUDu>xAtW~a{jOFdIDJ2g24DrBiMMd?WzZF*{ksP9Y| zldW%4$<~cYovnGZb;HoXZw~f>K9>I&aw@(l!IuLFDHnbQ)e+y_;->+4QSA<0P`(WFL+a000}O=n z0k|SRR{@NLay|5i6q2t5=uAmrDV=OVI{XCy!=e2w%rAiZWPpB9{tm9l at 09?dP_Bjk zc5t5v&=bm=Vg4C#zYJgmlyAcP-QhkJU@(;P;OYeMKEOCAH?i`M0&s@)>sa~E2N(+N zMXda%0lWcaP;UHlmHZU|K~TQO%0CXEE0jNE<-ZufAIcY5`OgLbg|^!VSESbfFb2v` zSoy~QxKcvC6^D_(7Qh$UPqXq*0)P<44xA7l`K1StLHPkI{{(;@Q2vCK|5AWJC|_sg zKNnySl#jv{$1?&%Liq(Nf9%r<)?duZKLY^dU{}h at A9)J(cHjv3h_3?xIotip%6~Ed z at Y!x7EB_?`zz4glto-Kyz`E=X!4=1&0m7mDjFo>ZK$lkXUkLCPw4Y<;KMSBgly}1w z=X(!eG?ag5cD*#DV!_7A~E8~d+mXaAqJv;Q0I?Ee_m z*8cze8~ZP7Xa5jPw6Xu++S&g{?d-p at o&6uC+S>o~zp?-G?d<;ts;&J$YG?mj+S&i@ zcJ_aQYHR;yN@&fYx>$2KovfXy?$#Wkv$ZwV)tbX|wGN_sSaYO8YcAzx&9QQ^euHwi z=7>64+fm)DIsDGnD<~ygz{@xv} z9kIVdXX`?yKjlo}%NTshma?O4s1B4hWl!-a2S~0QDJ#ke at +$#}ac0a*$6!j7l9W12 zqY}+fCC!-Ax*q>SW=k#BFPN4xd!}gS>C*_pU)pEPo0-(A zK4rEhDScYX5X)@X+P+VQC?iSJs?YS<&D5nQr9tfWAID>QB1vYUVh3sXgG8w8HCTFqhMucfDj at 66Z>XQ$4bw@{QZ`<r$o-=bM{0O*4BsM7;}=(s2+H(`%EH zVfLi-^m*wFT^Ud_d&cafR1Hir7h-IRXaI|mp at HCeZVP@gM$zrsQh~12q$CvR3=PaP z4aN{zf at u;ci-PB+El!_3OQjJF_4oH3^rpABuPAa_`W#Wv%oHF8j{ta}u{NN+e9+$x zpu3Ksug+8_steVf>P7XTJSiVaLIqO_Y6g`->8R~gG4(TrZ&l()*zTV*`>!MWuM_*v zh5hHs{u5HCs1gcKAFNm!(0&}DXIJVCYA6*%O`}#&g%pRgg2S=ma5+4V4TsNh;0QTx z91+KxBjrqOJ-=m6%Un1|XZY6z{<*=wuJErL{Ob6J- z9w*k!6dvyJM6^d8Hvh=eTS58ROD|vVR&)QSxlso%*O%!p>6DvNIu-1kGxMFs=`U+f zC9N7C&vChyVl!h#py0(Hj(lUeC{>auoE>pLXzG>p`Ln*baGx76`Z6#4rQY%4oP!;{ ze6jPOZ_1{9qpqGhc0<~j_ubDaRc~tJZ_Ca*UcDI?c;Vacys!0po4OU16;)Z at d0NGZ zgY^gA=u@&^`SFIM=LKIL&;2~t%7dR{J!RiDhf;C1{oeO7=M8a=P)+={$F#!0LCJ^K z1l?R0DZll{Kr at O}- z)yoG3&gFlUGIK2_e#Wo$QFG=@pO)fY<(;G-M@@h7aDz?Ck}o;k3+wss#+C^FD805P zNnU-pGpy6e--ORJM2F8?`k+P=thQ3v1FPh+94ypUgdaDApkbok~}rsGcm^R4CI z1X=YL3hnb(iX2Y$J*bM^ub(HfyPSMv%l&ERoEmQ>ZaQ^sK<`Zzdk*ZZEb9`uKW>HN zfx(jao(`LhSVCXJ#d3 z%^#l9^*5V2sSCPaes#z5l3~(2*M(=t{xoae?IVqikMiFS&OhAc%KLk!nzmoPx at _Hr zZ6!rjeiNSD9{+gOu?w?e^S=7Y=HSTi;rqg_dpcG{bno!Pv$5RaQ{UkQ6+fDKJLdMR zosZs69lAJwcIfK;)6R6$CFgCuIIr*Ud#VW=7CM~ejyb_^-{CMMKY59Hc+L=G9~Ot;u_eW`5f5$&A{~+tu0*>*iYRva#Dda=25C zewJ-|r&!AR-LWS&xV)2lZ at 1^(C4SuxIehy5#Sb0xul#cO(ap>^Zr`xKeDTuCQTHxC zZrJ~mDphyA*N>g^S4{4A*t-PRz!}TJ?6&3)DdIV7k1yAboE-Y z{cUNTr0Olj?z~+mKRy7KEu%Ce0?VI|^fAG7=WxEf)KS=la zdG}54MRhD1E9`SkaVf2S(T72gro~k59_;e#!M7?8ZgSt4t+S5X)cswzUDT&HUJTmv z$(iB15)u~v>YkEfzCAMN^5;&Ie*8k5z2RrqEvrSL`@WvGa993UcTJCft9WV>>uwb% z?K^q>o81WsHCsYMJkHLUH~VGUg57h5`aha9P~>H2Yd_b|z2np2p||(hCX~*PPJ8H` zG^hUg(}Bkh6%GADyVl(>Y^&{>Kl8S9Icm&yT6}9)U%yBD0?dn_X5@#N)Jwac355C^m;oL at J zCp+qFeAv)R89n_)>S at K@h0zJej=H97-F|hXG3O(vjcetbDsMUOI$L(}#ogL^#eih at k z?_SHfw`G;v8)v`vnffws;174j-~V1Q^1vWn$1N%Q>{fm&4m)@Px2Ju`;B1}(rzU!9{On6)K^b`{q022%U79eE3O1?J#+TO z at Kw5Fwrf9G6rH!%Kk4h8;hS`l4!bt>KK0_DUCx=^!tn`@rZ}b4hyFP7+T7JnMVjD_ zlb%}j33^bNmQt7%w6JP)AUF*ii00^K3V@$Z2hB>^~?g0vzU6+|-|i8+ zdp&lw^?fsRV9$(&Lv0V-O$+;@Voua>UFbUt_a)32SNYGq&T# zAME=W50$5F{mc+_EITxz57#!uuUpAT*P(hRCy!B^#?RvJie6UmVsXrhGt(n_o%CCg zSl?&UXJ0$*zq!%%o9DuYfZ;`Rb1O at Q~PvT;`c>Kqf^(0r3~4s(3*yKe0!IzT_1I{nD3c1()s at 4uQz@f zmiIw&_q99v4_tNpPTrX(+l&=8({H^j==12;Ysc^AxinRL?Ko1ms^7AGYeyatSEMz# zo|!EP{dLqk3tvt?I49|5{iJ0l-?CHuzQ8Z+`QF`jxpiAQZu2=ia#i|EF}^uWy`?VV zq+ZVE#^r}v-P~zsTT^t#W?!a}r|&%8Iyb75(+83Zf~)$E9Pd7gahTcI%}%kdir-<- z=N$q^$J?iE at 8>@H)cqbk7k<%eK#!?Czq23G{nKd=yA|F3*6ojjv%8i*@$G2d^t{to z{q{PqjmQwXObT%A$|+VkHg&fgu^Gvi~Qo9XU-*DdrMAGIL;aTks3(<|CVHx0|i9|~XI zneVvtjp^qzcWAN}uj at H#(dn(ccV3<@U9x9zUdnqR%jVvC;Ww{(&5P8Ol?Ufcu3f0M znlM!5>-TgvfB6s7N4n0Pk^HUaw5Y=Bsh2CiO8WWu%$Y~Iy_1cz at 5~aNsSN9~&2`MU zUW)L=+O=bwX51Qo#?F1*hleLceEHL+$W5P=g#J)xGy2&$sjN`^Zb-+ z`-`>XJNNy at _Io4{-Tz(r`4_d*>Zd-ue{YECQqIHbRl~onIUYazL0xXAmt_|(G<}}( z(W_lHF=j7ew-?>tsrqwN$>)vQ-SG`!)zs7Fx}qoj0<-I!V?!UW53;M@?s?{q7aNSv ze>9JOHZ at _*GmcA#21CH5>NJDzqw at D!0V-Bq;6$rm9a&C25cz);@wMy z8%)jxJAa5gv*qLmAgNR3kDcvLX>3Ez2G3pjW4B8M=La3JIw#%u!`g*SbJq+W<@sS( zkLq=sM|`#M+vu4eJ$cZ3!^x~W>l at 1Qww(Wd+2tW`IjkD}il!!sQ0Q<{@A^Ap_(r-|?Wx~FH> zh3hw0M4w%kJ>#n={o8I`-g8X9vT|$1yFlKK|61_*&yYkqSFxR6t&lI^sH?KW%VAZWW-5vMi*Apk5 zcsOiRKH7iMth`*h-0qv-e>m7N_M_<^yjgeat(#Nk^gZHN`Pn0n11DFF=P#Xk=lDF% zdz{ML6IaLnRHc66v+(vErEtc?EwNqYFTB4rxoi=>nBVZ-sPcj(x4-|oY*sKoUE6Qo zxgXP(f4{-i&3VwDhj)zpyu$6h{-*QYMtzX+#do68J*P&$!yoa(n_DNBzwdT%mZU=k z_1?bOe)1s>Q))lDR~M&$@1tJ=FTA%h>A;=0f0{J at gYzRjd={=0-hc4(!if_cs~$>K zC!!j*HF(yQZ22f`pm*;{<6}R+_iWyn=^)cR2Aqdhye=Qy}`+jC>Z^2%BMYZqPgtnZb& zj{CfyBzeszx}1?i);^rLZb0NsCO1QsUem7ofjvm){lj&JT z4!yhcqqjOYNZ;js)_+8vxL5TXL5pHO{-N>?eR at y4kK|C?!^8`}#OzrnAAO~3tvTfl z$#lEW_pbj|{bu>Q at 4ugR`SXV!dmE$HOi|u{_wAt*-`3fE at b#~$KE3#bD;?*4_4dIX zccsS*S2kG>88D{H*l~aS at N_}%H#a(ezG_jv=cXRlJ`#nWs$VpCcUVCI=jFvOlY`Xm zi5s6U_8&O at qm5edJi*?sIkyDpd{_*~W>A%$+x;16O`*uZdRUdrkS}3K;dn2#n z!O+_|A1G&dPiwr|oA-%M-7>+C z*MuML%>Qm+sB>4pJ`29g(k7Qy2|4dfeYN|1`lqKdPWOJiBX;ygw at 17Dzkhi)(OG8m zd*p%{hR5fO{X%YwEhtPF($@rnGQXhZR}=abr|vf_$h`Xd>5_R@ zd&G6vyY24%o-R*UEZ!MjIr~hfeNGF%jo(&u#J_YIC+pS!Y41D0np(O=hlmsv!~zy9 zQ2`MJ!Gc&Jbd(;DA{s-o1A#PCDC)ri_KFod7Eq3gfTAdfioG1gidaxQ7CaU#*s$={ z?7ag4^}qkU-+k|U_dOfY;&ctKQ7g)?fX!Aa|OV!S)_Dxu%|DuDMu;Nxq)^c=vf`YE(eatei_zFSk*y z;vN>f)oF?UVhqLW+OBzR$Q`gwKj4V2_*55JOwF?Ayo{ln`Kz}Z-km=v at m|4>hc}=1 zSbME}zWzb){zpUaIpioad+B%glTKkk2p%oh&P}5DsjhsW+-hLN}d__8|UzuuU zOq;D&bK*nWQz1l7`I+{Ip8GEKv)YsKIe-Jkr~ z%A0fFVETFgmQzOcWw8D%Zf#_Az72D3NOZnAQ#xn=VZjak%iPCXCRKbf>{ot1EvGcC z_t~;t2g3G`?qqYoVAi3d5hITu5$%0dkjz|vZ2!R)2OqUj=3ZO>&rOfvo36$0)4pqA zthi^A{5P+4`&ImrDF))0F;ip0cRe<|(t4$S-KJJ3yYC;mn{(f^UFkYcZ~L_#TJNHT zIwe0oMTShANkm=jBC?+%iPd at bKolzFt(#a;Dyo4S;VVSV{Y at I?%d!*vU3aw}!WTU~0{%UV_Je7gIadAp6MK z{jJ$2`J&U>f5g|gjSt^B*N?U4?78xVdRI#dy=tqg7XDpResNE}Uz_~wB%jU6)=TH5 zb-OaQqqMe%H&~7j{t7qTygJ2f+u|+8fA7q5XBKD0bKh1~W>&o~eRi at U+3e2gJYwR+ z>_1)Ix4e+XUb2jneHRY5i_K+nH6y3$>OQ7CL42sY*WPP+sDYe%hc{VU2gIH9MDeShD7F#3iKfR%YiZ zsf}C|U&+33q;O);_H>c){3VXJQr8%+ttd$&=QqVt|+yGz-||9nky at Ars^j~?il_|e|X^H6tvQ>Au$ ztD)oAMehPVm+Vg at DrA$Bs_mXVegEUf_mX2bOH-#`x|lvXd7*vn`c&P*+ at hd_T|0^4 zBa_p{^-jxbrJrAW-YEOxd`|U5Kld7up}5 at fFJ+10;`ib0UH)P9VVn at jPTY=X&0K3= z=CRcJsZIvUKV4*+k}`$0uxoU9;RKiXs)*Hv5ZubwTq4w#? zcI-vjk;_-)v#;K-Ic;*Px+bK$Wap}nlQsf)NRSGjdm5WbF8YZF2p9jx-RqF z^Le7Fw9?(mMo?j2Ipef$I&A-WKJSU%jJ)?xOtVUM*rudL_1lte@%VIh!S{+SUv9m> zG~!Ct_h~b;VvE-0g at 4c6qCaMLio=Wn-OO@^>Kec8VdXwZ*DhY+DXTmX5L^0Ts(Z3M zZ(?5j#o998Yn4yiez}x?>0w#Ql6`C1k3G1gPwP$TvU4egtOYIlOmy$+Akwunc06Ti zXgDXzFU>hAD62(qV(oG7$cwXPIh^j9)~9CDe#4!c{xn{5?@16c{pM#EUKSa-?s6jg zwpXQJC;!@{@zctzS4UpzcEftf!VW{$6bAMztV-2MFE5>x^!}v>QL+vH7Qy!fRf$^@n}(bcid^&(7W2 ze#@JMj+X|nH2Y5ewxU%MGpt3*4GF`&I80Z6*FBw!B`>s>OwViSXEMjILqI{>t0R{g ztetbKO>lLke%CL2z1u66>mcDWXrMhfp#<5A%qJN~fkV^XkmYNx4>eH?t;9}ZtOplsy% z6-!67{(RWc_4TMRb5mN6IzA$BG{c{;pVTRI*v3DkL+_llAJREX%P!zkiW93xs^b6C at T=*_3vdIxAxz3Y1)K*Ap zmp_lqpDT)qe>oxAE|4L7?=UoS-wZvT*w~TVf45-r^AiC?X4wrs|LEU>-Yt$qJrpkS zEW60`GTz#09J{CQ*i==bUj^@*Z#Vsm-ra6h#^%|qwSJ~t=dkFK-LPO$zO zh(8Pcr+0i5P at Hr#{L%2L z2~75bFu|+2p*!Z~PJEF%B%*+Z86s2^J&=TQ%^}QAbNg17 zp!!Dj?SnV1^JbMs?$ExPetGcqr?Qx9W?d(qp7g`$)W%hP&)l&}I@{UFt0ZLnrIV{i zeLZn~_O|2gs#ah0*|+P$veR46ou78*eCu{^FS+U}|C%dyxpMq^*UOB<)~Wl}I4u`{ zi(k>-*=FT)%Pwm&$822758A!D_doAeJ)C)ZOVQcSo0Ill+33(=&8FJKt!epEvvu(; zJ8ZBk9J~Jg)jyUj7;3wC97lJlLFJ at nR~88u&fN5Jk at Kg!3$(pv&p*>AKY2ZW{_If0 zV>5f?Je_s#&efEamxAU5Wb)>9>O5lZO}RnVqtf(U%p+_66lh=Gy+iUP`$fX^ef`>x z+biAEe$U=B<~!fc>YO?F#lRh^;JA!Kj;!?0{Z4Hi;qrd_^zVOeD_*-P|CFNifKHcZ z2c32nADaEwg1o=(w%Ok{cVwqN1el|8|{iJ79Kd-?P2n< z at JV-y(}ujl{rQSkApoWe$f=AF!FB)Y^OOhEj-QJ>iJ=$2C7C4CO{-?FCj>AqGo z(vN)i=)zzzryJEQTd~Wt>eGgfp`-ikatyWWzWm^Vt)H%UjJp!E=fbYG#WQp(bxuxB znUpTO_Ox54Lp50iVcy0MMqMp=HbvhXt3;dJD-x+3Vc(||6!In;zJ94VebZawz`>eY;U57`N&FFtEA$6ssXU#~9 zPc4$yFBhZ^be!LBW$3E|u9Jh>eAcz=;j`;O=G!Yreyn)#(%q(DLC}UyQ7`+-7*pPO z7M}MWSaJ8uOk1AYv*1|A^o`e(&we>!AKfW&VO#m*iNh{NRQhN82Gu!ztV%P_UNm1} zGOXG}d$!Z(qA`6p^?KgZY+Y~yYth59eS;%%F1!jmI5POj)kz-yNjY^dyWET%*-Lb1 zp1c0JLC>GbmM)!b`D*ixETtu8-NQt$Q@{=rOGmxAz{9*c~o~mUezmomqg5vy!kR5M(S9f0H at qO>`EVp)(F2(u0*17z40q>rx z#S;E!R at Ik*i2&cH6qR%NxVUt=>Z2Q5yn^Q~KK9U9)1{ zP#c>c{uV)p*KMw<__lcBl=ed^P2#icZ7#Q4=(W3r<5Rc7v`Ds zx4~o5M6-2z-5A4lJ+tWYpGm{AuH2fza*&*~m^eLd!TwVhUf&AqeoI=pHMiCKjy)ca z+m$%0!$o1)?s&tz!zEiIw35yY-nOccuh0SwdvtqK)csP{O`m1} z3Ii<auG=tgeOL?bUx1;)u<_JAY;FlG6oOm{5utAL5UN$eI7%n at 1~o4UC~Cyda5jjT zl-vMDAfZr!V4|V(e1zh$>;P9P7b+87L|ojrPYCE;RB|~XAv=vb{6zz%rk#grsf at Y? zBD(F#1XsLwXAo)V%CgJ;Yg%Tx!zTO6r4) zMTgpwEum5CD`)}I5D{Dj;p&3EV at X4NUdspML$O6D0 at p!h0zqJif%9}V2(3o0LWK<9 zirLVn*^D4LSE9hTBGN#F?rHfGL~H|&1#UNJRRIHHJ!#QYhJ{iY!7 at IOs` zbuNt7GL^@c`A#bkBnCp1lSTw}2eaJ*)tX_`cIy`zgBy?DYhlX)LAgjpcr3PL;EbON zdzs6)%sJKv-!FR>(juTx)7h)XtQ6b1t=g-2ISZ9AcoFiUA#ABg$aj{j6wwHIxO&me zn1I_zI*xHfB9h~rpNx<|2KQhZ&IhOndE$7kNJU@}io!5AiAqf4Ol^z<7;`ZM8r(p` zA-Ryvps6A;gc1NiScu<{r>kMPj%WF+n~CHIJgZ3LmO${pE3y#V)6H9Lv5n6{+ozMrYIm&VvyKLoFXd>We6yP zMU`5dIE94HfF+2zB9W8_GqM(^9(;o01eHx<2(WuY`3!}E$CUuZDlLu-8ZL=LyBKnE zlp{0|V}aA)GXzTL8;WEI6kv)dgdu>*M1s5-0v^^3LVgT^KtyVegK5ap4q6}Ux?guN`8DP>TwJO(}d&}+mIz-$MSIEQJJQjqXcXd#cho!J;_ zR!~XAMI4SelEYKUIbv=CLOU2!U at R!nPUr$4tG at GWyA#Gru7KhYob7&6Dp*j4|4){C* z$J+ay5dMF_Z+TQ)L&q;6ehA;&bY2}W{;50)AIJX at K7O_C9)RKZ(`|$pzwvZ2#Q5#3 zB8c(ZCW0Wwf7vh!V*FU%0EqD$o;&7|e_)8TA;xc7{+#QCs^ELyg#5EXGL%C8wQ)oK zIOJP)aYEX3J_qti8s!@ye^4X89P)=cH{{t;fifNzy%9b_o?NPcTm-dTR7BAG2zp}^ zfp at 7eL&G%rU!f6Gt65H at Gy(C|y9o}DT!7(c+wt~CBa2{m<;bN{nDAm at 6-eb3GJ*#? zV2(g4;uCTXtfZq6MZ!@;!x8}2VaSE;S}n&35nX}GH!dt8v8zpGcEn at f;iU|19UpNr{omcPF%D~Q#YpO2ew at Gtn0 zU<7;42nDR8tYutYEC^2#fe>8Qc`3Q|ZEseo+UfF^Cgo%nSj1ab=j zdv!uC;PMDdFMn*+3Ucq;h+EV1nqO6?P$;IuS4i5C##zp_IavP?LNXUz2`od0-)HEzXg%TBkA8K^L zofly!UN19Y?aKrat7LTDHn{JuQb}JW6WblrKT#PCIfa at Xsbu=`MZ{LZwiq_U*uZ5Z zqB-B3Pp#4^LMH8Gm;feUkAZ+cwpz8zLB3L&M`I2GsY=2J5ZORExgVA%;>OX)aq4;% zP&!2g<_YSFj~2q{iRUWFf$`fa)O7%@uz?)#<$wwhdL-L0sU35Zu1lG)YZ%esU#ZII z$VCbeb47#~MS?9C{VWRw)3UyC>W1~x^z%Q}iR}?K1|s}E66}Q)xE)|-QX3oS5k76e zC6o?G&~Na0WMP93P)Vi=WlbcH(GjA1P+tKi1pAbbeB^|6BN}Q9qd?e_B;so8wF~WN zWQmdZEQnM{BYLR-gkr<=5 at 0(91xiR{IT0r$;<3^4qOqMZ@#DEt0cGorD}bFCSa_6T z0Fy`Za|RWvN5L;FKEA=${S!HU;C{p~%-u!YD9E!D6&&!R^g)S#BJ`TW7K&x+qd$_y z9X6HZF)yUaV?Sw>oGZp>YgC<@2f at f(Va~(6pc3%4peDSj1nm$bHPSY8%(RqaPfXf_ zpLci5jUH)t zXV8isuiy(rU}5TUipPltrJBgnoR8bgCHoH^jN^|F4Uiw3@@CYj4&~T5oJbYy+JzDh z2XMWmk|>V5Tq+(f74rR+ay315#!Kl4rVx%lSFRv}R5Co%kur9MO88{GWZuP{o)$U2 zL_Fjv1!7g=WAO&v(QtNCxEHA%4i!WD_{4WpYnZv~4b5{TYRYZVg%%@x-1 zLK4|VB#r8g+ZZ2-b>9db*$%N~1`<(BS7#>K^byPnB=JOZ#b`VSxJXqZKIy-}rkSv= zV#bj@#HW%XZX#)6YX60800s`S9aLZEI3kg(abn}T=((O+ra_ymWr?&$9zJ|H%rJmL zQd0958wMDUo|CMste9SnYy_WQfcG#D8)z;bh#TNJ!rX at mc&(_qn at EE6Me26o!wRYu zVKC77Qo5sr7!S{AZX7H}8lEKQ^6gE%H`lqXr2_y5zq~ov%#G-EH6SSanfgYAacGGmd%=Z z^2BN|tRrANGud=SYQ0BjEIh3>e6c at yFb@6|nh$d&_!_y|qyHoc?C%@topK7K&s6&m zc0J}#I at YMrnief(TaEj3Sq>9=rUF5tC53S8_jok3yvNRUHWp8DvH9)So+r84qe4ic$^ z^g&#eQi@~ni1-IU^b1-<3xPvVk+8>7a`C$n$a<*h0zrfE)~Wst3v^ye&r9k&Jwf32 zFM#6%D-uY_cZ-p2Pzsf#zoJZ%bpIMUk<-5 at s9zDmBY&PEaY?U4(@{G_`nM~nTYybn zp~U{JH#15K!VM(fr2&fI!<34_SSKUuq2TjKA7B%SJ$D0tK6ym1_CG(tX#uMwjZFsQ zTGPkg^?sNhjs(9K0^6V#H(Uu;BvZX-6%u$^hspT=4o<6j9P*_f4duN0c19BQ6{7zh z-&Nn&Cf*C$qB*2VMPgW^DFdJlFxqibct39|G~nv32%=z`+ZM7ujcEX}f at f z!>SC+p_S%JnJIwTyYUvpQN!QBP!I^^;wI}6DCafy88BH0Nc$%DNH$Ecdb~i#<<=_F z7T_8phvfoOq7p}fHA7|O(SE(%%cyl2Q~gF1tWd5Pnn>!6+(Xr);F{(52bskBIW01g z9v})7NdMZ>#IJGXpuxs)dTzz1^iuruGiggGiLV0xNxv^f5JkQY1sWpcsoQP|ro)WH z at 0j7JXG;Q4&axH|< zd!m1WYa{#)Q2@@whg at k8!&VdJK#cLv{h}Tm9{$8%3+Zbk^yWA4pEqL^+~_xOCcteg zsaFiEgTo7i(lzjJzl7E^8uAZcBNVQYcY2FZM-6;S_~JedAh}R?6Qt|^)L?uc1$y at E z8LFtLK(}t)LPw7tMJXvM$l2K$pZ6j=J3G{`Uq95jb7y2^WQ6qad!Q at oPzH~pfBjzz z|G&^x*VWMxBs8vdKf&u7(Lw$P71iPYI<3F{3 at 7tyx@sz~X3;1#g=^B)9Xy8fbq6yu zkJUluAim;sV|XTxH0izuPQX>w2C|&P;TjegPNpYd_>b4sWEw+oq)GRYX at Ti7j1V&3 zmtoY=2wxGhI0Nt>uSvKCc|{hD=xUwD0@>F9I~L0>JOFGHUs>nR99aG9InnGP2@?L-Ve1+{=jxgrw?YTZ53ae at B@SY29{nw? z#SwMEnrzIkenil59XTMVuXijegeW8;|$b>YAwdBPCM}xl(!D z_r`RT<=0X1YsykJ^+ at H_?nQ$iY58?O$e6r-R9h=$Lk+h1D}HpX4g5UR*9O~c!q1r0 zQ3f6XYF;!a%+(~L-Zq=?Ye(7y4EAs}KYA39{5%5ee!~wn_!gRQEq>8I${YNOpVzl9wDiXQLZ0oyYyTxbQg1kwnb}Bx#``}0 zi~iALJ&O!uD*|6}O15Otp{xkg0CJ*k!8G_5=`W+MVAkqSRt zOa4I!(((Zq6TVznJu1i)f#gVt1dW%C{(qoW=o9LQs#@SR) zZeV;e%PcW2#^Tw zzYHXfWk5;4v1YiWG^r9wZYn4x(1=D1X6nuIKZfR`d}N5Ko64lVzYEYXXg4+RW+VSb zTwQ^SoNf`;Sz;3o2({4K3Uzdbe#D?3B#-3(wA`t7ZX(GfNA{Kstu z6*)O;>7qfvk3qI+CUPew%qMM=vOH{|Hsq(C>VM-n{RpZtAg%M>>}riR#+0oZNWm7Z}58$Kw1*WaudkX5WN6dih(<}0ujU<(2E at Ej3WE2fX`siKM21G z)UK(e&|~By==3G6pWoYFQyvo3a;5Aa&koU~m8nP_YI>M| w?V00$rmbS*8A>z zcX{`|nF+BIR!~BUqC@~zD at 7Gh+($|M^T$U(QEt8Vxly~EPQFkeh&lN}JUuH*mXSGc zX6Dp6vguRj&Yh>1O-q$!8s^Go&6P!r)yU?|n~^%m)wP41$6GC4_{nJ@*h1>kn6aMuk+=vhm3;j{wKpiA_%U2A(u$Mg&}IV zo<7R;ThKU=T)(@ph{v1F;h8m^#_|8tT-7RyiV=vYipp15e!AC|>QwC+un5v&jQTG%aP9i`#ZQDVSauC;y${7G(gRbS at A&@P)SiEyf1ZDyf1ZDyf1ZDyf1ZDyf1ZDyf1ZC at K3YaE zcQHMXP zLw_BWX!TqTc~haGlj*izl1S$)RZ=>8>jh(pORZy~PGG%|l=PrjYVfA_!Vp%^1K9eu z-nC83Qin;A24>>qqcCuQnFc8qWx8^TsWNcLHozxsT zwJ!x5WRkp_1f`44&YB=I6~cT6al`2B+KyuAOPcTIn$smPjhYR7Uq|ShlvMKpWTBD1 z1C|L%nMKv0wi>*x1~04Uc3i>iCM;5`VFfosKG@)4aDwzEBnTGX;Gxxtv{0}C3ScER zkyQs8VBIB%I|v8=76z~Fr`2k8b{eba$IwP&R*9{Zj7qF1HFUvtIDL8 at x7GrXcAZ7^s$LXOSSvNA zHc at HDMI9*Zn{Ft5lK~Z at s%D_c5HDuT0O2FyU%A87(E>Y(No7Y-xx>}bLXpH23~9+B zZBJw2Ad3sqWsa?v92z4N9)nVEVTI(-NN-`}0O1+Qp|RbB<-*uHb3(NxqH9mH>Walw z_0(!rvpr!VTsq3EYP6NwK`9g42s6wH5l_;0;>u|mtf-p3HlCtDn7F1^&nlGkR1eCM zXOAUj6$_j<22py2S=GR(8m#{8PUr!WS5I#`qU@!v9Lt&5_fB3>_d6!!Q*lme0%`A~w-c6=F$RY`zxnKdAsbLwvkE2%B5P5(sA-pCC0Y-wr(X?OXs}Xt$;HHWuyceIMaQ3q z2A)1#ZF2EH_Y<&z&+eC7hX&Lb8UZzwHqjuXX++{#L5#RQfL22ms67w)jo8SdYI at c{ z`XnBQ!IKWc+Q67wh)4dr64s$s5nw&IxDY!vS%+FZgJAASsNXLdOT{B|pPqoK%wM3A zmXp4_SX*D-K7kI3o-Bk`V2UiJMqEK1w7?Nz?9O}dc0Ev*D)M&|o$+nGKD=5->B0(rjln{c#BxaUraXMRikcQPr!_Hd|D604%^2 zfNC|pqNL3-$Wb~YNheq%dK*wH(9#RHAx-*b)ai(NGlk;TWJzcoN9RKWMy$5FbM+Be zpU>4>4b at l^r-mxAnwCRVZ3Zd7Ldw0lath1G2OH{$N>~kbq|%S8ya_8%s|YsK>$_VG zH%WaxsgL05OR&Csu%SWUpHw!GN;y<^QPUgRu at ZOjkrvZ=5LQ|QGga$QeYM~hoWT7E zjMf^g(+S2AEM9;m1T~Y^{|ymnX``Z4??4)gVd$2O)pH>%7g%FCv{5r+uAWP9b*&^h zDTUbjxHwb+TzL!hp$prx#sgL1D5?TVAo5zgl*n}uUg!fQEph{`0;MRbo*6)G5~n11 zP;XI5LH4L7v{)`QmO%gIsKsDnOQcbp#}EZq+&H83hA92SD1FZ;iRpL9e-^=_tV;4$ z at qR)hGVM*tUX at hK1d4!+qH1X(lkEY5O$z|IHP9dEv0j9>iL_m-g2^d0Ybo3)kQ6oN z-Kg2`DKt2>Z|eNH3c9|8Ot95FYp3x<=sO|-SGWfGoH5r8BFmL$)6AiC71pyW#!;le z&==jN-Y`n-2W`-lv_&Hrf3#Su12(OI0xNivOuf}J1kz at Q&tiaSN#;mVk~t8QDJ^Ro zP^b-7i4S5 at AE>s(iq&!8@}OwDqXSn0Q`Fkl9z?`*9XA?ete)lQAvxre+U7;UjS#5w zt%scui?mR-+O}=N~jXKrmLTb at z4j2p273Mp`9 zDKC)5Iw`QXo at cKMnFHY~sGd&1G+Hk*2~7-m!3{dfx58J|G>%DV^i8N27LEJB_wX68 zSE_nnRim(s%MmOggbSRV0u!ZG>qIampCXtwh((UoQx`O>c-|xv<07XlLkU z4a64KK+ at y{iZGIHTTm%%lZyBIGiSnmq&ckn~Zr zMbWqh9yyCeT_)+>q0EaeN1m{sb0`*wpv+s%uEH!PlhpizlG)ZqgH-#0RND-af>(e5 zYhohd8U2)Njrst*Gl+D8T05OEkzefACTns^G8p6B5>znGBInkLh|AcZ3An7LyHa)_ z{n9enFO!>yy%%wwxFf^}1EHZtqX7p8;t18pW#H(5^1&`*Xs~+9NIQwCi8JD%=u$8$ zDFi`^V!ox`E67XlVTt`XPR$mK=Js`oX$$(Afw$mH=J5S=Lk6a zUdhC|Xw~$GT-N*!3Z%7?^g*lGYWiy8%C*cq&kcx~oI;AQDYzmKyBCOX!#h8U*d`Zg zD^qqA=FM5J`2*3c>0`l&?Slk}_bxeTJVo3tx)zuV1wK-o7P8n at TgO$%NCip?n=Yns z*qZrvl&ux-&HWuq?HOVSnFDe!DIRt_dzYojwu&Nqv+Nn0Dp-k at Ewut#5TYPcb5}rS zj3h8hap+)J8~wmglwXPILTh8d)7eH!Yj$GqZwX~gC{_eKFb_ocQ>!JN63Xo3fp|Q7 zBR&Uqf~whAMG8>*h#k?eBci})7Yv8=q$Is7Q9TXYKZ;ltwl7w0z)C8C?eqwwiJj$0 zaWSPN&kvd3TEj;`3$QU>pUKfzSCn!qk#q=`K;JDVh|+t~+hG|J6Too}#7699sDj`W z$)&gh4*Fxh1>LDDVwRz`3CsiEO9Qq>#vZNzt1IgYZh^3fN)E~8WKWZLPDGk4fmD(Rs zv9$@!1%SbWAr#};_ezSW4mum?I2o&5jD^!t>a0Vp at QwQmU0>d;jbxLtu9oWs6nB!Q z7eO=Jwn$U!P?~Mi*iWq!vR~dM=ULoN+Cm64ZpCe4RG9f9 at C)-8K*=!|XU|1W=p|`6 z)6MPt7SlS6%+*I>yfRf2ZY*HKNg<5C2~Bb+p6uYRinbQ_i#*DvV;0r7{3a|r%G-J= zc&kjHH^wR!(`K~P&`3?(FzZE_X-^Vxx2mzT)gb5nxEg-99TGuII^UY at 8$p(f&sr;a z|2Vg9If<|WE+ at iP;i*KLUCZ%1umt6{NO|ZyP#2e|CPMcaRv8Or>O|ZPE^@BHH9YI9 zH+B%X+XV?VD%d#^ zG;Gi1+(O(2LDkOT=}JV9fOoc-Dr1R{>9YP+f>y)c7{RTsNMSWJ>af+f7=RnZ!r~lx z5V0J${{r*MSpry_T4#C+5>yGLNhIpnOwKYIl5DpF;^O{C7NP2>%_1=M0fmYxy#hje z{m@`lqkeF(s!8vssMq at tl_%Ps$jZ1A5i5jMc*g~XKgVL9^C_S-IUTx at EevG3> zf6PYDq+`uQ#2jlTE#z3Uh4MLOvrx1bm#l}Rh)dR?-7>3K#Z^h(N92Z$Sd#Z1Ni<6G z%p}ny$;%;$2K^g&q&6Q9-Cm;`k(=k3#w5j4{cySt7Xao)-^9d5a+sNbM?@R({Oe#j zImXn&bk)|O(5}%~DuwMP_bJAMnZE)DHsVPXgpnKl$hB at Go|rKzb|aohfnEv0$7op< zZ&(x`GywrtoggvMqPhvOE2>~GJiN4e`Vr3#Q~v0?+nUr~Zq_(&jLOj22b+<8LP?Pb zQ|}15 at sQI3VoPj8VqBt5l$dyM5>T0l$0-yrLQ$p+H#z-qJnIUAO at -)k9JT at dz{bZ^XIs4 zHNELL>NM$y4kxs%AT9A^iYr%xd1J|G3Q8Zn?l|!)NQto|3XhBPS{3m|(R356CubM6 z^g at n4V~LDA3~p2h6sl8LiONohP7;^xpMSPE*rTxzyz7 at AZsrJ64w;iDg-!V^!g)+FI7dHjtez8_CA_T=el zIMzasmM6pj0)DJDyQ+^hvkQi{271 at vy}>5VwX%AiAa+MdOby!27Ca~b^sZxV=Hf!; zB2ymRbc|T<<_T&4N0ZS$V?m~u-}AoCu3Sk-WI!-qp`ebE`w)O64Nde z>Hupnaoi+%FGBVpbrEE(6rI*?s6C;WhdNitXtVGLK>}~KODLZ1l7jIkvEXrttw5`0Z-?-Q$v{4+Uw4ZIE8 at t`M=MXZI*gSjCjP?) z>Vi8II=UWeHSK at 0o%*)kTS-e7zNM^vOWN*D5;l3txH9=t!g<@Qe#cxr8}$&kW%OJ_ z$SoC8tFu#U*+rb|gt4=injcn4*Pm#8vdr(qwVg>lU2%fnc}aaz(*Jaarn#Nig_B#e z3gRg|A_e09!21}@`=|$={E>E>2|fNfn?kV(-%`!_ZLn{HaXHb#XWYx1xCLQ7K^7*W z>8 at Q!Lcf3q;In$FwJkv(+4s?H4Gu)nGI+2gz;DJ)972e*C|g@{h9el??z~j=AJ0ou zj<$pa2K#~yCvDDu&@;FChLi0#_@Lhtb(J?o;DDFz~_CYepO_H|* zu6UdqPh6rT<6qV!LodQ!EsD^I*81S06OtQibiv8CQ59KM*rF5JH4kwG$)SHjlTK(+ zm8YmRW?aVVT-$x5mznGg;OmfNhr41CyH{RdC^M9BOSlTp+i at HIY*o{8rPVQ)ty1+U;;$ ziEVEqbLH)W+*FuCfkgYQE zjd|2bu2*N{j~P&C5A7GY7{tLOF3GY(T%4>fa;fsbAx5fgvrx4uKY24#akx-h{kh|10ZpIq==Bd_Q zI{Y{VDc8^yTrph^*93M$Ab-EpgAIF%H(2zqu|GT^cUtILKe~`Kdc)SJH|xzcieXoC zjl$VoB%yzm9S&8s^K(L{kmH>JbOGr*obRje3LM>zOT6M#`|Xsh@^KWBjd*vG4TlgF z&$>BB3LkR%EQ-5{;s{+PVLrVjKP0E+oEe#lQpBiSw5GyD{X8aH${57tp`A3N)o%XO zoJW%kW0pk;lsS+57mv<)6tJXc&ZD_{mz+nL28FWJ!8NirfLux)Iz)~gTif3fE7pne zM&?b<;)QfD*kk?Jd_%+^NBwRPA4W8e?WdBc7If zN}*L6jN3&^=b#`=IZclDn(yzDIHT$gn9umrtu;jp><1+v$3Bp^sgb%4iMS^uDN2*{!WbPUZ19HIOG{!- zGF0m)AYLXb@k#lAh%b-eEAT)|(bFFlid*1B-9+2%lZye?Bt==0zN1o?tS0BOu*Ie!dA at i6>{=;nWU3`v5V1m3*h z4bqTA66G|Tj5XT57;B0c0R&`=X1B>p|^4>{|6 z5$iFC-zuG;i8mD1UZ%ZBotT>oiUGLS2CS#Be!tGgc039KVQ{AF&miJ;0{-ZkMdOb% z$8FQ*uuJlGqKD-(nX6Z`D+c0oo%KX|QFuKi2lE1dhpN^R+}S3xE-#OL8^^ zA})$Y$(f2ICbr%zV!{-$jpo?;#odjt0>(0*MA##ya5S4PCvgGLf1%ct0PZ0yQ-GCd zJMz9vBv+0gk4PKp0a*hV{_Es)HB6uW_zZbk2U%upbdZ?T_}D}$OBu84sWN-CIOxQZ zM+zkGti?Njfg8w~v^lwPA_G>*l82AQSyfFnTiW5GTjA1oYh9ymJ&H7uJ at c3w z<#Vg5p*FR3%aGPBA$aWm2>iVfty}oCYjFr$$Xd7XXx+jwkrk5DcohqxA!1alLRBwW zzUV38H<9{D+|D3FVqVfo!G$cSXlH5gJRlPrgYUpU9Jsm)m)MxyL_tqO6Gs5-)>cCU zJ)@$PE96nz9g1!B4Yaa#rBtWnIqO%^DyU$s5AX?Qvac`^a*@>^zFn;TY{CGv3dP#Q zgCu4_he(T^&>y1lrmL2_v$_%8T9goXdJ}3lM|2IIxYKwGmnM!po+fhlYSk=C2C>O{ zM|Qw{SW}%bG>Sa?)td>8!Sk9*qPIXfX8ghF_h)suv`MwY$!jdl&pGx|>b-Ri^v7qp zQxcn&864>hG${6T%vmC(ah2Gcm^kjajX2`N@~?ylwGgeK0VgVnZ>cbiMyplti<>*> zUOqay_*RCN9H%_%B at Vn{)*ai3Y;SHb_4wk33ll3gi(C7dxR6YO7^*Z{ON`yEL?+wI zH%#gq=3-=fTZTvj&YHV0*&gOD+&c~u(>1vqIICkkpqIBel<*;OV z1)i*o5i5 at AU73r%T9NM=vnM_`=Nl!dF&rn1*0e^P2?Z%gq36+eE|7lM?oU* zYQ=g1*YWgJz^FXTUR)@I^6p6=XptQDiwih8UL;Sn{xI=!QNU5f8GS4>!dp?Kk2FVl zn at 4+?M~ls)y~;-Tqf=}ao1;YLC>L{-%pB!oj`A}{`J1DH%uykhe1CfgRFoe0Qx at i^ zbaRy292FB#SX_YT*flO|GwNdt;JV$6lDf+N&!9vJGq#NkxLb) z&5_>Oj^>5phnK*mI#cvmG{X4E->epA3ys$$#z*4CU5t+;Z+6t0qvYm=Ls(>ou|$+I zxmXRz0ju0tA~rAaP9ZaxTwL&&T$!JTKu0K@!7U_LB>`Xax#!OVOZXX7JpbG%$;*2}%X zP4&R%N8lO)W&Ys4;(-`7-<@MyO7cWwNl-Bex6CTHoSy`e6D>9!H8^u))aX0Gm`|ix zJ}XRCNnQ!$BzrnDC(qp&Ydj)GkOUv-Z35q#V)6@|z;WATUSvdKP7`o2E%omA`w?&Hb`5w?M2A`TJ3-g)+jcaIV8gQGJMVOLV zp{mkYt#PIn3X9%*osdCj?U&jN@=4N8!kTx28)+Zdv=| zs?P2BkE7BIPTv>D%?EEB%Hh%%R-Z7$2YB#(Z*tfMqz4oR+%6M>PY2tV at rf*}7t(jiy$yYY zHW|{Ed7T?eXbuzc!@Ob}2Gpjai1h-tK(2q$EvXJ4mGsGvk-wN9FCV}$Kd9Znc$ib` z&?0Z~?*F(l90eXsMeYrh1aq7iN??xWFqdb{9Htx(L`2A6WWv41soA|Rv=D$ekqA5l zW}>AJj)?U0k(7ZJyroYO`Ir7Xdd%TUTojLgvG##~qoCG}o0DT%7!mz4p?xz&yyQnK z!FDZ4*2d49fq7vaqme!+wbS8Kp+~dH4>mcT**zs!8Qr8ByR)1o_c5yaFknL$sUivVK^CX1>@y@`hiTGH$Rcy zFpMHjmemag4`Mi at 7PKrv?w2oew}vZ$mLRC{L&3)xC{AZ?BZJxLyAmY at Zfn(Sc`ssY zY?MPoB%SMMBVS^=>IPES!US(Zzik?hwrNNuc^~rA_|6Td@$3o6+f2ace>nlie>H&~ zZ6_e-C>Pr(x6_YpwmtV;|Aj<*Ut4ORIT55e~z+Uvo$#`7= zo(~8f?-c3CA7?MYR&oZCpFx?>8Fv{sS2Tw*j-<)|fh1WglEAp+UZ;Sjq8n1-v4FG7 z^zx2H*TLp_36BYj&`ff}v}kn)GJCSG7PvGM^|lu=;)JLXZHWTEOKmU7JL7`=VE@&7 zF(-}J9nZ18HDy9CG&N|*<6V$)VV0cOt4%J?CS6F#{u%uf!5P*ZEh3&utnra>K^APg zQQ)u at v36xbS01hLwq4C*XNnYt$M_f_Ob?HDB4ViaVK6t|p769|s}4u`4nj$*!d=c} zg2*!w at T^SOog%Gl^{cVoHZOjSvwSTx7rKjSlm7!bHX+i`lD!@Yn?Vc$jxH-NVui-rLc-4Lj%nr? zO$MM1GZWOA-$1&c69#JKSpx!&);e1 at 5o3V-ZH0&HrlCiG|Ei%gf3+AfSg}N>n+4|Z z7|W`9a0td(!sFF(Wfa;!T_;O;2EKSbUP_)Cg3*VV3UQOu%XsFOBl8D4H4EP+%)j8& zY6aZM3QS=%GlXY?ffi#&d^$Ngp7*kt=$O%cDj1iQl06p`7eE}8^FwfT!kn5{2O4w! zNK2PUT&>pqkl)aEK?%^I1o=!eK9**Ulk7REs6i3S>W4UQi(7C)A at Afs3*Mq;{*(sY zN1%$pf~J|{qq#*!C5WbLqF{If4LB`vc8XgBtuJFm#H*i)m}_RkUCE;bjX;UXn}!b! z?Tv|^3yA!PoiG*&L1R%{@zpw*fji6%MBLjj+A>}YhiZZH^8y&kkW1iwTl=F6?9cxquI% zKMcdMZ at Y-E<_G&{=#vNN#VN%}Xw2)=UHgBfPquzIKs at SG-dRcB576wv;d+T_JMrI6 zq3DB6I)=WF5Yje0kOUm(Zb3p>R3jCh0nC6A-4=)s5T9fZxK9^BR4x#=cA{kzk>~gp z;s7r+AIl4(O)QVK8Ukq}!+`e42XTWCGk^vF8zA}xo6!)U$^pISSoi|vR_hz} zchhniN}JbP3G at q(0SQpZIT{`WSr?1uk|3~+c8o7pP5LQxAXs+dFublyp)!B zX|?cw#Xt4G;~%huydqk0-F8H&k!0jfbOd3LXETFF*%*YX{jV7m!80g=XAq7{ zlsDSX_ZY02e{gife4BVsNXI}s-0V7YXAv at VY2LIW=EvU`W*7n9PKfU at M&qv_F3)@^ zW`+ngKA7`8Qw!nM5Z^OGjXzl-G at KAdAdiCPcV&*%x&tB~M5M$z=o9pJH_8{?AsNPd zkkTk?9XS3V1DCm@)yYRJeqrS72-=Sr#pCieT;>D0xdNNBSu-7yCe(ca7YHuXDD&M( zUn|UyZ!`=m at f=B#cY$i<+T&9_|Kv}?BKpPc|-# zIjiFi>SD-l;bV?-!TFdMi6)x|o8zP at utk`|gOUsI?1r at DPE@*~uLYYD3UI9$Q)K6F zhb2x5NEV3z0TT`j3%Cq!Muk`QU|eEFm{jkB?7+-8R(^||14F#msZ5BmG1Ax6OrIXw zX+_K!DU&V_fgRPKi4^1Z%BMh<3d0HcIC={s;|@@K#oV8(beTA#Ra+yQ-ABssnaC`{pImQvj6{8=p779n at x z-wFbrwz=Vf^|qJ)u)UnDj#xRaqS+dvt`xUkO!DkgD<@$%KA|=JBz8?g&pZ z=_FEtu>o<_znxkLj4pr1)L>e}a9RO&Ez?qxX(|6UE&1Q3wOOh^+%gYE6`qf0`83Z0 zhUO;n?75Ngm>QVKufA06=K011|^}?w at AU_v6190{J8^PR*^1`lDs{a+fn?` zVvmBA9RLX*-y=f83(r3M}W?FjCYoW3Bn>{^BoKiYO at qavNX^V+6&8l(?Oa@ zkF4o at YqH<9w6_fcWW|qyt|7iiO*}MJGHfff-YtV?d2y&(A;F#hlrO0_Hrma9#iD*v z at Xgm>fBoo(Z*6Ii!v*UA?P}cT>;$y548XwuA>@2v9N8x-Ghsj}?5->TSbSYrx%ZgLz zc?=s+hy1 z=Io%!Ddyx5w80^q88X%_W>(AdiSaU_YaW6O0*F960uZA?jwCSO%9nEoUX!%&HDi8P z{yceajEYLLM#Mx}Vq&6{io=<=nO$;xo04(ZZ#yD0Pm+7_>zig=JSmDYI7A!&5 at g*| z6l2wV5qwKcmkq&8o*cthMw$jCZlz#0mGI>%fJwTTJ1|n?VUbyC?qH-uW%!-~MQ-;Q zOBNU7Z?BN^7Qn9u{IBA5G-c?G*BHvs1FvH!LpQvtDMJ at yslD;3WPU}hG_uy!SZY@* zHkJx&g~n1*upZPc(cnrdG(cCn1j3~ocC^9zo z%)G*UOjZFHa(TW#5UipoeILo*conX8d^+%J6Jj!pMw3EV{rGfCe0;i6QJh)9lo?rS zAKt^$E28wB(HCLgQKEO^@AIybLZ`DfxPXSDf%u|2?i~f2Z8>tVfWM8>2{^HdVv3B5+UXs1o!v9S5G8c3*homtg zDKwUH4M^iDxZWL!eZ#~15Z~jrkm5M=gqTJ22qP>*){xVaMvKc2_~WU*hkZ|hj}#2% zCLRQJw3VNf>4 at Ip3~M at Kcnqe)*%D>#a}q37O|4zPZ6q0_Ce0cX9|IhUkD*}Bazjth zes4)$H7?O|Ile@|T$Jp!lkD{f!^2Xj^^m;fgs!1pPHsl@`BPC3J)@bbOCvctHrWcsQS{R#axmEc*Bu$=+eUWv0R<5^Nhb0%$q|b(t&- z5QV-cKNVpG*~&So6#yz9gDZ2G=gI{_XS3SoyR2Z`mPN=t@*`FXfGx0UzU4(=`+&zF zrz`AgM&k2M2T1c}hX)j!ZsX!B^CRT$JOlK}FushOmt7`@mE2 at cD$2?2VGrh&fXnz? zD0X2gfICOdvA7kQUEXT5{EjQ0vHpf{aAJ(aA|h-=^DZnmOJKn_aDKAcowo|j4?19m z_qSr?A`PsuG?95!bVtgasDlC<&G8ufj*URz80RuS{7{wREy` z(ZphO6+Q45p;9LEk5d@`l4b?KjGZNW9E9bO!bj1DKigts$^yf%6HzIJpf3>S2#-njXa&MYS}<6{71CU=># zLu76c;5~d8%RH8tBB4PtK4(#kVcK6($mI=0Drdac(C^}nCviY=*cih#<5O8e zqGV}zw1iKK?$`$iFb)REyTbT=LcgyB4xeQ_*3hezRKNwM3b)UqS}&{vEKHIp-~xFT zBf!H%e*{g=fef+G`zqhtSOhCv$cRh?!4c*s(Astgj&Otph}IAc#n9z{M*<>fOGOI_ z%ufMF{zd{%z!AoekO2Jyjsz4l6_6lw*hc4^cpl2;Y z%L=q1gQ*I*@V7g;d%U1QDzi# zvFMgvfS`pcZao&uJ2D|Z@`OEU!OBteBp}2_k?{}FXr|2Yqv^rqWPNYW|M)MWc{Al< z#l)m`0uJ^PA5_8@@W9ZbZz-w~x_mqH~) zi}6?6YViSUJ=C)!@yBu|o#%h1yGm^h98Z46w?b`EolxViZCgFX2gTgij(-$I`Us?7qugJiGj+ghQn!+87|Fl(iny>Sj-2saxFgOhI>9JN- at I$V9v zdVI}0A*8p#Ip8Rum#i)_$5w-|1G0u3?iVRVI8J0uChiofI^d_1Irh9dj`g9)BgafC z%NWiZvu{!aZ4*ID;Ur_5tV}5@$Dh!#_HD%Sz9K9SCA=^=So`|n`xnR{dNKdwkgN;$ z9%C{7d=h)6`S%o)qKb7c^kx(xbg0WzH_IWNn at uiRz44dC8P!b&pLun*R at 6EM6e^K2 zq`|1VDXP7|qKkt#3J^y;hogeSQSonajHk$4Tyn`9azgwPQ0!!GAwaKA(6S6AHRCf> zPYe{L7_?gee5>&%^;M1LR94NXn#xpo{%0jGaP+{rvO%^ZfJt^ZfJt^ZfJt^ZfJt^ZfJt^ZfJt^ZfJww~w-bqS(C@)d(;R(&GSr zg7hG`dIPu=aP7M7q$u%DE*%f`dVm~&2F#st5nE*Ke z%K*Lx*aL7F-~>Pwzzu-K(0?w#ElAIR>m-1209SF10qy}b0XY0XQBr_z0CIpq06_pF z0Mq~z0MY<502Tr)1y~NS7T{BWF9Eg!>;WhQI0kSY;0nNR0QUf%0yx0fQh;s%a)3bq zuL6wT$F0dyp10>=oyq~$?twJ~{>cG412~{uKv^BY6 at YSpT>xJK?1T3CaLobG1Ec_q z1Be6|0w4$I2p|HehqgC&b7PgjnA-t9<;M=sOr5GvjhL00I$b|6bCJxaZ`O-g9y>Kd zJ1cd;*tE!5>8X4v*A@$)He=S at nSU$i3TDksONRp0+!?aWRJ|c{ZkDX?48X~kw<+Yy zM$Mh2f4OzV;6X1B3V=S7cs-edZ%~NU08+|BoJDoSce=zG0R9x^R7go3J3x90fDG~* zDEu8gN}L0rgnTvBJ3x9ofEVOfP at NnVkX{H71o;Ze-O(M=G=LA}x5E_>i1PuWAYTvt zMUajM at Sr@!zd(OqNb3QHKz%v%cZD=eNGyl^X1HSeJb(zuv(O*$!ED6dkY7i6IBFoh z7$5}lRWP3}kWL5igFG-t>;kYHAO`Y{&|e7YaR41*{EaYvA4q2cybSdvFupUSrvdba z{3f{C0W1X=0r{KI9~MwN0iYY?SHt+>kbWKDRmh)*@jF3U2QUEgsKB_M%K%10z5)8% zLs|>anNq at 3IynM&#Pb1$Lj4ICUjpegfPRqw7OuG7ZvjL?z7G03K{^GXC*(hd at ux$2 z3BWMOUxD$vLwYX2Ajltps~f;O0AnEE#PdH6z#Zmq!+!;fmwE4KNb&fAIXD3;=v{ z`jqGYn*hThf0gI|Jb;%Ve-N&S?_Gegkbn9Q`d`#e|39PJ>i_k2`oFTB{-0^5|KC$> z_5bca=>O4n`oD#0tN%6a^#6l)`hTgN{=??cM*koEgZ>|Br~hA2ZT0`xcKW}jo&H~F zr~j~7w9)@R|3Uvxw$uObsJ8llyPf`j(oX+>Zm0i0Qf>AB$v^0SaXbCrNVV1fU)t&a zs&@K+uATm)v(;Mv at Bf4TA8)7s-%xG!zqXzJf7DL at FSpZwaA4Z#|6l*0|7Gp;|0}Ak z{{P-i|KD$?|CR0Z9~_T1`v34B^#61_{oh8l)&D!~^nZOj{lC^u{|`}Z_1{WK?FCd9 zdx4;ny*t(2ULbY1x2L+=3q+pwVN?%$fl_KOq`d3}b{_UGP~P?eSx0*(s++w)+}S>t zQUd8xdpqc#3;nxde=m1?N9^z5X+IVFPm$V-u)om5elYg;?`ZFe{arfS7jgY5cM4z9 z5L1qn6Xig4pzJAUN<_I(Lduo0queL~B_Te}^m&=+Ov%zy=g!pAvgvf{^x3V;XH3;k zwUuJ|{Hf`)X2 at pD%F<7rJ3UpVpEpmIHZ at Z=Z7ON-xBBVxW~8<%PoJev&77M4l5I4s zZQmzLmX)e+)o0qQX6iCiGr)KIkNCKrNYb3Ca~Ih<&C6^dCu`B1Y4g&vn)@RGveunj z;m!gNGZltUpErHBtxfBCu0p>k113nPPMwjODVv at -T{dS{)|{#O=`>}SJA3ZD1#@M5 z9XO6NTa95`Ut3Sxx^uV}%$hr6-U3iY|b=slx5-b zG8Sddnn~+rgM)(u2fpm at A1I5RnmJn*HX|L#!Q0d#kXQ$hUNOjT2asJ?kXLuA6V-+4 zPW7VtP`*?ErJ%wo4Kcxro?WRIsKHbiHI>SxiYS2~S0Jzx2n8a6gFq~B5l97I0-3;HpcG7LJ-%&B z+gLb8XZY&^e_rs{75=)xUw8QPhQA*0r-VQJto3(X;5XInk9~1YA9O95{L5~e3a%{bS#zN}|I*p_ePi}G{kZu1C5{6NeqY(+(25z-y*=*9w(Fu^ z`{Dl8u!DKo=YQ%}d-LZxal6kql$p*Mwd>M56>gqAWKEcmp*&PSYYKY7O`mr{9+^Y?Erp7)Y_3_bpv9#e}#2d3>=5q4$1!)uoX2V`g0 z4Uk^AV>W&NTCd%E9KN`DXnnx>0`~Kxjthr8q9pHZc3SJT&h7esSKXTfL+6O!PoJ?; zFlqX44RNz)Pn(+VUFDx at 8beLHcYBRP`Ws&ex)(KwmnN1-{w%$;Jyl(^x8tpXgUsUm zADXW9_<7o>fj at cPUwm$PYRvh+#!uZ5dn#`Ct9t6d#vA_o&xd_+ZFJ?Ds?a$lXEy!S zaPge3W>$F9rMW{Q^JjinQ84AFtbwA4Uwa4xCdYL6`siZUpF>`=SAQL5*Iz1iKKPc* z(>roO;Ub(bbf7M=!nDdtJr$U7IV*x`ggb%5~i}NHOWhz2Bwp zE0h at vZtvN7=tGwqdxRgJ{aznD^1`ic3(kJx+3&K**!fCUN9XCkhS%ij at c2bB=u)Eir=R133@&~>@X`iaoWSINl%RadFH%pKRkML=iocx2lsZl at Xq!r?8b{1m#jMTS;^t5pmF!E zjlDZ_|CyPI2fqB-VfXOpp*x~}@^!6>>E2=6gVDmFQ(hN^72lb1E#cbC&3E3JJ9yE- zS&_?kPCeeun08>p*?E13-k`^=S>SR)IMR9l51s9Lztqn@;h(z z{HfQ;&IfZR_WR+%^#$AKEf~4i>$eHw{0yDMdQ9PvHpyAwZv8a%-C0|wHJ-E1o~k;X z-g)7T4jcYB>slFa6pcB&Qy4t8-^{NbcAioZJ95^j%M0cX8?8ID^~!{cm(rZCDeDzg zuV}U&*mC64{a4>Sy<=pJb+^Cwy&r#Ec6i at 0|5ZCRUvAtbw;x)uZh&o?2qpolaiuJ8!@%2c36)_Kr(&_iOeOEO+b%qW*^s?%s9jw4pB-YX#GUcvbAAj#mg?0kJ^9u%rf at Qsf_rmT>O{m;D$m6%&uT<_{=e;)1XrHvM`%A%7 z>LZp+t9g6i*u$mX at s|b5JXb6CyIG8EpDzzz3OeL^WJ6F)!~PfE{c3H8Q)?}qoTw9% zq6Sy0m}!sa9 at AW35TCq%pJ)1pjTeVo^51t`yHdTb@~Zom6J=)~U$0wr{PCZYDyL=k z_-)bbtGnZs>+{AYjqm8zxoaO!$xj(U@{hv$gnl*qN$PJCep}qv>3HIdpo%dYx2_c2 zSij8cg%e)|OnGu(z_#o1 at BXM5zH6Ydvf at JMhT|t54_#*5 z at 3`{Ah4BZz4^I7RbM!i+qQjPTy^lWL?Ua9ft8{Ggoyl(L4Us2 at Uz)Sr?XW()1H1SC*_#^Hky`hIX0UO?ifLP!Gn(D+bw1MYb7I4tlGR at wzH?#ir3W6FBd2 at O^8{a$ie(bOJci3$@ zyruihm3jXCHmrZKVC#{akJev(^6H8E7vFfoo<1;pOU{!CJ3biZw0_5%L3!V7mwWr& z^>hq;IdVYHtObJ|cU{kj`mkD=yPajkH__*Y^>t|2wKJmzsS6Mx}ncPR{m>$%vWVq*Glbf5*h;?IU3b({BDSW&rA@}&Sm|jPMa#I at m zto!6Ex1CqkdVbxVivM-O;IT~~Oq*6&rCD^U%h>Cqv`ZeV*9@$D0CaO%jpE2Gk1+MqG8Lp#2@#nGvcE?zG7O&#ujbJ168zlb{U zZd&)1oB9t}_G9&d6~c>RD!Q^i-V!;Q=OE!nYh_z&`mj7HDn zvlNlPjd*>*lZm@$r(S88u;j=qPMSaF2Sq*neydYK{rZld1)LbZEc1yR-zcVD(H$1d zJ)b8`Iv8npWwVoG?cw7NI~H3+rp{yS3*tJty{kAQxoCRd_4=Izml=<`IcZi^i8~DZ zv_t5~NzNG?`+1K%db3B*1)ukNvB#92-#Wk4{iCV3yB)svjn|*MXLT*V7ueCd?qR1d z`+e`eGA2vvF(JgWkN;DT*WW4V9DDQiF4d8-L6v^*2EX&(QN<69&aa025i#63 at 2z3u zUM&nsRojJ*?~*cfUiQbY3@!dCP_V^oNZz5u!8=&k;Uc5=4vuIV%5etuP5WW87Sm_(v2OUU%J7US4tB-@`)vS0tH~p>MvnSRq z(AkX}Oa}(tpCx{C+qB`HbEc<#<2yC3sAkIf$}dxY`EkaKeZt;pmRZ#^WydR{x_st2 zYD_Op^diH`(M{8 at jy>+=J?6c=6Joyjd0p(f4@)Aq)jN!QFh;2=k}r*jc==>l)_93> zz;B~Q^jOY>tLeM(GwlKrh8-{@I$hkWU0&Fz+5h#c<8F8?R$o|hFpdqrG2xmz9U^qblrC(XK5U(o4E+1WEq zpQgY6bc;iR)lb^(arf7&{u)v8=_A9|NsUo8)crS&hwt?Z&8v4$jJ&%#%&B3c at 9{q$ zudzHlX&w7uO7g->iLdOdax*vm6#UDu%Lo2^?JBc==e4sh{Q2{*(XU*oa+zIuCvD5c zJymzk=k6GIL9}UFMZl>IXLK3AolEW}KP!Eja-{$2k4u&e_^EW1(yQ!*Hu3OZA!~|1 zUwW=+4eMUGd0Xu9^+(+XD1?-+3+e9l`ZyPYdMJ at 5y+Q_8j5RxW6ovtrN) z-}k!u)U5h=*q3X+iJ$TQy<5H49LcF(-B@;D{ps(Pe7d$%(8r%Gdi;re-tKjs>=%46 zdjH^$vd`TA&_B>@ahx2zJmtFUJF}S6 at 78^iv+VN25zNw2BJ=J(rTO_YJ~SS38^83o z?LBkO{B$KZ{=}-h>0ic~UiIqowrl2vw>DJV*z*29+2&KCw67n{-So}kg|%CwJHEKB zs$KWw_dq-zj~=Q;LG_5hD~9^_kL0GV&jJU;je!7^^?ULKY9P)=M`BcyMOQM zu@Krrrhc4Kep}enE3v*cVDi*`pT8bv-|!KRQbsrpIt|mjTL9l zsQz)D;B7%=!J&(zf3DKq3s`WiS}UDCetlwB^<)1pSdaD6$FDVhJEFYsjceb1RW>tR zoN4Gc at 6^eRH@{os>E%A~uf3awe_G-7c7OJCw-N7Veg3Vibo^88jOq8oXR33S%yN6__#3mM78HLjaXnr}f1mYY znP_UvhJs6fuA3LJ!g{W0i8}3%?yvl$jqU$~n~&0dPwAcQn>OaVcz4@=Irq)VnZYX; zp7m|$HFuTpVLwIMiVuzX!(Uo?d;F>wL&wZ!wepz?zy{G1aL6I}N zd=zh&(Z6ngRQ+pLUy3>EpY!N)!tbi-A8!~w`%#(kTo-z1QKn?sqT{b5-`uLcK1pef zAJcao`yeZy+1mNeE1esaOGTgbA9g_AtLBBUg$W;QtE^^@ZJ!jN*pqZS<;<@M+n1frIO8lB$#>bJQ8y~IUt zxz73W)!mz}D}O9{tI7VQ7e{p&J?77C_viP1d9C}W%N8E=UDxB%`?Bbx4GRZtjVde@ zJURPCTA0o|W$nX7!2`y=zjl4{z5mnRcYrmqe2WhODJlpmsMi(?s3-^)#0sGaN)L!2 z7(=pwNSY}i>cs-~-Vi$$P_BxAq9}-py<-EhfOsuarUg)MPU|aB!?D9&nkL*`K+|4YjDfV9pz8E zwf{IbcJKIN;gxn-Mlt(BcN82Oem+iXPHozjXB$m>x3WvNllXO6vBylXpkUhlF#}4a z13Zr1UiWUUj=}opIhiv(40m<2&g|?y=9aTnu;kmB>IW}VS4a4DPs_ME<9ci5I_@#S zd)*fJr^iu at o=xIgBkq8W27br&#AiFnrdF+d$x9i!jlX`E(St>UVjt%0eth?3w+**S z78xAz>>rmo>%@y3E4@`GyRPnf)R;dtgZbg(v1#rJ`K;1E?%(-S{OIYcsyo?!@wew+ zXeUaVz>nH{>PPt38B2&uuiI;d`tWo`B{gkE^Ooxyei|uZUi1_iPrf^a^>k;%H2Em) zr#Hvz+!=ezaQ=^!mf2B5v-j3GWhIFoq&^^)Lu4SRBhed`r_T3yEY*Avf z->(#nxLE8r=VT$*tjFQ1>ySi)y(`L%k~+?wYM84p9&NRnFWT^&7pfH%>)&+NN|`xN zzv}d-HfMu~jFR(hkG}L>nxFH}_hXA at g+JTIl$=5r9V^9P?XJ)MYU#;& zWH{@RZ;NT8`Y>33<+n06zSNqzASg21oGG1u=$PP+!FBG_?UPHt8ucr=l$24J)bm2| z-owF%Mt872Y&iGmiO`X!j*AYw$%$ufI(g`b_K_#8m6^9T{d0Hh at U6FE4(dFxFjYJ> zi~pO~s_i=d$OJ?2)G;%rhU|T6bfeW;gSxFPQF@<0^|occYqQp6q5iI0-LyVL3Uv!= zKZgf}%^@PLbQ0N3lSJvhsJ+uUdhzZ4kB#ro2#I(!?&{ZLWzrS-m0vp?&3B%XvEpt~ z(XNUeH`m75-zzxlQ})6CW^Tm$)V!bwhiu(P?pb!@?-};Lf3Rg|Pdn{#)hwMEQ_7}P zp4l5w7HBJ3QRybkkG;Y at v@A~$|A)EsR>? zor7F2Vtxx0)NcLBar2(!%xFI|vwwQ)Bc1Kn+*+~u+1-4 at Sr03Zwt7(3W5MlPci!K5 z;uQJl(3kG_<0W(R&8}4+vzR2!h$-)QbZpEb{gCH%ZKlcux+5=}XtfGmNo=e85}q#P zM%CRm6Wwr4Zuw+-vEi+^-a7FC!?h0;?1`}87EUqy>>(WMHAWKiApPdlaV13|4;{-| z35MMp`7SLlon4x{?cCU`8?$Y)>t3EX at uAD*;{{9Dht}HkKD;aSc%fa3YsI>214 at JX z^(u)tc}OtB`Yd-`PFQ4ThNZOsy2GvVhn;D?Vn;}evd&hF%H`PqJ9V~Y4YCWL*WZeL zhA%p&^Jh$z>x7U!3w&6K7cQ18(Z5-c>rqo#vE=Wnk}LbOeOhOy$9Zjww_33`KP;l8gZPp$Y^_~J}yeDC|`vWT#-^uJu( zw!e}_UF{n!`ym`|8eJ1VQvUhy%uZfb>lKI>fPKPQ%2j(QjC)8b`#oJ)a^ z)xrk>UCysFU81$zDAzHyS4I3u`;r3thxV5mu!DBc+b at ymU%y> z9Ozws at UTPS+wE=Rtri$$i7vVK-dD&r{pVYpTfZknOyod^*lN4p?nk>CbXMxLwH!L0 zo%g}tefgnSqEt2|uG03!^N+Q)KMGFXEnGe8>Xqct at k{J#Hm%mn&CCm!zIP8Xd}Msm z_?}5=Ee*13E*Ym^S;VOf^Kq*Z8Hr0At|<$QmVFFq>--O^7vr=@cKTinYt9C{;;}2N zp6jNd>~ndY6B4Gemi!SJk~_&crXndsR8nGU<jc at H@9W(`@e*B zmX^C&S_?|;%4eU`ONQ+~&+8-6laclDS?9EZ-8KoUBl>Mmws?9jJ?BU1_OC at Bua3A; z at nhzkw5Ys|Ss_2Nwi}Gumta48K$qSbL-kDGce8XGq-PtWaF>-I_KPa~G{Y_4ju(~{ zbET%(`&Rk$Heau1UwvGhu>4?R+i^#h_iD8 at S#~iYm$g{CSD4!$_98u7Q-`yCjg00; z_#`>S1*B;Q#@3wj48JmWuKl_0NxiBjA2Qmr^)J)JhtC2~=kGqYA;sb08?VQ*?|GE_ zbnvZ-n=rH3YJK?CE_bY!FKIU!jM(zA^+T0wu(s0B4 zqSk?xNs%5Ltv7 at _K?2>hTdTDI;oiW|IP3hXN^T1a7|9HdQ+;Lx7 zK__AMr?x{sTx|C_sm>(RBGp*ox!QD8Nc;A+HoeSpR?O%yYIk>zXHD*CVt5K&$_>X4z5_Xe2OdPi5PwCM6XY7V_Ow+OrI+0GO at mbL=I9>j5 at Wz<6=3S!weEKUpyqBx) zZg!1Z{BZj0 at kf0AG}JenbtAk->>TCp=}z6&&d^D|JoEhJAEG?#3~`*xLaBXCsibDr z%c$%HqNy>jCq>%&GlU=QhlU at Vt9Z`*_4-;d1xl zD at +g59UaEAyL*pYt%~(2<$d?=VsOPX=kXE!B{)qQu+)zQ1!WnS;otZRc@ z9NSD(IC(s`bY8lwYry+R- at w6)h#*zom}bK8VBQ>wTX1D`y7`DW4WSNrUi{38rK at uOYNyYDw| zU8vn4+Ey2+n^yCO at qlmlW_13#?X1(6&~(*D^wRx9LHz7 at 38O9Ey9Jq48L-xUy3&8w z=jH2bs(tFNl}rzta_{)Cp!?q!8$B5F_wdqbpYqBMZD0E6Q;%B at hmC($9M$?>QJSFg zPUXELcdfGK7KZQExtV-@@a^ZaskeIn5q55Jt?}6{>-wC(Zy9%?qoYSb(1fdJ){pvj z`u4n?r%Wo=U-3G)_wvef+b>?4dHzx>llNC$^pw{Yh at Eeoy8Xv>#xbka2NNAviND9J z>F;E{_GRBriK%0 at Y~Tm%Ti^4a59=P!Ik!FU!k2Av2X1V!ZUxVcL_zNs?Jq4)A$NBeJ2?0Bw^t6ABbNh*-d+l|YXxnwwk;OYc-)g>qWcfKFIiEctr8+{@@y%hEDFLm&=-GDj+FO?T{>JgzHD#~etaBCzZ0->8x{r)8?VWq> zCC`DS55CT^;kmvDjB-fcay$OQ*VA^99b%WXkv|O^b|tjjH{Cm+&at{8$vl1OB8Azo zN;92#j$iV|^x4|uW%u421E;f=J}y2uI5gw(o8TiO1E1ZTJk~cZqwaO5yWt~yi0&_R zGq^bD-1 at -`C7}PbY9jOtc-bXQe at W_ra3qh6_&XXOBn~pKvVS-QxR# z(;Yne4LtbCd)%O&(I1y=Gf7P9pFf?sp``2ds!QWfxu;v-`k{4dDoc>^IdO6qAIssf zVcQcoJnQxTgI83i7N3garo0Hhxq?%AA)NML?CsI$G)H;3dz+s7*}mxyHEUn&tldz4o0< z+~%Z2_qumppqes6%UFIRz4o%=(&nJu?|W8uOdR{;!0%dq)*4l1E*cO at hUu`NndFbo;m#tiPEbH{nD13*fP;b;`zx;$gb`KKQY#eHB zUF&NRaBSnYiqh}P!ltzyQf?NLW at mlfWQoTvDeS^}phVrQIl+&9axAu?U+Lz4*}C%WsQ40^&k9ipA z%zc-c^L+g-LywuAGp)Nh-x}loO%iPN@N}vELf17 at Mn*%~?hrzK z=OFZ01GYaKp@{%nmel}rKZ=mfJcRNz at CpGo1n?GVz?AsDZGa_c(5}Jvwa-Q9iw5it zz+}*#EVBW&*a$_TkKmK{kDN)}Mi&lNO+`*I@) zxaRERb@!0rcX5h#RRRfgc3iZz)~vZ!f=(6Pylo? zqtSB?$ouDK901E2Ig6wU!ksJO15R7a4I=~y#ROV}T%-yYAi=c&X+2zs`DygYOQU5L z;%Ns;#Em%TX^Rv}xrmSeza&fx!{)L0e0+ZzLr{&sa(uedI3Epvr2?7&~2a?%)?8{SBdCx0Y({yO`z^& zbDhpYvyclRBGi3eLG?-)P3Z*RsOBL7MXmc8&IS>ak~_!nClo3WOe74R57vNX2e?wX zP#Nni;^MK5!1T^4xtx%YgT at 0MtpQWh+F@F%qHY0AX|NGY2OL!m=otn54D{HohnD60QXhVwncj6*bJ4tBi#DcvpXK*Ltff)uLtVBn4TSk*!I2Dj3m7 z2Ah!Z8zg at bxk~uHT%kmXP#DHz$10SB*oy!$@c`ctIS~;;35~G=q%H^|Z&xI30QRj6 zU#UVvlWb^T=^~2ofJOp{>7aumMvOuRGFJ*%$d%Lw7mE(rkv*YN>l?5HX^04}f^cz0 ztuZ#_ue7{CJ``K{Ubx?&RRuW2F)eJ-RE33d8G$lBkgEBwVXz~mG3uIH%Tyg(rWuSNLI^^XlSTw> z2eMuL)tXsJ+pSOdRNQ$q3iHK+a+Zp)FM2a@#Ycssj2XV>6y=5Qn>B*62q at Ha!__`3 z#dbbe9aTJ>gi3H;h|x5JEfop*PI8qZ5}~m!9&|S at X+a;!z%ibPMNe?eM at C4Xf=BQg z*Zow4Jaz(Cq#`f~6=9gGL?xziUNy!6jIS619d4kxMsgv$K~oiC2qgf3u+XiBI^7J* zWdh4r-A$yc1(8)Ga-B}_AS$vD+uhYuZRC;2SsEx2N`y)wSA^XJ83Tl3=OLkP0R|5S zn1=?AR7BA9Ewmx1 at ghOy&lqAt%#+0;^a7X2yLJunRSA!)L^>oMz7e^#HWdc(4eS_( zDRjw_7$k0jOJswo3;|{E$eh86R!HayDr1PbB9W8_Gp!b<9^8iF1dZ)y2yl2r+S&>Q zk1GL+3tAi*3|tb8su^-JN+7fkV?of#VhEHV8Xqm;$U;n7=@YCkFI at A;M9btaQ_+U`U&GU(`X1BLKOA zB+M|4QVJS64L#(Mw?(@`%L=N9ViAWU4(ISxa*mig9cFvRH1H)Q`UIn(M3Br7L=Z{^ zGNMKg0-OmnG7g8sl}ALwTC1T3^73L&aP}W&OX}@1;_x`cbfFT}ASxe^I1_m?952D? zkQeTUI6PcLM&@gPO(LNU3 at Sf>I9#5XFOr}FD2WvjR3k_N9HC2Mh;+bIfgGS6FdS%7 zjJCryFbkD}!1GolAqT6;1#13Ol|so8 at P*Lhc~p;iQn8r44Spe27f`h=R0|xKxH*)J z-s9f$2$_--NltR|!7z6M7K~9UA-j~L#i2_NU=-l!a;ZoFmUfVg(@L&fsgij}1X31a zFgRF at LM+D`Ee>UpLRiU>Wxh&=j2Rq=k1`1tVq`J2Mp?*JEe>f*$AA;Ij^@;ynp1Q7 zb;9QgIM+Gjhyw07qVEM%UPb4xA%6`2_vpGhVf?cN6h6-XGkpBhI{N{J-%q~+dtxpXJ3ybRG7% zUOwI$U>eR2VEG3G`l2Ry4PYAX;>sQ$;N$D!;qU4k;Nu_M1pnvD^mUf6uL~=H)tH}` zt9Rfp_>o`)d&*D+taGenTwW9iPZ5d`-2`Iud29rpc3KcJsNy(0SpMd&#Es{U|&H;f+LOu({lt`6KZZuaY;=*bK zc(~(vn^J%q*#@3}!ixJ$pf&XPyKHdvxmG`)y-a)g2u5=AN?J2#+7AMhZ4 zeGwA5MS#6HAs29YL|+eIY}E>KZ`+7l)0O+Lno}qgv*2Gy+L6Yp{#Upd38UKD*f71g ze1Zug8o at MI;2({(hPCz}fRk^9z)z>q7wF at VhHF02gq&O at QwaVl30@L2)p+4NW`R_76_SO39(X at oP4GaR`YUern5-Mi(-1iPLI?yEbW96 z6 at edKbjE`hVJKesF=4IA1QDxbblcW=>@HGCA0-pp9n&{f83{FonjNWR`Y}bsR>HOy zHoMrsWhA0G-<(hFtSCYz9b}jQCSQYrfIqfcb;v>9Qkq9&4g#r4!Uqu9K{>hKmB- at F z(a6#2b`@}SnhMMl)Dsga1n-IADoDrpZ4>G?fL7Q*4)}6F1qkiQ)=X+g++^rdCals& zG{je`F*oSq>OqlU%SAuSLc#1?-#K;1`f0}bpW4Ls2n%ize(wm5!V26EFf*yO zHH-+KCg3ZS4oJ{%@Ok9Lh8Uod%n-_&NFJjjM311p0Za(?DIxjD39Cjlln*0+Sn9{( zX6v;J{b*!~;rOhFR7fLwsQ`px&GZmpI|cx~{tZ{;wXI(;u{O2=CFlg znfhptq;Z2y9J%3#GI^{gjgWK2`0R{oQ}ajwnJdhBm=`nxu@=;XH*ugHVx&gdn$DSh zjr#4hz<8Z=N zu$LA}I2^$Blu9BvZgQ!3f>g-&Rm#=$)EO?NBbY)szFfJ22vEuJOh?Mt2^!&(?UHq8 zH+ov+coQ*Drxb`)iI2S-bVtM4P2nD-b~sc#nD;JbR3pTeCw7}@W5{3 zM#7lkDy5Q|0GiC4_0a^&s$r~}J_A<}bzKh8gyu=H909|CIUB-B!}4MxB~JQG4MfhD z!m?SjPM#1AhIIt^Gm}j>q}F?=#=_G|BNqFT2j381q5CjbLadRiBl=I0!12D3-l?EK z#!Ph#Vb^2+q+^W+t!U9wwnfEPYE>9b%cLLW4Q0}+x+W#l^> zBvJ_(gSaZC6z32T at li1P1ude5z@eu|*kdWV_#FsjJJfW6pu>3URR1Ogx-O;XC3T&i zAn2D0wuY%x_Uq6w!WK^Q*s2w8x-4wJf zz^1NH;`r8+86gGX`jhX>07dX&O2uHTlM(e$hnI83`E!S8{^Bsvm2U=mmYzbZJtN7}jXY0B8e at 4%`&p&)W(OxOyvsD46E9g=|k_8bB;LK`zD= zD!S0HD#LPUsku^S3SjnbyajR4h&SL00-;>oWIY1cd5vQROcnytzR5k3H505JFVOLI zD-~%A at EIhBhli2z> zEj*TX5C!t5zYS>;*SK=fU}HEvx8l=pDgJtyv?UbBS3&%w-wPv%AYXd|9TD=>eeVmV z!wkpolHsUlOBuNfXh>S9IW?!|)SQ}Ab81e_sW~;L=G2`2UrY at 0dvzv4b6P-dPu}UT znY0i-?}_{gu7mKqLIF4jA95u at 4qHu>0XfFM_=|RMdi)cAEo7jB(7WHjf8LByaO2;= znEqFK(NKR}i%^J0-BC*mwb#JMzc-1;G=Stn-A#~e at KcBJ zeH7@$ix;T0v=kK;6`>O+PN0N at 1mxu8gwK1Ct*tHU*RLPy*s&urHa153_tC<2Vk;zWLd*ShgX4V4L`p#R}1YhmfDf;~Mib zHifQNGfh)dj7@=Ed;CeL7Ni=R0bMndER$Ewn(#A$k>S>B9LGAk!QWVbu$(56{A%jU zUmctBgRYz6)`2tqhrI>zgCIt_Y*zOxek|LGG(UI$i4;F$_zbCm8dV-w3V=uWhkOw at grqOb9JZ7Cbnug{3bF6M0gmSF5(kT5Oke`ADkTR`F*Oeqiw5!P4tp z4%gKG3;bWrv}i&{S-v`_$EY#R`g&u3f2(eZ%Bv}v zYRHwUIbp75DfPD5gr5m%6X5J2YJRjAko?B_+5UzfYKSc~Keg9Y(=p(8 z{79P*_OqSz3w|cH^|txb`0!{jON(EOkBSDr;^*=GD=ocozmTU%NX at _GN9qliQd1l0 z&-7sRzZf6w>;5cb6Q_y4u$N!(BR!t7LsMKv=EgtU=g)MM$5S>R0%fTD!XMuLL`P3H zl&|A*>dD4_Ut8}Bjp*v9IL*nfY5DEXbpOTle+``$qVAI=*NEtpJGBy=sYN{k%SHrJ zA{D~lit3XKQZIlp;hzhuM+I3TkQ at n-pz*TN_fOOkeMaq3g*IM8&O-sP+7^-&L6FY? zdO6}lEe2{L_+vtjTU5dos%}nVO99G6v5>2Pf{A!g5<`DffQdO<1I!ulg>WSb%H9B- z4%e9QFQxG%P{ysR;2LgGPSW5J at BkvJ$HkOFnl_TeZ5V&!ep@#htd4#LjJG?CHy-^U z$2+&-BCNrU7|2%_8 at r$leY_1JaY%tT(U1QBsD4`4>xWHB zf&hu&@ykHsSO%2z8*7G3N|U-m$xQ`U2{fV+gE{(heNUoAC>t4}%BC`@AMau`4Ejwu z-aO>nh^q^5k<&fGI*V<>0U>Rz9neNc7{^ppOY(^SFUy_k=T@?x?|$3QZOBQZpB}%J z$A8{uP?4jPmL3`e{1{}P<{&px!hF&;Da*qaYEAytQ~fXW(`v9?wH^E`UkZnM1liXH z5BZ&KV88SLZff7fp3WsbQQaDrQ#4=`a7FEvJZKeTMUZXdQY?9`p&j|Zv_}Og2g=(c zpf-SPvtdL|fQ?H{qsG4%4SpX1NJ|1)ZUtEyp;sVFF>uFLAcC9&dXYn$5#*Q^@HZIr zkDq&N47F`)DYTDNgHB)5`uV->HRYjUdH;qlG_^17|3Ulu{2TjH%ayW!JUc{^R;D6# zs2O4Yb!3kDonHRU7(m7EzGVD<{mU58oSIW}YEI3mIW?!|)SQ}Ab81e_>Hn1UA1t+D Ap#T5? diff --git a/Lib/packaging/command/wininst-8.0.exe b/Lib/packaging/command/wininst-8.0.exe new file mode 100644 index 0000000000000000000000000000000000000000..7403bfabf5cc10c13ef2b6a2ea276b4f6d26ff37 GIT binary patch literal 61440 zc%1CL4OkOb);K;P0Rn=F3KbP?TCqh at i$z>1YJ-x9N+1{sq9P&$hloJK3~DPD8|X5Q z>DsRCvb%0;S9fc7eY>{xgI22`6!4>4{HWqbt!;U`Lt|IkvWk{EzjN+PAYi-Q_y7L> z&;R*9PlG2j_v_qq&pqedbMD-XrX^b`B}Gvx08yl}uA{yPCi$bj(6oO<+F073CgqQ}HT$YZ5;#G zKW51Utr$QUd~}dI*^!sSoutps`XxcKTi42pPxTJe}4Y_{Q3Fw^XKQ!&!3+^KYxDy{QUX9 at u{j~hHO?>9%lws z+3|;($p5i;JZf0gO z*%?iKlo(o50y%BY??m=tJCz}ZZi94H9XqV*D at Kz+w>tEc-B6hHk~$UopY`YBu>TGqU{B?5vnN{qlx%{<`yekj0w8&)fmEV{RUTmUVHg zn)Poss38oetaJq;W7SrxMP!4-3(jtlGxTVxeo6Wepp~;*$&M6RoycmThA>PNMd%3V zJlOFaRC0EknEZy($ za$A3Bo0-}1TS!7BCJ^(KB+q5&GK*}u$cBlb?a0CM9?UYEfrHl|9mj^S0dRi>2?EBm zAy&J}3K_c~12}Poa2;p>zH1QobnLtbc<6q}YPH&ZEMlk{=E}ku)Zzu+ppI{1hhse) zJ}pSRPS*hsV(PM&FFh`CdAhS)tG4i2YHNn3>O~yvbeEyUPML)~3q|pUAkNUj8$$G) z;S_HOvrngK7%gXL!%APr+%$7p=ZwOZN1au~>wLg)o1O zK}HyH5R5pRZzAJy?TOICEN{B52N8L7Lp?~&`&`vw7!+UC0^girJ70B*+-%{i+Q`jr zzUmy at SolBSR)s5B`DIi>5TB-vI_4Da;|w**W1Hg43w-^!tV+(bl~KjixraJ!d#HTp z`asH>@$?uF*zD!J3ww$AV5wjP(l)(c2dU!?yrIH1RmpFhp!`l*UbAVId4a-5Q>FHS z8jqV7C{>!O9w1b6)H=plH`x`W6xl7DX`kk3icWa~a>JFanxk{WmBtCm)0(5HBb6`_ zHOiB&M8z1+Q0+3*nz{4};lnf_+fbXt8FpZn at D8MT(+*%y#SHZ_MhlsA32 at Ua{1!@3 z3~NE^Rlqi9Or-ZxTp{AlJJ&2W#rmCS>EDK2!*=n<3{2oigs_G;?O- z8a}JC<71#Brmo{Cj0ZF^4UFAw{u_4=G11vh(Wh)l#qDKmvVOC=;&$|gc@?)~Hjb&d zUBm=c+;*^!>6`q5jqXRurO7YQn40Q-$gXyodeWea4HEZf1hT$Zo?7k48+wdxRrO$_ zJ{2tB at 3X;h5D`xfwOIsem?_A`_t!LzA%ixWr3(7{yMk;;G2`)^;(FwA$5T zXeHEw`ayiB)FPAfdv(t-yc$(pEZ!|AD#;L)4DwdVYMi*4yPyhX<@eV>ihYcxS-=W^~>S+|UkXw2rh|cFEI9GM&7un&|p+VMz+= z`W8vor~a!35ZNiK%TNhY3}##6tp?Lz#al0tZtDSX?g5h?-&8)*Om8piKRh6`!=gaDP;GV at wgJ=t zYz5e2Mskp0^j2t;;o(;V at Z295oKITqFw-@AVK53Sy?ZYr-7R&cHq(XB%KdBJu!C2- z(zh?9Yxm-041vNyW;ziHJ4#``p&Z7^gIuMVrJ at KdTI?yRBt_v;5rsuFp(u{s%8VlA zTS at susk|My)iIisZ)3)Q5g=8zkt&H&l}4;`=Pp*Mkx|r;@(8JX2bN!ga#}?OxXWx8 z!P;6uUb=Bvg at r+FSGdx5Erd2<&}JrBku5aC4&*CXl|)dPLN8%6^q{Aehy-4PDz2&; zut{_`v at thVZG(Gcns`CVhmNYzg2key0z)j~c_64jj9r0E4SU4cB)Fklur;pVS{FfK zc2(`Zix=&jx%(@?K0`M2X2$4+itj>F5Py*ZKQO2T|6Ii zGyW=P5HyvQ#Fgt|o{nR?m?z`dZibCxJDHL=_Byi~rhgS34voaKe0TiaOlBsnB?P4R z&}zKdNz6xj4-CQXw-ZI_hyXLP6byx!-fb4ALDeppRA-ZR0sAFy=-i33#2c>f#M$Nz z!cG)CV3CqI8XmVTxo__J27jB at t&;|?UFR7F-P1SD&c1Ob58w%5l+1_rK0XM*hvRXk z>zc{{n6o%jx2BRJH=UZwTgVqvm!|Tca1(z~Q~3qS0FHf(8TFdVk4Q$lrV at QFo>j+x zt*Lw$Zl at 2{RK5k*G*G|9C*)WnGn0M5O1B^@L$~1qRHsMpTw2NO%EcX<(f03ya{9Uw z#4)yw*ySA#WbbvpS@;^HO!D=Cu`a_tv!&V4tt8>V7LWVFPUg#7TyuSeza;@hT^Zok zhw7h at 7mSTVlugzqDzFLMM=`xK6PcFY1vO?MjfU<_cc9&em^YXTmu)x91_)!!2g1Un zKF#$OMbB)^Sm)tzXP^A_^vyu at I?ojGoiTOsZA^Tep@*3kXXs+4#2LDoiSeCGBu%vt zK>|T*7JSKA)i6-Ly9!vx_=x9$R=(M-bhd~@OpumzYlfY|wP>mXH5S>*3tVADIP^4g zpUmV#b35c;{@?9nu}wQ^IL*#jpoKp5^)&9Y;q?NCYCWNA`Or^Jt}!nZd?(JJ{suok)p(Pkv(W5`99C%bwaxF7RfRXyJk zV|rK;KPguX?ZoKMubPzh)5Caw$f=d}LQ6NULyIj{jMWpJz=eQFW=!33 zVZT8Z&P~@<{m2EkNeio7kkpt)vH@`mk##l9O_HYa8q7-)T({ztDM?~7lbA6{nySws z{i<*o&9|oVIXMhguLsJX)EqQu`SK9Zg6%*>{WUH4LbO8FtFY&xY6k7&m9e~ITW`#6 zcD;wh2rq-JcdxWZ)71LD(Rr_P?p(QlW+?W3eH|(BSc}PIxoq^fbibelEEm2=Br#?t z`w(sj{Ni6QyY5l_ at SN+12YFZ*^MO8FC`pu=m?D3n zjl<)Z7ZS%j#M?37N at C^h7#W+YUCBNW3~Q|r5Q7_v8yrsILDy8Dm^0jPZkQYvmse=2 zZa~qdSx;G~4rPWcJes&3Ri_7-+kqi={4vdzza!cdb^Hk?m_Hw7RYjfVLXp}iql!0G zM;X=pT}~0TQANBnNrPdYI76kT^4A!ZgWD<>Et7nPB5)xg7eq_Hp3K-{Dc>4XXEsAL zsRF^SwEGBeeK5HK?fAU{LaIPfBcU(E*88~ha+QvAZ3DqtOk0#3mjDmkUJw*aQz z9U=?oQ5_D=2Zt6@$GebO#1&aM8~wL!RPQPf4&q-8e9njw-61YRJ9N6mf!-0`ZN;4! zMMg#jNuu-gG0rY&Xzo)_XL*nY6cHj*CRAiYq?HYtuR|vjS5J#I!(}>5!abb-HoJn$ zss$T{=mRrkt^KT?=2Jx#-qfK-&t5 zDuQJYLrWZ}c%cmDxNt}qdJo^i z8 at i%eqYOQEY9XKA9hKgxtY7%ssAH$Q&EPaffv3|fr3jW4gyjT%tqR#IKJIP$LAFvd z_;R(T(uJy99;C&6sH&Zi$PiuxWBY0+F^ZW?2%2vPloA^bnqtOL!F3TbLBOaDmg^nO z#7f_QWu&!_VSMZkiEUDmnHH23 at rU%F`td|Xu}A_-r at L1XqKvSulVtX<*6{AjA~ zhuUsGo*)vd5K;WMef5~I>0_7>L}3+{%#zk3P1P|pjODr)U~!63>%l)dpxx z&yaGQjbW}TG}~q}5Q|i57We1LB(v-2pk5QocgBC4*<7^(ihLoH0c3b at w!(14{fGuU z3u(J07P>WC=n8DRpC%>SiQFP$tC{{?Zvpq5nsk809wZbX8NefPKj9)_R4;ofKfl|T zhmF9v@}|OUq7}h2VSRbOL|SF77y#Q1SdSc8KsdoQFC#nj>-W@&<62&H*p!Jx>w`GelB$p&F{)Y8zE|t4-Oo zQ>qEBsmf=gU+q*#HLyXDRQr%bxo at os^J=x=(+Pi`;Sstoq1hy8AS%G(}7ZaCyhnr)SWF<_LIVrP1q>Ux_d{ZLc4 zZ*2(V!?dWd*eW}(qfy=MN?HA_;#pbs3EkB)b@(tQF(QObu`BMW$d5)^j^chx27QB2 zcQ%9W^xWV!hw$QKfQKe=&gRF+CPPQLg8JcZF&LqLD|gISqYju4Ar=c4jPfERJ%(Gp z7P&9N3Axo~xs~4B=h+~?mzYU0Cl}MWe?pVJlk1XjLP&K=3S6DtKJ5L{4vW0Kas`DL zN%t^R3k|eV1mo6{eI{vSd*hHU at 3z8&-(yhcN{rB1%)(YEhucWAP!Web2&veh8orDf z0(oKbc1(_hVyz1D!p*`$lEiYe%uq5~cOpn~G)S_?d{2!LGcw3z(RZb4DEBaFtjex% z``DEkGMD?=_AL?NfCHnfm{T!z!ma6mun{#)_81nEtw!j2B>kFwxng)Rp5FZNrJW*M`^)`#5Xgs&Td~e+^)@_qsx(}UXcc@ z0h|vCN?18r&%KKHnQg%CBe?om!T6!uOsmStzL%V;li~>sVRvGjfg7*j!l7{<%{(Ee z&r08B`rHOwMoB|7*iiEvsfpo;ln)^uq5)qFcLV5_4LGS%j+=c1Qat6`nWr&L1Du#wg#EgQx#0`CH at TN!3 zBW?PKiSQx at V(@J;V?(?2k>3!vxQ|&EtC?0aRBp4<^GI>g{oIET-W at Jhc5bl4)dc{9L#tQKEYH`^Us$;!K z*$$4V^SwRrodS;8d%NL=E8nWA+=vfENj`ByE64Vx(JjjkkV8xKqa49 z0TTs at S&*RHHsa1Yu7Mm|0inUEjTjnKOJ>PcRRfMTG5BU-=Typ*QMVB at p6$y(jAntI zN_hqw27bgSmkSHih%KdeZ}i$7&|2{6LEpw2XV`Y{t{O-QsvBPq!?wxxWJ$*nS82*7x?#^Tg`lz=ff(el2wyiBlAF z6J}|c*?LcmB8dw-R7m(7-R0{f+8`2PwaVcJS#U7EkL0WNY5Nwg;l%O0H}1fgA7z-t z{L3Fjnctz6A`m_?LM2AScaRt at JpCv|99md5eUdZd>0U#{$Kt%u(U`*-&Y>Q+nU6+1jeE_koTSxH<2+!Bv^Psd z#Fm|t)YqQ49PCU5xByR0k)E&^8l?w=xawQ1#GfZ^Ekv#GX%&^vWkEo{PO at Zkz?i_D z{cDkJflyTgA#Vu at Q>3#wp at k$BO5^4M+sMaWDUtU7T0o9T9<<_J*Ltnlpee}Gc17=2 zo5f0kS+Y43i^q`cOU=?Yc^fLrWliO8Fk+o!&$2)s*$9`;F*W&9bM1i{FJa(vx)0 zqniKiC}#GJ!tuWug}VPJR{Re}VYNSo`-k2q!C0T=4Y-R58Ai~qVjBf^%7@hwKxBnVv>`XuA)2(D9)V(N2u?Ox#drf5;GL^gd#l)N7AF zLhHQ8%Q{PsRy=l@*kg-qH#)77HBO93>@~+$UJx%>dW~^Y;=~B5Vnaj(m9>-^0akDw za0nVimpK>LIj46)o>-<5G?S#c zWdfk$R>*XJL~kKwYH8&04VjtX)v;L4VEKM~q!f!m39O^+5X;d#$QK^|0(Y(d<%3I3 zjmxl$@C(K)cpedIDxb#)e)JXMBkf8eJBz!_LgGZo?Zm at TM^w?U4raOsK_W#?p`3SO zJy_p%QL-sW-zplm#+7f)2a)PsNkpL_=w-yQ$e13La*@+kjW;| z7=D=rT5iMMCv}HA6CL<%r#i}EofMS+#Jw6#)pdNfqBYYyDth&&Lm{0V0Q6hD(6hrb zgcrWUR+$Vf8mc?qq@>dwq~^K-HK)ooXNiVw9l!Lhxx%X^bG|n_*&9K4hOp|kD7wwk z!vLr_*V(OPW{ZX$?wP$!rh7M0X9#z&$>`qV2=8M53?bkS2 at 1c*@^XUISe(tY+ruS$@ z_a at KL42*Pe^yH!7{P?TP96Wq73lE>f;o+01c=+TISjwYfj>oZTvJs$pv7S?tvjMoK zv)#h{yJRf^Upu{vZz6{RJpKsrAn>r9*O8*2-Xlf8o710)qSrwsDE*HbDukLJXed2> z*z~aXnodb;dXScElBV-}$SrP_;tHave20>EN}0uzz6PVjL?>ygFi3>ylIoBtqfv^| z|4MDn89V)CQI4}cu;E!Tl%iqdK5sr-mb2=k>Stb)q9QX|3FXM1&&JcFPHN8m{ zO$luR?)`$R@%D9MX)7ZYMDo4%2K^vXl!nT;y*iQ1u^RX^reZq9jG(taBS&OFff$R$ z!iygRPUlQ=SX5Ja9%GeiuUho?_akl<*$Ki;l?;op=nM)cx>AGaJg6(MA9>?=fgBEH zFu*6FEfYs4d1IXFVY%l3fe>|34tzCsN+`h%ZrN3mapDv662u3n!u~y~Yi+%#6v8+! zR7qh at i_1_4HLo-q+PcPpBp6Pu zCSm{vf|QguLRKMp5ZY!QuO}s4eI;w85_XnU(%n~5B$ebxV~GU}QnO*pR1&PMARX6` zC(hekhEC3~2OqmP8 at B53G(grqF6%ItwY%A{i at ZM~bRzNDmwGh(m9Yag91kCfvDYu- zHt80q{2pee6PNc88VL)1&8er3v^jBq?1J5lJIdO3am!Hn3Is%I3V9*vW((aa)#5)O zmGJqY(9&DUZYB>AEp($)OYU`2H3p{&dLPOCNXp%bas`>Y`emYU*aK-Z!LrR83*bg; zV4=4_E?wayO9Uw)0X*3?vd|?`6SCncM1UDI at 5Cp`Li_iqaGu>nJWlZHbz*pMf1B|) zOG~`R82QT&&OywOSJM9X10FGJkoOFZpux9-v5zISDdHid;T_!SJ_*<;M{cZ;a+i at Fp+{Q3Au-T~7XM!qhjEvhD!TL8FBNk at jZVMPuyFx6B z6s`CRn)qf`W$$sDU<}&$4>@Caxj(l~ee0ro2!Fc%j%v2^Hc+N6S2{n{xYD|vcl_6C ztXxtAw{EK7iznvXA!dRr0$lu!;T`xy)P83%#K6t^cFs7J_0xC!5jSV+;*62(5Uh7*_Sw%k zV>D-+$XO$!vbDT1GQQ0b#-|3Eqgv9$vZ=zF`^m3rocYm|J0Z##9p3;3qD;wU_3(3p zV2O`vF!RQ#N at KKHn0-HbLOoDBs*M>9#TF<;9OES%-12C^4}G~uD~!>6N;Gecj6cDu z5I3JPG5$oUud;pr7YRzEMct?1ACo?~8b`WET^I?7CW~<;Hl*TDdDrfX$` zKq`o}f_}t^s^=DiWE){&V<$=YIvzu3q`VuJpN;69n0hn^hKQza{=>7MDKCkJ9>C*l zRy#$lNZZYbd`C4-P*_jkA-ZZKeno15zH3u5%uc`Ty^&M(uz5V`}Gnu!(t~$d$ z!8b%`W~doF64a~@+w~mibp_z52S at uPNSU)kEuIpk%kP;x3 zGlmF?5ja3~y<2_jtn+gp=g9!1E+HDHZ48i_)!8u-DI_ at 7A&%jYgrS#CkT|rAlmdq+ zi9^?bGs-q#64Zg#j*GzLitp6iaxD|oJX at mm++d2zztuopBU#HZt9~$H1F#^F4A=Ro zf>Y<;GHNLwMpvCB5OxBU=IX2tWaiu9P#?qu$TR{=W5i}Zd<%|K)RjIg5!NvHM+wt8 zu0UI=j43Ya?@Z2>}O z^y(fYjX~vHp{1Jre0xdIR6dLPXw~zE?)X+Ny$cM6q03p`MKQTB$g1PaR6aqA2k_dM z34B5bKQAom7 at yvyY>hu%riyBDD|u5_8gFU?1EXw76NHh(fXL*9;O`sQ9;9lYQ~)IL zhOY63ZiS&|yixDm2+>c~i6DvMe6W>%ejeJ?Ou59Fzd~`$al#vwB7rk?5yFt7QG8l> z)fq0ml^Fsg%2JoiVYSj?YsK?($0d4W7Zbzd`&hS2R#*HL8&l}pvLD8=9rf!9) z2e&U~O2l|^ES!=k^Y>7u^-wnC-%%FfOA4jRMa+lWdhp-TTV5V!J(z(`$$@K$Zi at r3$20b at _Yf(@BmQZzZEDYSR4;EyY_r+>a-90dvm=HpYXvOebc<~84d at dVvf)+-y(s?Cm;6gChQ zc4H8r%|Q|g0k?;F2#}0lv)>@BRUYK4sazi at 3Diav#SG^^bbji8)*W at b*)NRv!krz1 z0+CjwNA>3aIIT)a^%|Vl6sO&sQH6KPRHr~Ok0ddplbE4N>_lMS)aOt at K=CN|=w?3+ zUPJjN;j3FBP(Kutu=0U|gTePn1qxC-s=-0%rA*?9hjoVn{sY#XUBL at e2IH>+{k_Y#4 at P1!~0%dzez1x?h^>D)(^YC8dtW&{a z=)5s_)5aBJNVR1!fVD%N8}r7j1*e7v{^BEL_d*zGrwazES9{j{&FTTYOI_oFkMoy8 zYYqmP+Q1Wo)!BK?zuv9P=Mqy&L?exU!3`yEq~ndt9H-qOaHlz_GGN_&XP&Wyf;!HP z^f1R4u4mDeb)^(?3eK49dZ`l at uZ1q-B6C_Zg@(aC%w;UWpT9mAOq>Sf_Z822e-7#0 ziV8x;F$CQRrH_aFlm0(KKA*CP_=kK-a?;oaUbTsDfrVCc;5hiKhPJi!nAGMwZ);0a zJSFZ2C7f&h2e?6+1E+{51Zd-LJ1#*I#)`6+&zmmgbIC at T9UZHI`T5TBOIkKlbD+_E zzl87Mf%rVgTuDBNk8c57-GH(RgJwgZPcSLnzmOU}_u~!ydmG-yhEF@|2GzU$owhbAGwOu$ zHlLEmTWMv=3S7(3?<$cdtJdYwW#_C>n#xab+JAKN#j+L66#DvP_7%d`L0+>zM?$zA zXa5CMyc9a0Pj5 at g=N1v^0|)jxZ_HB~SHywbJrj)a8{bDn$8xDt9y&GmcDfil&1n;Ja&+qgDM>0BHoxx zVwL%0&+ at 9R?r3S21l539f|?!^@na&swy{!vV6(eZQ-#hoXXvb7(+Q>No#3fx4zwsw zkiKA*1Tg~-5IQ~krLq-hfWEPs`*Ep%`kwwxZJGlg$^9!&=!wPRPXG;P1WnAXbFZyLspnGk?4V}9;i%oOgO9me#|)BIrH=@( z^G5Rz%s{^Ko*7s?UAoM2wVRW3St89?c7&+e56=mph`@$CvSr7S~ zsjWL;!TR4PjBC>77gus(bQEP$aYH3^dopIH%y}A z38cf+zS*dUYNF|SwL-E49f1mTsMJv9zo>q0oAf;JCwvbwGR5o=g^~O;=Nc1bMw$)R zoDhBE%ODtkp>Z&t4i+qd{oO?VG}ZyP1Df#-?C2kI0D&D4P=XT}ZwzAsfX89LWA~!o z0BQs!5zjo0xR~``^5kgedUHIcD!%{e^}7Y%??5$XKMi) z=K~%SH(Mo{M7vK%3Dl7s(~)FD_6qI`xc%Ygd-Agcw5va4RGk|mDG3RyboZxY-Y1*J|(SP$50#!1Hrab5(rSwWw^ZVy;?|9imtsj!fVT z=a`9AmzhXu7sqP`W(SiQIISk}1UEMtaNz#XtU;{*JIE-v55z83)vZgT&Nx5QD^Dw} zGhjM1CbBBP=Lep&iVb#_U!m}=Jy*UXBfHYU{!vFf|zzK*xP2J2~khh!lT6X@;dcCG< zD;~gwv{v#1*|_Kx5>5C1-lGBw7Z);xc~JA4KHOM7YdqTi?*7P-G8ks3d#u#2sT->fySLNxJTk4z zdB>+L*){unyOQinLZ;rirb~%6tB2!vLiKR?PJ%Z709A17po0 at XR0Co~pX%Xj+sQuB z&;%(*Q9ZoOZ}U9G+-gmH*16JO#Fw{fo*4 at k(LE8?XIv*CHkKA at cgW3p9ix_8Qd&Zu2El_Z3SE_;-*mF at Qo%Oz8T6t4z z)Q6kuNq`A9*ASG=S*LTx8PbcT3L|!Gx{fb;>HU4#GTyL(PhV%@vkI*|%VgNqoFOEp zF4I*$LHtxWNb7HH$e|)eK$vaT^RX z*nlKww*pe7ov_$LFs+VnW+VB*O@=UilVOA+pDQ298^Sn+(@(_ at CYNR(vX`s_uPjEK z%YVp~2jx3Am}XFHKmzCsn2oXdv~Sv9#<)%$fK*8w2Cg zX{HEzW(({-`CR&#%zQpEI6PmO7(62ZBHZB7P@kG9EoLbIV0A9}lC4njDCz!};hhxoTJ5JQmDbY0|Uap_v3 zZ84Xf<+Os!>T%5%!65*>;?gNFsH}F=oxKpZIMn#W|9hfoA)HCIxn+V$TWuP_n^c;E zFfX8Jo#lbRW(tNs(mj6T7*Z0zrwhvCn?r_Fr-y;L%;$rKsDrkxPo38pB}jGa9Ai($qb`SNDu?5n?#i_ks{}TI=(}e83V%Kd9E)n1t*k%$8DK1p{pY#f##8iMqC2*`lb$}>>U at hP6|Yehp##TjT|FdMw7oI>7eoPQ!j zh45KDd at Bd8s$czQKGi`!yx(S%x;oiM!TW*!x76PT*-G{SALv at g23YmT9C#S1hskiy zM{1e-JcD3@@C5`m at bYF=8(^xmJcI_kDU1vHjfaPXfoBN=2f@^jJ*hmwUqlvGU1s0n z4dnU8H6Mi^Z)oE{1bEXj>Cnz at 75>O at 1$pEIs;dRnRcAo?U48ux?WQkqH!Qx5jeyaE z2dM0<{Teem9X?T=%DeI1nrAM8Bt><1oFM`gRCQca`FC`Lztd`-*#tM6zS|3-g60`~ z*&N?+2oo`9ZhZ?Kfl6<3W4d-JZfqPFqWng4AWfmXORhfhRViOp^3_+q`pH*+`Kp$$ z0rE9az7CSFLGm?Nz7CeJ8oVm+I_tGbnyR%ZH%&2Tj^H3~-Q=5(;tl@|P<%@SUAv>H znuouhysWAGjFJa=gbb`+Q2l>80;gN+83g{y)E%Wcpje>nOiHqc}GHGAKq))0f&oP1(zrW|2p&&T=)L)W6mG4nDMD!fzf^ zGQ%|oM#i*_y;v`(V^n{r0h2Zxc*Vj(rqRZv~e^ zbKuI@(|pK_HQQkQ2>C-z4W6(WTVL-E!_-#Htg6`#m;0c>F$jpq*7K?=tgSh46}!R) zm&TsP22#f{suxLv|G)Lnhkxwp|F8$=8ny0!--~GK(Ny6p0OQKljzls=K4gl%I4}Xk(A0-4u;=Y(x;2Vm>i&)W!BGHk({8lSIab5&5#~D@` zQ`bP=mIqOU at G_nYX*ea0TZX49#;qXVH2E$h-z9jmA{c!Q*5})Xj%Q$%Kb7W6j!;Ln zfQPEAA9Z|CeP+i55X;_Ne@`y%;)vtw0K=(%AFQd0Y8h2`t95J(-#Cuy6vg-!M<8FH zxs9hdRYb!iJa$q=xjX0wR_iI at 0KP7!`+ah%xbYaC9_fO_PQ0b};a4qw?ZuMNo+sp2 zlkKd7bh+BD7R~_CnGN>E^z=6Y*}J~dqoHS)hp at +v)iZJzw=hWIAdKjx;9zly(Z#S>eh=kNzhmmu%e?#uYw1~$-szmSEUx*s7~ zRduY6i^V(o6dvnq#8ZG1eDPEqU>wvj8GXIjQ$Vi=!zj8AE7oGg?^IZ^*%yoOIWrgz zwFL-jBj?K0SMWI5C>pOq9#+LSpV}#WWq}xqxvz%cA-ZUey|&qJhHhHuh{5~e#8XEq zJlZ((6iNGup_HR{W?sdr?qT2rU|Tt}7VV)h2}a$JziB3tYFa{G^P6{}@Q*{MPqLI(R6#jA(qVb6&)$=~4UX8>AwX+MRP`CpG2p4hB zbmsPY9B2^zX(6_cK)wktk&>EvJl-0B9qBL|lvdacB^|NSTRJygkA&3Dwgx~Sd=9 at u zTk(7JDg2IY!S9)k at SVRUw3A$d+sS2g9l7`(CYN!wdEjFs&~ly61cx1eXBb3&U8KX=a_4|GP$NdCtw*ko=Mvk+SW3RV z<}zF}llS4UYT<$p?iXJX*>*m55kV@=G0NuRkLrEJm zDq(T&I~_8U8mt+$kwEZK{EBbpJ4-dZALxpY*y?Oj#ouy#jlWsSsEx)t(f_6nj9=}L zEGwR0%ik0SqK~$nPne;s-!z>_eP_(^{7vh^1}Q*2`T7Rg{^D;0`J@@j7R|wg5Q|lF z at Cm<|GgUV;T#4$ivN8OIh!8$0DE_u1fM2XuUX1_F5#&6kaMne}pLcvg-q;M|qbrc> zc#0EQ`7Y|&LIK}Mhl)QF+~%lb=7quwn1MM_ygs5{xc^qG^O{2D7{ugY7eFgwj?V;B zSSOL#r`s`g!Xi9tCXNfkANq_7C!?ib1Xam{`9gLlMrgUh2rUG~+Nf*bAQ7RPV(5u^ z-^|$rk%i!)N5)1DpLXWqi)E+=-qe}L;WKP1GaKKX_upA*4dkr_UO?})flwks0e|-5 zYz%9#f-zL0MO5HRfP~W|8{h95Y{if8F3AX4-T<>89mFRDIc?p9NtTSGDPQOh#Wx=U zQ5Bisss<+DR_jjG4)+QxzNAYG-HoR%*`65u-P;~~tw^UBx>vsLBUkc%p3qwIuF$R+ zLuX7Uo*g`r3Ygu4s=j6Y`6hH8JGofw`__3b7CTs;4Gw at fE}5+9A>=!Ze20_oNb)_A zd`H9g&!3+^|L=WT-l3 at T0JA`0CIf^61OnWFye|O`yd%}~+fPwl`=t9K$Xf_78z36s zNr24&H2^E+`i=t>^(??k0Dl2^7vS#zp8?zi2s{XV0Xzzz2UrA92oMeZ=m8c11j|F0WcKc zW#Hj%fVTh+12h4&0$c)U2j~L03!nxAqy-oW5CQNgzzl%-0E+;Y0ptM`0x$p at 0jdFB z0C*W-H^5r}hXGCioCCND at FhSOz+C{p!_Wsn7{G%769Hxem;qJ**Z~{>6#&lxyaccV zU=P5%0IdM+09^no7 at O{>#HW{FzIFlZ1qg$A4+Q7}H%|a)184zw7hn&-?*OU+o&>N1 zEC!elFb!Y=z(@c;fNucTmjG7*{tj^Xpww3h at CsiOyZqfg*^SEA_ui+|()}EVEr+os z7C3CVOtE9VE^=Jyc+5BDlvoRFYg6-$1%);_SE`E{P+C$@wCbLGDWjk$zYsDEMR_`h zjbR-{rMhu>fK$%zmnrAXD=J_f^)8q)`O(QS&}JFH8e3^;&MI5>%HnlYo`=%xT+%Dz z&4- at 7lGG|2lkF%jX0qwkw)Jwlw8WNMkW-kQUtE}Hb7Ys~Ff=7K$u6af9ZW9EP;)Hv z5|guysVR#r^1XRs>fD71CJQB}=cJlUsVQFBa=v9z!oo%AW@{_v|l+C4e5>KVMXNy)B6|XJQ5xQjgD8+t~=GqvGGzmsh-wacbK;^SVxdbo% z*QYsUfIMeqp$*#5w!*@gM8q( z%3@t%xZdSO{f_wo<}Csj0+| zi34cB!ToR{e9~B(WBt4$#^%V+$+bn!Gus at c1*HrsP`}>h6ib>#_+ON3`yq6trKKAH z3W$sqqZ$E&3!ePJx>yOT;%}ZTsm4Va2 at 4I&%_OQd5#rO@^7{a6VHl21HC*a|&6TbW3GtuVf1fnS!G1Y|6YIGP8}vjx{+9X}=y= znr+T;l-d at tB{;*FmpvOARd+F=f}L39!r#$jO`Ft1c!zGYzk zyfq~t8QIdsRGi0>jux^-MQE)gxt~0FGT{|lm`8-JxWrbZD=97oy2*$qNwcdPR~jhM zXe=lqEQNc(lx-CB at YX+>I%#@?1IfJS6g|x73X5~{bka0}MmoG(%8jsY zj>He9V2w>DPa8EQI$CGS$+PJ|Wge5qJ-K8(^(f>Mt3Ic=WW8MAY13PlT4r;sb%3Rj zD)jMH)>X!alaT{U3z}(aV;&3kqzu at Tr_0S>h5swAZcWarf?Qn at yJjU?ky4vYw=xg( zA$x5>5e@)I8BZ+&f=hJ^i`V27p?1 zbquja#lXiR)}{k)&p`z(#9Z6D0)|YTM5ctB*h@=sKC?ClH0%d-u5^IH$rEWs(*ReX zCNjU6g%!1+NFJ$U{rG>26YPC4$_3hESuP$f)%BAlW_=0a3**QsT4ke3NTqRkU;xnU z-a`Z01zFyZ;W8?UN-6fpT|ex-^dd7nG*6cO54k~E-}oH1Cs;7qV6xWI1+c2D%_$}G z`ft&A at Id>5J`_a$8S;N?ORL{xn2bWO7z2i1tYb at Uk5TDGa<;7055jCL1cfZKjVndb zc~Ccr)nVqi(n%hfEG%C2Aojl&^mRaWDtcqw~$ z=Et^PS4J#gVnJz1Va|GD89d`co};KoKiZ3Pfo(m(nDvADCb>L7)1;F1@{GmB#ewEP z71C1DZwm-^uB@{YCQQ)vTjSx at 0lt)OT;?O=);xj)Bt16Hq=R~a67B(cmqgQs&8tfHCHK%5txxivYtbU~2~8+cTb z4i3hT4iM$4 zZ$aoaxpJ$?fsz?Oc{Gwd-Aa~WB!L>B{cAnik2Li0$lF#!2_=;~V0DrEl)8Kjh7NWI zmY=?5e6d7jzQaZsUCQJYgX`*@hN=`51NIs0yu9Z1$;&b?=WkN42E%v at Z8@bjP&yzV z^skWoC-h_$D!GRfxPlhs<4{W()QbmotBPUh3vDGJfxy5#Foc+mynL)T7j%Wl&g7No z5%lo_YTNqc_MUu6HNdazzdU2zNe-fQefld;hb`{`3g#5on^Ij47!OEz;)Vhnnh9)1 zOxb@@FR-@`%z$@!ZZEAXZQe+szBlX1LWOz#OakQg<;jXE)w_3D^~(1w#d1I1%l7{@ zee31*0F6U>z03&dFTr8MMH2AKH*0f>$l at sRBhcFl>+&7NYx*y#k9)};ET{Pejx_^( zA}G)8Z(G3N5LbdCe#m59j$;)Xe=MKG61jly3`a4 at uIy6)GN>f+taMy1UJHnes4Iau z5=a4b at m}|n<*P2zff2 at d$*)TVmwyd-b;iP+RkGg)j;Z8|g4|*Y)E7xqfCJ#S6ccAN z8MK{f5>a at M|M^4pb4g)eyu%hfSx_=yRmJL*CnoDffDJu<daIk4KVXK-3T$gpDROD_A3%lHV^uQ2{Sm-A2R39?=|u3#u)oeLjERx1qgWnZEwVd47T^>gKV*%>XR zBnRQ1buz~RT8H^7 at YhRfGk}%~QI}Ff{qKi+phz7}Q2}+7)*no$dIf+E(mN=8>jkB* z0MJAF8kGCN{bGPHNN=Tv`NzXOgq!N=kZz at h_z!`5 at GRAlklqVdK%lM$NP=`Hv{%9X zB7hJoRQ)-$kAiz(xOys-w?O+~xQAh at BOtvSu2{bkAQ936v`2ifs;I*uT|}H;6uQ9dHz=ez_mA|34j||IZK5|I-8X|4pjD{(t=w`hR?Y{=ZK3*Z+(EmSC{q_I92k8Hc1N8r+0s6n6>aYL*`U(C2V1WMr7u8??zZ#(be;AvR;K>sfc(Eo!}fBnDp6Z-$*0R8_P z)nET_4AB2q2I&7M1N8qW)nETbO6#kjhWjcM!+eKOqkI+GA-=xU2w#ON)Hi_|?W at ph zeU((0ufiw9_W>&0SD_o~8$gZpRjBXt-9+hubgi!swBH2nM_~J~A-?|D-Y?WQ2ivdE z`l_(KGQ at WZwvQg_8;tFP?(?me+EYU){7ssg@}~kQKPr&&r3O(dDu_~2!ITd*m{L$0 z;*aGPJ1_*&721kcF*Nvow%pa;`D9B^&c%GmbHWWhvWLwS7whtK9J-Y`q{2Prxy5-l zulzy?fgCx7k9c~+(t&MC(ZBrBHd3jlY-K?&6#oSm+pObBA4Yu zoY6~1AAdb9J$#pN%bT91=C`|4L6q0N~5Z!r-a~ z=y?v(0Brzu&q-xE&%;9UAdrN;Bw*D|iHnP!^k{T+EX2N!)w+bdLLeK at wx~d2{Xlxv zAiseiyTKr at L#ScYaB38FKQ)$$qGG6cY7S+ga;Z|vN$sQ>sLv_#0}u-3zyIG5`ERKF zH%$Huk^e&FKP`2fYNYU3jgL$N>Q6AV96>!mO`#H~9BLC)Pbn0e6bc`OQlV1#Db$J} zg;o)!&?%x7dc_Lw{ylwq`occ$gTLYM7Y2VL;BO at Sje@^$_!|v>dicZ7OVR#oC*}

    wo2cXi0q<>ibEE&H z+J8Jh`smg??ZMIC==R!^o_Ocms|iOc%g2CjcP1^o*UCmWzoz|MdVRgG#=RJ9Q z<@eW*+cu{zQ-oYB^vlhisk!s7V7047R}{ZoTaetIu;L at f6RZAsx?MSA?m5+h at 2i5( ztll5^r#rj%#}?MSHT(SWLznfp5AXTBua{zUIFq_&luD4m$FzF6j8U{dC6LRmHl1bNTPQ(w_78!MCq2uQ`5k{DU>E zd-v_W&^&zR+nJk!_f3vp_TIt&Dtxz2=dAtez}rWE7xdWy$0s)U9cD?Um8WYz8)&lOEsf26>;FD%&?rLw=h>^1Siu_+(6?&n{=IC1nFSC{TRmiPOI zzRA75eW#rb{Ph~2*Zl&vKR#`+yK0rcV^{{|`^@~KFNQo>``H^&Z$34B)PbPiKX>MZ z;3FUX_rV)iHazgj%BT^~teo~}gJn{b>ixnzL)Y5!XJ1=lZGI^sRlWIQ z%e+I!PHz@&+&Ou%>+_)0{d-Is-`M}$B2HRWjU;4`%Sy}E^jERw_Ru>n1UsCqQ z>M3zImQ2u14DcVcW_tM0Z>JeQdCNbm>4`-pUq#zicisAS!l47lru>n8KAfAn!++~{ zhhG`~uB&qJ`m3*xn||Z18RGhHOOGT8_VQ8hC(M{|b+K>i`p(3SD?5HUDfL)W_ at c{- z&7s@$hX%Wx!q`6_yEy%5 at cTQaCwCos;8(A`6!`a-T*CsWQ_GU3Trlt}?-ZS|e7bf~ z)}ePp3wP{1|G2CAH-le#-duCx>X6q at HJ`cj>GfZqyz{SR7gjn(f3be`)%}a~uT-XH zE*?7gz7b z!cf&Whb;@^>IemjmB-S9lP<-OBZi;9QJ=>w=4YM>Z?<> zPq;Cm>Z|puPwYu5Ia at p`t9$YU&voQLCP> zjDBdxE8}b5c)$JjD_6gN?9{jCpZZ?- at bK!_E52Xy)^BG8yzI<%~IJ~WXYB_ zl at etuTe6hIyCRXT@Vob!5pAE}=lgkm{`tPXuGc*Go^zLT&$;K^=Xu6GXHH^@L$$1h z>6i$Ls~)QI$R1;7->4pM;7pfc8dNbAV0NU&L2vCN#UnPO!tqzq*mFB#d2a9{rtd6e z4ZdG+aA;{Y33$H3phtIa(3IhM$(92z1Zo|Yhet>n7sqai?k`?j-Yk(J6_- at kd|ZARb=YT~hNUIimi9L+5mb z at K9e{X-^6F_xdz8)sS$}pqyycB9VHJ37#7KcC9}3K)>nzd2ZN_QOlr53M?jrzKS~I z*_kYbpA(lQ%hjredrgbPK>Js4t)wBo2&LOsrbXM4&cgJevW79|U-6$ei4k$~?j{Gu(lZg}nN`fh)ST^c7n+MQw{b zTfMz#f>lX*P*asPG)%=f;=N4>o(r?7hl_XPeRM?yO`$^ zm5rkUo{|rIb2nXl@>S~gRR!sah>ITM?=3tt_pKpckn8XgSRdmjVPNFzHN3)m=cSiE z{v9WS4Dxp$=4EC(w9cXK;C1idfS5Jv{!f$W1E-%>9mtX at Asp8Xa_^i{Bn_OIA`-&# z-1dL;bEP$wb=j&of at eN_$3d0H-4Sv;Y6ix0K#d}h=h+oQJgzQ|Ec&CSm+WD5>8 z at jhMk)u&Hs7`hCbI at 8LTsg(Gbvosg%JzX(jQhYBOgjaQT}bO0Dq!d at fu*{kXB=djcVDCWFyz zb`$5SDgMCLZ|V;dCVeukCUgdnk;5UCUqp9=e&#aQ8a{_%8NDV^^L6Tc#Q3vWgE2d6 z|2A`ld#&szzqfCDtMaPkt7qq_#N4jNbzfh<+pW;iy40;@2$#{E-#YZ-NRH%7`s)t$ za?g_*Ts``ltXGLNa?aR1+Hmgj!yxhYDqS_c$F+OSE59k9e{l6^)BW at PTovhe^lK6y zMS+#7elpC(TJ6oGS*zh5_H0#CMV(|3?Q^x*JJEjM-Oos=OPpP~aUkZhN^0y)Q>VBu z{|KFb6x at Ao;&Dl0-R+=+*yW0slLMx%h>-H)moxZX*i|fh=}^PSMVYN9BbaP=pSI~? zi^QL*i~4vaIQ-SP`l+M3^e6L#t4^G7x)@T{fcP|sWv+Ne>_WG*ZxA=|>r%8X1OZ7GLxsFjS zNO>qWku;*Alze0Q;I%7pWmoIT5A)uyWV~CJrj~#5+0lZfub$;>&*sQ=;Ly!B!=B1= z5o#&6)#16vIA&5PdpWx3Zg^)&NVh;~yNzY}r!DdDG%td6E-5_qgyqKIoxEk{aSln&UJrh2_n=Ubnh_k at M^7-plD|k!Zfsa7ren zpF5Fr%5&nD`jd(SUANO7J8Lj|`G}I9Kl3#7O$e8)HR*R4{IB452F zSd~?+9muS5XLHj2Cy{)4&fAyNBgb>_iiXllZ9m4n`MmGg at wj(88jgoy?{+J_wls*U zQ{5=%7slE9&s#qWW46{$YA)qQ6Uh at 2pC2a1>4?h+SsIupycr|u9*$xD`uI?q+DpEQ z at 9ul*6Sqnf2uD2Pi%m>AEWTl-_Vm4jf*9JfQKOvW{W|G8EVwUOsHO|&pII&2G at g9Y zwa%BDBmL>E9;U-(p>_`#8$FV23RVd8?JLX}Rqo=^JNCY^p*uJT&n{haz)i>R!Bq~n zn#V5LWUFb^Y3jr2?z6UL85y z;=C=|zfodzEir~}Ty#6`%*Buss?yP)EMmk=?KJPoGEFS)O4na=uWmT?W7pZ4lZ8 at R z&MPjN(t2$8SgiBevr}5HS|)h%mD&59j+c{E-6kK0G_7!vzwgBn9#ErT-J5CHW2H80 zx at UcS{}}nisZ8D>1>Om at qx4rcsFaAT9ax9)H at k4BrTf&=EGxO~`TIWEG`us*3NqAw zx$@&IVcm8I7Oms$?*}$NIT{)1 at gm{V#_UO>Gq!tsk1EMpD21>@rS%cz)-vA at V{=bc z%Ddj9R(e0|JA<^C?uuP|zTO$}71|ujl at RV*84Q&^2EEhO<0(DF7EMKJuCJ+g)8hpfp^bij%RJ0XVc4W ziEDAKR22423HHHNwQ|w~+RbFvd0na|KNT9jZmu26H|{qssDyk2sd(Iw?q@*6_8UN{?T zI3p!>p~zJ9duM;bGEeK%e!M+fo=eGR+|&){+S#W{CwL^J*f+ZS?ea0J{nPsfbmLXb zhSxD3C1~2KytwiFR8?JuLXaZnaI>}O17hw;--FGAPal$+SMOVro!ryAhI`~lK>F?$ ze9iJ4cE6ie$(2Rhs)A^OXEH9oyTBvDDxV}zG!lqRLhK_EowUV`3ODB z`M$#J1G;S2)<|XZ>!>tpNbVzkdocEDAT`?AXl+JTZQ%2z-skL#aKnrYo#^=rCYjhl zcKb~iSd8v5xj$U#;W`>M;Fz*C!Rh=p_E#r12Xqu(?|wP3Ca$sV1WUf2L{Rp@()Wdu zOlQhhN3Sm6baKrS{4!GHsS{d;>0H(R;*k66-VdWM@{B^7jy+yZh~MkvmR>RKFc}z* zt^UYOV`bpTNNAhl*x?w#%=UFVQSgZ#p3~-~9j5oHv!|CbU2nr~`WM=bY{#ZkmgKo@ z%}bwB&xt3zDz0w6RWhlzxs~vCXP1>vM>AX9&4wNOMB8L;8FeB`Pg;zE%j at lV*WDe> z+nf7PxbEKh3x%aA92;p16KokyFjp;Y%gJUP5RoPwJZ|Bl$93O+_04>oV-kZ{2_(IN~sro7hGPxy|B|Wl-J)ZBdD_b$M`wq!y zCqi7GqZN&to6)EM!QSB*R;Klf1G0y}c>WVVP0E3z%%k_eay&H0X0=r7J0>UTGm=-IwzJ6LVV;HkWU7IUMFm6Nl2sbHA7 zOWt}x(y`nk+zXcH_PvQVos;ZhZPoEv_3=WFThj0D%iXa;>Mq-nf>NvP7550YKNW at u zUM$ber^|n{)H}QJ;y*97w_R!UyF>pvLatLH(%>dZiop|Y^{7~(DlW*q1bsiwZz<6HIMPN zPLBNURyK+DJ4^WW5p){`2Oj9uQy z*Dm!tU(BjaCq&CzWX2#W{pjBIvYb-ZjS_b)&sycW(pR?3rsdVw$!=;(IJLhsbM+;s z%B+u$UqpReuU)2fk6Ch=g)!p;yS%Cwlk+hK#C-Yr@?A&Y6b5o1$d<@ln$NFzwlVV3 zyO(8b2RnueSYLIm3u|h8G5q3p=5F#0QJYJw~SLHGzlQv;a|51-7`ytF(smvBLg}gp)f%v=@hLF(Mqx|vvE+H9w zS&~z)GURJ6_W4;`&k_g%FEFZI&n(#!&WDOzJ)Ow&HZ4a>uq?yRez?CUwST1k{e#XB zk at iP9SZnLd8=6{)A4qPs8+|>d@!MqGG6lsghgg|dHZ2oSbnnuVAE~lt%K7AB>N)C$ zl_?e<8NVu9nSW9s+UE>Y(v}s8CEwUXBkrxw=nPQK8B!#V1kAej>y%+0 at gK726j%Nn zV8Afo5TsdYAbI?isX)~^o^YB7_F}bE;r at _v#kNYtq(^M)ibwU9#HK|pkBEJ4Rg19f zY?0L=PC1oIwHuh`o3S`vZhM1*Q{bS!&ZXG^@{l}pLq?-`aSiEPBhV(*Z9H{-^iua zt`jerw!1CTbLXyV{b1s<5Xmr>9745@$jy2ao`1dtX^FkT`ngD}28_vz=oGAG;rFIr zCcbsINy!&uorv53Y^R4^(2(r=zLA-k>B{n#_0b1wYm#<^gv(D|jAkm%E;02_Ps488 z9umJ>C_ZBeOWss9XJ*X_+aYTMtx*EIdz--Y0n6Z}r0j$H}*7 zM at sfFrXYEbO87%VJu%^{Tr7+CYxwoYTN2vZcq9$hER_$k-M}w-Sp^YzT@;TjOA3)S zIhE;f=4_rx!|TyUybp&)&4((}&W*LjzRYAQ87L5lNWU!G>2^$fNc^c=z^5h;om&&u z{G=W&aVcDx$TZY39TET?l4SyXO at Djwb>Adz4N@$Z~YhghgRoN71*CB{MsDS>oq#)mph2k!kdQ zFf^5}3Ur|_h_qT|`_Lp?03CY_jD zV@#GLNG at Tu(%vB;dd*{XZ?*Q?tA1XZE?zMEZ at EAe?>mu>y>Wchgf zELXN at DkoVlnn&4^n|nq^n71%8a7AFRzM{TX_qM1_E!(TlMk=vR6sc+sDyxKrvMN_7 z8SkJq#LC;Ouu!;sh_to+f&3P}3>sPU@=%%cFLO6Hx&0%@Me|z3?cJI68Bu8)hGb_% zCHGegJLu~PC2cq$*mpr_oyZ7}xc}Xa68AdSihZ}!+NiR`Q_ at plbW^VH1F5f1E=nt0 zz3p)^qQcYS{Wy8ezD%zUxeIjiv`3?#f)414*!ytFguWQYIZ-T4NG*qC__);X*T z2=>12uf8TGkUr_ at fvTs|gc7MN_aM#VB*m#t;?$V|x4bZdtKY}{F0#h7_z}ge4tEYS zJG%3z+DqKT*$vz`!lt&oaB?brixZ-|=iH5t&}pd=)a6NDvD;+ro?X#C0S29p-}eZx z)aY3joYjwiouc*dV!Srv=Q}&q_KayB6}gXjwpmk+!-A}?+b6DZ>hx;UVHZO)Ia+6P zpAwb51WDDtu>H;GU1{6gjJ@` z2r{7ar84C3=g=LZ!&>HCqb!(nUuz_;jYpiH8Z(%E*5+?**LqLEy#4!0_E#!zw{?1c zE$PZlJoWnPy2cKL-S1l5mbNx$;D%ldwdTK+%sEo;aGky(>A74}pNDIs$SUhcHZzmqrD+Crq=YBQL5wd6?{rzFTL0 at -qa_h3*L*nfunzZ z^Ez=d^Mn7vJ7UXr-zME!cI$T4`n2IAe5rCDq_6v!`KA=8Vv;7r9wsYkj9fc7edB6b z+?BkC-5HE>h%;B{{JeR+n{CIH7R91RcQ+0l zVm1gTm3BL|&>W}P)m&cq#kKWycbA`>g(K%)!bE95yAD)5aekb3 z+sBJpcU1TypX^_< z-8nDkI8rZdsECjIXuI^-zRz!Vyo)=I4LjcOTB-YPU6g^PpWH^(e|kB?j4k}$s(or@ zn=mSO`7AM!tP_{`&{9Z7{7r(n!C_s}*yFFvF)!894!M7?;MUAjzICp*o~Cn at 9cJobd|(%9 zljPCZC$OSmG^22z9#5BYL*@Hp_ at LnK12xj@5Bzl8YS=iglCxbN+tWW5Yb#9B(w6|S>pS@^xvG{aX)6R711e5F<{q(NX;ktV>XS+UXNfn+ny|lvl;|32}&(Au=)q2vM zuO@?K9CyAqb5l*a+!XS7^1i&wihytquU>0~8mk_|%sr;FYGeKJ>oZTCAoD5=@zNhv zn?wEDJ_a6WUU;rk1gyzbDmPFd#PH_b%yU at _gCnON#FUp zXV+#S-;wYHuGn~qGJnCiw$=Wl)w?TnGNl@)X)0VXxRmi&8vz6HZ2{Jav2pK&hrj5% ztz`Jx5 at h$@p&`j(ekonkVfqx+c&wm8O=K z)7)>peU~WD!^~o`+H23nl;>iz1qZ^oI3D+SpXF?OCVs0dU2!FsR&a{1aBCIL$1aeD z)2l9X<|(=QlKJ&vp&`Cl?djXwGIny=)cWcVGCm(Z>DZwu8sRj7>7SGiFv7&F*_QF;vsTo62)1nIr{hi-WTYE0s z(!=YQAusiuD_r*`ooe6C;*cYPZ at Z&?_gjrE*B#h5J#3~DPdLiB?uClIX4R?ZH-Z#0 z>Y5K at 6p0T+tq=O1%zgNDuzBC=W>Qab_L33qHNCsj1CA`O!MEJ>W6vq7Otzv4s at irr zVRHVy7f8=v^Vc+>{Y`O>dv!&K(G^*%) zBkq$Ncs2IG$T>Q-HY;PT_tNKqxFY*=oeYe_gWR;}8Gs7PaRx1#Utm`1IfpqIM!kX2 zaCDIWJi#Cxg4vXqIdkbe;m>Vh921zIpym)(c2Psrzz3E;JF6k|)H1BEUC<8ZZ(P-W z8mDzZJu^WK5rCmpa^~p?;YV(f_jjj#b)`_NF=x at BTI71n6Nyqm4zq-=Q-% z-oeKkOUA&Tr~N4g1!DSp{0Y!%3!*_Fk+C}VL?_T at Eu;n;KzCsz3ehByH9;2$nUa3s zJt4gXb23>lG6wOaGb6hHM7frZK=$?`V2OZU66_1ucEmV2!LxNh(`li9j~?CuIyr+D zKD7Ei1aG{00H8}U$2(y)T00*v4|Cl3>N zny(2$rdW3mh=IPLpvB8M93_YXau~uCe|L%`0IreN7)$m6jJp8loDf8o4s|}qlf3ZW z0aX8Ib=XhC$IA;#M45sN?OcGH>#GU-Qh>P;5Zt^Dz~4iF)!;r2CMT z;t8{G{bMOI#rsl5gGUK1GcN*{6`9sUPXsFUtC;4L#UQ~W0M<2jp z3#}j71A5=%Fo+2)jNU+S*7e4^n_~R|h3x=CbefmEIG7#kjHao9EQOV|5|{~i%f-6Qw|Ro>Bsv+|L&tx_8jfWWKn8^Mv490fFf%qp9eP_) zTSNjW;V8c8sCEHsq&4$!0t6^XunWKqz62xJKn%Kd?8XKl z<3HC!aUz`%x0C4O4jMqjM+h5uV2M|YMU1jLtz(SFi7h>Oq~cu zb1%klZkh-l(I7!@*7*PuoWDf at LEtG?(!wAUBm$N?fH?!$s2p8 at 6r~y5vF?r at 0bm7S z2|Yz at 4{M2z_TGpY+72Fmwqu}dZ3tqC;$V+JT3Z6#o?ws&`7MAiI$LUy2-|p*z)U~U z}BrN==hIi!sq=LlB{K|1JhI0Cx1gY;C7XRu$} zl8ICbP81FS6BZ~p?m*vMU~oa07S3C;0YAm8_ at uBr?A~ck8{R)lMzP>WkB#0;L;uq1`>aLFT zQO2|dH)&hSY4<&VwwJf96V}1U*%|9)>p~*A0Ue^V^&!GD at kku#0c1lWqU;<*_0J6v zqO+x99BDw`pJ at 0(={RCNylq|38=lt|%KV537v$QPgyV6h&E=)zj)rVBQ~AB~U#bSH=YojxAAL>vi&*wC2* z*@5NzaVrE*?cf=LGA}qj7L64|T|i_PyqEs9dK;}SS(7RzL-2qB_up%@=+E)UR8=kH1IsR%><@qBa(SQJoZJk;g{ zwCv>Lfm}sPC=yWy5~Wz=4mw-Zc7?%OL2Il7dj)tdA=_oDWSr13ARtCwom^z+W&~@qK|jnSJc21=;lyuvdIZM6NCJ5HZ}UQs!>>*1K at QvZ|6v>&O782*SOf{kbm) zV!QwbGDc;%38hLwCb1yDC3r00{rmSwXJ;qU+}w z7K4$sGy=K_uNaKw0=y-9<=pi%Jx(4l^)W%7)D%u0K#m(;u|8p`oV=jlm>^n4Yk7a6 z#|1cpqfe=6t7(BhZGge3TcGr&ev~KGex(Pd&I3mWl&OEvT0njWh>=?6o&6I%jI0Hf zo{q5vg&rrkT229oQr0!2qGp^ktLwY<-G4iB#C=D*03 zqIxrPIynRNl3LDBozqo#{e>P-`0qf|f0!JE<~}f^T;NLnOz($9Q1e;TASjYjud!qds#pa z)%@8RG)J#vbJ|MLp?Tf>6Fusv^YpamuJgM23q2lmjZ&Zm%+aD!f>e1^e(2^e^te!+ z0LE at PM~`X+C_QZ>*}u?3=JysVy*aBJqwWEJqlfDJJ|o%vf1t-D`$IQ>;}3EJNs9h~ zKgw?KCwjWyC#llg^#^%!Sx)^+dg!{rQflf?>&J6v>|gLlwRK|*Czra#AN1u9^iYeZ z=phd*BkMVT*U#VkQ7oRK^Om3tfIry7;BWn?Hyetr!*Xi*&vrla!xnz(_v03~@MiaG zdGPms|HJgZrXLMLIrj;Z8d9M{c at jK8LpiExf?yGE#0NfsqX9Az8hwBh1Rs0w^hica zSi}p#BeksN0x03p5xqeT z1zwM~CIPG<5&&`^&_fV$1SNMcA0N;XQkDWZ4bUDBYTQ7155W3^IzjLuQQH$i8IJA) z>fnf8XdlRdBft=Tw1qwK)V?lg+j;(fp10Ib%+fPw0e;s4enXIHl;0!smEf72ofa`< z1oCr1t|2t^6nV_f5`THprUheM17k3wF9Wa*<&EIy^tljS0t+Mp`S$=4 zhcci@|L2vlN2N)rp~%e#)M62(p9lmqA2BQkZ)kZ4J2LdEOn&ft5>Wv2rWoE)#PBDo znt+NIbw+T_0)C+YPiZ8BG57!I>$n`&W7V|K|*r zNKKuF3E2$j(V}w-Mzl}~JE6Ks(LAW3Qt02Gbl|^fqhmmC=XBs-*^vW)ozZ#DTgTt@ z0@|c5pf+c>(8}#mE1Vk*%E%YA#)6tTi*y8|!dA}c*sv6U*3FOO^)GdijLLyx>COP! zgpN7SkveD%OTX?I|K3jUck4&B2*~mZkR?0v0m#xFP=^{o0J$w#7cVfTGs-g={K;9!37-D|aExP}rZjJv%x8`I@(R+ATa6vW9 z2VK8~JIlY`k^TO*CjX}GQ}*qR=)V1Nf$b~XlgU_j2SR|LzdM0Q-XY}UMN}d?x?tVy z$&&7K=PM)~N$yJaWOpfFSs at tG6pzD_=MGuy5R#RW5mI4WA}FZrg!RA at ov=j502E$; z at y1Z;P%A*y9A#ZtjrR^fqnqv!^1~D5HVX;D0R20Jew^@-+N+@`Bc)+%Dl`{)bcc|l zl#J9?8F?9y3&B|W at Ng2z3j@RAdt)8FeZ0T`{)+OT&c}g(cifE)FeSNR;e>IHiVkuP z+w5hrvWi$a2O$+@>0f6v$AI*oIhet<8 diff --git a/Lib/packaging/command/wininst-9.0-amd64.exe b/Lib/packaging/command/wininst-9.0-amd64.exe new file mode 100644 index 0000000000000000000000000000000000000000..11d8011c717c3a1c54afbe00e002fab6d37766c6 GIT binary patch literal 223744 zc%1CLd3+RAwm4qBktU1P2#rx$f;1X!glJ$4G{LTXmIcM=w7-sio4exJ{e z52>!Yb?>?7-gEBR?oy at qtrjeTAXwo~*9DsI*HaEtI7-n?ZIj`xS()fVA**I$bF z!H`)P^mVkk_}^l)P;R^O>rugPE)T-5Hq*=z!nRv`=gAR-@=;3`JP>?95LRvCFoh=g zoonuu&kO%Y at od7zX_x?gk`2E%ST4?2KWZ`0NNt3+QlrLSlFvJ8$#eIpEj z-&|Nra#PpN4Q_FrWR*9WsEj1F0vOmh`AW(plW)wpGg5}E6=E0ITC4kZ$F zWzSO7BRPK7rLg at 9JE7F<62myGsyu=iW^l7%F2ZA*wdGIZ?_Q;*KDbO_+kiuK=a>i0 z0 at KtkJv2Ih7bNP=TOg&TJ~U9N(S!YzsB_6T%|cYM1z3~5Cy}nO57*;3)Ax8gHaSAW z)~~|{=lKWBLb8Aa1t9l&8)a*<0OpM*vF1 at -*A+I`m8Y;rT?GmYy1aD=Nl`cE%x}E7 zP0|eM9%xsY!d`W~2DyAJUdj$C>zYH!kQpH2F7)C)BR8U^;8jog*Pv zVvFv;QQ+ifMDD*KqL=m&z7YN1qd-5S>q;7(lkqH8t$2BNadt2^%n*nw!k<)vpOIs-09I6u|7 z%~x|YWY?X=@Ray1Vw;QD=I`=FC9BMPWi-#JFim$}kN4_%J>-Pi#qbiOQq=j!3bPO| z!+QXbV>DNa-ep$UR^8b-AIoor2I|fOcwf_D6wl|yXJYYwMDV6Sbgrw+&*lJ&K9cKa zOY{8fQ)!+wwEfi>?#xApEShM0 at p#79e(kB-*uLqN;K00SSav#&mhIJ zL#f!LSlX268tM at xD%*$nS&QGj0|6{vWvaEND|$>CzcF-5QCoEw%+Yr!>&Z7$h4eP1 zb7$3xe)?Q&V0rM`WF9PW@=bA_?NJ!Fm5~x)!WZduBd2HqTx)+3AHU$7>*pZ zKnNBE00%ZsVKZE1yjrNPb7vqb>3-H%>o*dGp%~UlghChk^^K)$i$8YA8nCqb)p0^7 zR*LQA0E|kttDZyxEpU~mQbwM^v2;15P=JCfy_QY!49PcAR3FYXfDt at M`116_s^kh6T|5s<4S8j z3pydM3Viau%0Hg$;0?^31pA~d(N*@TK+C+mDQo>4Yl$$7sB2=+m06F~?I~5Cb z-pMz8?ilvQDtVYbVQz59gwes?If=k*J|}S1__;w_)%ek&K2U|Ewn8AepR z8XC+M411AAjFP`a8$l}YRhNd()f;hWN%N)qNgmxl4|Hpstq_DQ at VlM=(s)E6!qu#V zYPLaP`#{YGpH#Q%tL)*{;9^xbFMCAM>#I)B4b7 at 5$Xju5RYCsB5mg0`1+%IOmV_q5 zyCzFkq7W`k#U^0%dQggHwfRC~Gz#!Msm at NAwrKjZf-oUHWQUxJ-e@^rYe8nsOPFgj z=ov^JT7 at dq+XV6e^l1TCpn$7)I--ckv8)%twnH1jrrlq~wf|K+OoBQhqr!q?!1gG< zhk|p^o?y0ll)XNbrbKP6(8F9d&obbxN5fP5H3y`yF0Em^32w7SdpQbuN~CZ&-bbc^ zJWop^WWcCCQpP1%%greXhPJw*7XIT-#D?t;6)DjytQYjwy=KDXT7W-v0ThTje?Tv; zyW1kfH<9RYK1K=%)bwD?9kG26;Gj0lfp=5s-Dcf+=q?M5-B(CH6h4l11%Hn+yznuP|goxUvMJANy*Xxan+U!uzrZ4#n>dttO>OKNeJW&ESk6 at 9CM$m+cr9Qt^X4VFx zobJ5#POK+5fF7Y8Tkl77-B3PpJpj6|f&ej82S7CR1M(5WArNFKXp2ck(sBkZa*WThA1EQF%p!lI;7Az?W(0z5!_!>*)Q z&BZs1 at eUeUQHH$|LQT_dz%L^$7l>vp`UxuPtlam_px$NHXcSTIBRn&qvfa>I@#$nh z1YBiES`ekq at Baz0H|Y)|*9(~I)?_Y)t>IWhj at 7S`rl(vI=1S|CYqgQ9tiZ_90Xic7 z*#*pEXc`#a*BkjE-)tk_o0#vN3tSj3#7x5}lMIBNP4(7x*ZTlwe%Z*p{33{ok!b*C z`W9qD-dK#iiI_{MDR$+zqG4$@@!o|F8amTVTBsaAphm!~(0zJY9zZMM5Li~coEUD^ zTr^5xj2xP3F-n0v=tH$TI3nH8y0aY|%lNblyqC&*<}xz;_iQ5CkLMtFm(I74TqRxv z2Hv`q7#Ep!PGf-m9R!Esk50)3VObiTlH-p|*;^Vd)&Q+p^NgWeG?f^{nqQx|Rd=qK zh1f#P*ouYNV|kQo<1DImFqC3Dbl?jTTS_Ceb04^^iaw$Uk_h2+~V) zxy1=m;4d?|Rh|<_jtCM5%`pI1r8^(J8+ki;(`B=mDT|+H!48=M;sMlbO062Y?`0$b zYeV(d(~ih*U1bI35UZ6%RJ13%ZJ&@nRr zgQvec$H;n6cS=0zJIN$)Rz^V*2yiqQ70+2Q+>D*$IVFbQL&1VKf1?|C^#^*D5W~Nu zluyO*kLV_0D1>O%&B)1npg9Uy{Bw{m=5W^h5bnRc5AU~wZZXfb2$*zhU*tFT6(qfY z)UVhKu1V~WO|fj15X?Zx9$@v7{vj%orX2NbpC$WIQIoX^V)52&fE0*~@J~TaX==-ub~3jQC)L at 8D_I8fi$bcX?9BeUwBr zc%3JCl1V_R at AIUB`;3A>`Y=yAf3J}XU_FjWtke$4AKr_~5VFm~H1!#WAck*7Iai~L z;T*UrtvM=&uc4dI#PC)0szVIhCoOxPMA$A%*o97aC_w$tx%AoAMw zb0{M3$!4XXZf1;uuJg$u{ zgjTx`LRUpspbfG|J0#-RU)f*z0dP^1wIIDoE--;%z8kzd{R6g5TYawyyvRgm9mW?@ z+)`SmaUi4UBUG@?~fKRZ#%w0E%* zZRQFWas=zbZ8g>%YWj5X3*AET5Dj z8?@utqHsnVf2Lfz^PN&I?@KI#mWv(^3{Mb>LrU3JA8YcnJ!m5*hz8q{8^e%4;nbd~ zBC39mbQF-ZbR~8I51*|6iXcBo^?(m!)O2^LnX`xPJO;P#V|3Niyfn*5I{;~{3!@Dc zE!yiL^p%e)kv at LUrl8EjA(T;${K06~x27WefoMbhfOJJON-Z96nK>1;+p8{4n?AnU zkrt}tr&DowY|)*CQ&D@&b(OJAel{o1&mJl8v!z}Pl_Vtr(2s#Wn++6P2n1Z5twfgR za1x at x4lt1W&YD at s)`xVbbt;X&zs;fwXyBfpu65qRlYl_F^CO;gQ!)ug>1LkvXfg>3 z)=|$LhcOxSV2J7)827kMfya?Zo11`Mr7{S~cHmbiqy6Eu4ldv}WL|h}27$N-Sl6Pq zQ2ft}GEu?!Ul}^Uvq{`h6B~Q^TS_cAF{x+rugZiS9$q37} zbaUwOZVt^TH8>O)5GBy`DP}=>2U$Wgnk!Ag=6;CM9G=|#NkS?OokGl61&!5MXOcNX zV7|N?pkDjwOl}X9k#YUnRO3l|@T9Io^W!#hgxZmZN0X_wT}Ju&{$#9Ux523ECu7&| zHrVtHc=DkT{Hqb>K+QkcMwZ~&{9Q)0;$fXafHzLTXl@;{vU*+ at WvwVG-%1>;k>;nd z^dR(=7an#f?)Fs~wVBs}Um0!`0O{2!yi;=of5mQ!HY%1qH2UG?3s?=h25h at z z*#zQB(5g;QbF|}+gLneNHf#DlWM at fTzSe{{W-*Krc}ijYCb$SMBUIfa z)(jv9%-S}Cq61?14en3h4-JTa2ctgV4`fwMNAqT-T^851V3gYgRY|c!U?IE|z|MHl zHJdQZnuX10%^S>CZ1m&sGX588|C at f^AvwV46M at m=uTt{&r=XOxeKy^A3*$gqpGU9$ z4zChV0?d4l8oJZY-%iKs!c?91)N&rm!G{f_P&1udNk%}h2t4}bWa%EK5bUYnghnTG zYWc@>Jpnak?VoM{PC|qV(4N$W0pL`iD951Jxk{oFk^))qBH5dRI at 7DDNyg`I5n z9z??|DSfJ%y?ZH!?|fA;)0_($A86S>j14a**XGF*KE!f`WQ?6O3cxU<;8~?~o7>Cq zUe)#ByBEddtqN+{hZJtCqDY?t_mNQwm^L75%TU(NMp?TM#H=@I>m&Agidy(DFNI%D z2k(N1*1O>$RH8e7NE~n51uyyR0aMcb(Xy)m=~7FJRA&|VG*V;+j;4gq%tad7%FhD~ z-C0iJ3?;p~F^}RH_w*3vKA`&=g>9804y7VZaqrds_H9J;xZl$x zhTk;2H7`c?z0hO{Q^S1p%)X1uc`uAdAdBw2hGz&qBs0;6Hh$2RCq)%A=#fep9&+iL zqosY0;!%Sdf at J}ylxv3AQz=2u&XassESt4y?_kJns~?Pbe`JhHcaEQA=4_i72=>Dy z(m!vOfnaXYHiO}0h#w=sbn5~xcCcfTj>R0(x9X9FiGhX>`+|~kXT!yS4BeRth2l4wcrPvn`vjiX^Faqn_yPUIu+V{BZo7x9 zjeYqY6jLg<7!kXL03-;1K#--_E&&uF$g{{_Q!%~ey7OkhXgw~OKzOyp0v99{-%w`qdVInm9#9%#U?BY_|L{JDZ at JjFJ9=D0<;4#(1P%M=+b-u zj00m2N1pCnKw_(9gCz;q;xod=_t8xwMYkNB0>{d^g at WA-7D_gl<~e@$bS_#cb9=~C zFAwOj)8Jpr9C??|;B%}4Gu3RFA?A zqphg;Sr at oY(3GwKR(P#o<`r%wyD`5*cm8Z5Md&c5U5y2Y1ziPr$-_%7UUFb`dCMs9 z5Wfw>icQG`^qFq0x>E?|8Wupa;@%^!1tV*%)gifCLUu*3$BE$t*kv^b1U}u5QEw^0 z2Zlgl$|*(W)SJ#J-9tuq-d1GzkQf at qq@Hasi1?2}lHJd)M+VT^D at jVq+%2JnA@}i^ zFI0eDE=BdZQ^3nV!^@8e82F%hSY;Bp6T27 at V4FAmh$jRp>XpbFcEb9eA|AO0gZlPD zZuS%yP8&CYxLw0O#7s(RbwfGG!wGx__P>qLw4ytYPcU~IY)K6_WgZ`+?8HQi50+Kvu#WjuGuu=@uCN<|~ zn*!jJ=0=S6Vmxt*QiuRUS8LDdw76uv5*d6Go73$_3Fb7fKbq_o&kU1C?vgm0WOuYXOmd- z5#0G>nggC1#PB$1Y<#nY&rc};($gHg_9F4YJM_If%^VD9KDHb5;GM{-W4}KM`>cU_ z9*j%Yr1{T*W4 at d8<8zP)lHk3Gzt={>O8_s`F*Fo07qwA$&PQ-egX)KYogEw$RdlKD zdCC;1Xzk8-2jp928wRy{$2SMZ00o?r`3S;^IH*i_9+_yS=`Tz$#24W5Q!1$WEQ0Jg z7Lu{_4LJYgzo_(^6ER^8B_x0-&ar+HaYOt`LKC=S6V3bv^GokqQlhPtZ8fCZs}o5( zN_DjtwRI^k8{qNGxw`XPm@`^>p_g!+N6oPP3smQZW64(R<%y_IHylqUHbUYm=O#$2 zb^aC_SnK?GzD0t-eXzqlhMn$QBLbYQS7pf>f zx|eS~U66`PHg?;h=;5J%x0+AD9q5~qF;#p54lKYM)3D2Jd(gS4K2763TKH#$jLC0d z0a5N!cz6ouqxp1mj|F#N#L<)}1~yP%=+1NBAeCIAcG*HV>dvtq60GP?B*$9|xnwIm z*tYnc6wenuG!W{!*P-AFpbvn5D0S=&qxpP&3Abk!m*QY+)aJZMzTTtBWNkka=x!nS zy(^I^esZ6Ypp~TV3h$$pX?>EV0x*nF+iJP1D1zcEws6~D`|(4RFs7Ke_xvbA;yp0E zwQBz6I?C$&uSpb-(jI|S=KQvVteiC-e$ZH?nLl!}oO33T_|$&Mcx-Dn1*p(zry2cn zT2W+3=w5w{9oz@(2BU+2JeE3m7}(+CsMikrxQwI1*t=lm4jIqY`)u7g9rC}2%6VMS zRYqq214Y=R6k^};Az~Y~*DGm4^$jl##^qk(j1eQLk at x$I{-U9+eY~nW^tr;dSSB}{ z53j|*KslHj94!zv?roNB;BDpdNo+0`4vnD}3<3L_w_vZFa=1A9^T*Muh&stae787- zEsrBQUyuo98duuMZ&EWVy3W^3MDDd`0z<+1%pZX6wE3 zhgMO3dsg!9n$%qu2^`xtqZjj1{_}kndOs=UJKb^b* z#DLZ!buX8$KC+mjbw at W^+%-5sF47 at W%0&t9c zhP-Ow_z4)c9H`x~PuG*R1#tG|@K|$dnYJ}q-`Hf#?B<>x=1pVGJzRm5rIS52sSnEy zp897Q=l8{A**szd0zO4vSC4?C$g+*Y)iKZBPK!n;;5!7mh{vCxj~~Mq5u2XP+jUUi z0k(ZE`6ty!e#b*-zc6>N^Tkkd;bITA5MkX79a!NZLY^x$Vvf3V+!*fn8&&4q}-TH&Kgk zEW(i&4jR)Czz zs4$U3##n3Eg{vo!GL?~6sb at Lg%@}3I1 at -rkbr79?LU)cIg+pW{T%*%PZg*13)o|TV zB^b8oxm!~KgC|F)jEj$MP2EaKx-*9t0AJP|9HcuR;H93r zvsbA%@_1J$y7QnLZ?|ee+T~!(u$SSi&+KHF;)?yz^~>J1eodd;<4*R8N at K(}WFGCBxKnr?KP+0QSk>*q!re`_VrR55H zmRsQNE@#ld*s|rNZr4677Wm3*@J{~GtHWE1Q=mTu&`NadZ~Iwz=e8?ghq*tzQur|Z zvLPXPbZs`;BY!F6>U}n?lja(oui-UJ&5sUXoGR$lZktEat zCJ^|Aa zkkyOGO-9VtfqEKz-p_pb9r;HUzT3s?i!Mr6Pg{aR0r#u!OzM6V!&SE$$}YZ^1osj< zSkGSo>yQh4>Nml at Pz2*3iOmXA95{~#58CNxF!OOF4rX``GrYbYW4YRo?&70_z>K-xIZeQfla!Qqf4Dy|s^8%d~>mOhlXlNpJQ?tP}lelilYzzrrP{ zo6><4{)*j7>=TP7yxa?8F+7=eYV}0%&o6TnYv#c#nSBKollI*QaYuy?%J|bRT-38C zxlv)e_Bta|eG0LO^Bjc~T!x0dY9wmqK4ML=nJ=7bw%yce7P!Mdcs2}ET(kGmOF)## zY{D^|ZgHOlZWh-LC~&uh(tww1c7^^$4MTpumog4IW>~Yd?%etK1g_qqDZWj(s6>MYc%^U8?7uoo*{4YQ#`w=J&i*uJ-#Q(zWC;&q*ebIuLcY%S<77QMlt@#U z*DmSxIJCb6RkkS4B1q!8`V9#f*Rg{RIa)N(m>t3RLM}xQCPOA=82HJQ3)f0Ui>}d~ zjr8_bE7s7V;IdYnAniPG{Q>pU%mDM@;CXg at a_+22cYZ6^c#!lDX!%?-=8~gRDj;WR zDyOq3*D!2JifMm2fYi&{h|w#ujR}oF#Ws${gj at _8`4G{cLl$FUYZD>&Z9C#svj`W( zHIsX9xI3N2hI at a7IhC(lk0|4;n)54C2>Wzra0H2o5u>{owLHL+el*HRI<7mX@}%!4 zlQiAw;YqJjh=wl=&*e!^CX=9`a|8-sWn9*)85Zsa+koC&-xWHTABQaXN*aY4u+pF*X&z3Bb-^bdFt+>vew;)G9 zG&r at jVGv((N+fdZN0FO#FXhP?MH4&d{9ObiO7DkX0)tlLZrMjLoRp{e))Wk5jSZg! z-tI`M&3nEy_nZV)4^Q>86R2py=ztkhJr&i5Pk?9+j- at G|K7cFnPAO~2*O7aSc=G8H zw6EK6vca~gy%EOoHJs0Ii38{Pfx2@$=3rjZ%NJ`#(@K!S5j`T`-Jbp^ zESZI9MzWq8X%U)j2i+EdFLy~Fk%}XvBIOrc#$5POSMntSdxU^JOz4id4?~%18_BLV zKRZX79=Cd4m>cX5&&f?48*b#Y0NweZlOSg;AI&`3|Hc`hcoEL z$%rDjYM*~fBmX*JT#NS7 zSxnigJ6{=U2FS%wOK=|iVh#5IpjBg2H5?nx^o{-J?5x3gBd>b=lEqjEx zbkGnZ9+WIig9=I{4nYab_h at p>5A at GqBeN0Uw!H_F2tR0na^QRWG3<|?bioj z*lRib7R8p;D54R5w;+Dt_?yV_zj%)W7l`j=Bn6^;%-nlbjI9lKrABXUB<35uVl;1U zE`>rt4m~v1*c%YQ#m}3$DEukZ`5vw6F!p?YyFboiG-+EKk$;@aZnp4PDtab3gK+Iw zb1wk%2Afl5AHN36Hfyi&vg4_2){imjWt84NCRLgiFAW`x&sh%08D05jTz5XkY-~8t zoo5Eo%Tu`|MuVw05!;~tIK{ai-bYt%fGV<~iipkJA15emjXeLDG0FD#!1hmra6CC* z%QaAfvgfc=H0!H;QpNwwCj>cm)jao-Tx!Q(uI_HfpYoIK=-zfWo#&Q$Zr{LU6{+f> z-28mhb~j_r=-3-DOSG^U(rEWOnE5$cX at Xn!xI9f;e3({TJgfZ-QsXg5s7;YyGKY at NR89FXh)Br<-`EIvY$6ep)&E8$Mu=LUHR&cEuJ5Be^LfgI?v(25 zE*3 at e$8)>P%MD;h?@%<_69s_Jdg%G?SY-QkgydTeqT5fd#{D(zxG%>R8Nv5{573<* z*HfmCZ^vb%@gHOG*13|GczXa5=+zr7G&z(5?cRZJKxhv7fI2Kqdlr0w#1cg<4Bdz! z>uXuo&1Q?Bo;Iz#3P?N*?zPP0kYyUcyB;v0lWDZEckx)-jfz at t3L?FyL;X at +A44Yh z<5AJ8Z|94z5Wm~V)&6XIa)-aVv4CO;D_nM&wFcOJSzNbMip3q0+GPrj6xW*9pU^=H zTXxim0ywvxol7k6;Ip*Jo>uX>Rc3tG5`PXY0B}6*(IQj)Su`ZnF2~XmA5`0464zS% zdLu6-sr7p3D2EBK>>MgUf4nNKO6oimJ1jo3OO&G4e&8)g84Yp3U06>qtGnKE3WE5Y z2 at tRQ)9)X zc#k9>+Z5cLP?HIHeK=+_O}wMU=P&{5sXV=Yqbu)`M(+mGXUahPL0 zLVS1^vZ)(}#Gf`NYa+&V at 85vGKFfaDeV{lRzLv9d!?Fz762o5 at BC*0xbd#{mW*Z`0 z&>_ieiJ?PeC$_G~F&DM%9F;sT0#&X9M`5<;{w}F!bHwLvz~RTvDzRfWIln*Vk7*8Z?GCt; zS@?T2rALKZFeN|y5}6}0EnCjFJ`eqlY0nFp(4zceD|Qa6PeG`^2!fx*E(0Of1A_g3 z4I%S?4Z-ohhA;pM0g!G8STYIaQV5FLn3IG8q&e6FQrG_)mva{tU(=hU^>Y529>oV> zaZID)T!4HIjymv)b;(R0+w70U&B!Ne<2gVZ2;OiJ%dF{*-q*tSt8r84&%T-i|BhD= z(O|&9fCI;BHn2J5zCvsS#>BgVj`N}N at ZB(gV1R&N08tRnmSUgS0Xhtpu-hyQ-vsHh zWv4M{Ms_qFQNIRP+~oxTz(w{MmlJ#l2IGuGcT%KI?#MA#3o1p{H+G z+`v7uYow$$osIBQQSg}@XNPfSfFBYHc!&l((`+*N1D4MAg9z!-QcG9+CwdD;Ankga z5*g!)@DqLjKCX$B)HCAJA>!H+6Y`hZY=&~t$#%eD zsHCI8E7t4=;mO*lCbYNO59%$$8zoDlj}5ApSR?RpJ7 at IvgzVnw3m*tI`t^Fu>Z{F; zt7cwI{X`79WzVjq{S>_!YVWSmZUEZ|ro6qf1I+lIG;k{R;~Yx0U~KaBj9c5wB;9oigx2M~?@%Ym5Q#4$w_jY_{3 ze?U6f1j}&{ENgrRy-}i*$TTW zSMlr!PKy)`ib(K3Q;A49%~AkCMa+>RYorL0igF at FBO^t5k)kn?B5$NfR-(@-Hk1+1 z(JG=yQ91n0&aZDS8i40LH`amd(Xk%%Oln$#;{(i}TM9R~sb?I|j`T4}_C*IcU=Zd! zF~s0+U*s+shluVL0zuo}VeMTNTqp*FYDEVckOP+|^MsHC?!CA|WBpLXTFQgu0wI)vYc_aFfx`S=8q-ppGC~ma z>3Mj1Lrs0i7A-oLxLb)7=ho;?+SPKq(D`xVYStX;E+AiR%_3JqgZa at ii4 zHKWLy>eXk0^e?7$6=|$Fj;A%LPmhF-f^2HV7 at _?OwIWZ5JU!C=ST=ilq{3!8Jja%R zJusypK)dR+_lH3d$jORFCd%ATk6}~BuuY!xV##^MGNk}i4u)HQ1ex5&g4tLe%gSt% z- at QXqAvyBMm_#F+GSc+)m~m6agsdD^o+q}{W@(NT=V3Ii*Fna-t59WKq$X$k@;_ty z11#?MY!So!)RHH2{ho7TxDmD3xCb0!cs<<>3#H5B9Ch&|McqYCZYVX`6 z925jf`vCWg$7sH7S`KtxFr94zt)(6`MNHy`ha7#E4)@kR>dK29wNo4&A8upQvL!ko zNgLa#>yZ+$%#TRy%jPsXG-(haRe5=&)C)OFK2}%>)U`2ai7d48O2)EHR1MVu_4CsY zYGtTvQ|xFqn7{Zs9};ed%C+}8dR2?_jGPEYK5=c1jy9d&6GItM27R$JD6(maN6B59 zCfB<9=_QKKb0}zoj$5*YBQl^Hk-vONn-zQD0-42{FGMGxbF4tJ{ zC;*UT@!M$9qy+oOK^>+lULEQLA at p6y1Vd&k$%oh>yQQVB#!+PNJj7z|hMk(FA*NX$ zsUPZT2|dg|$*jDwBsK)G`X}Qb#LPpw; zzMC5Z*sAt}*mVQ6m%qRg_RigidBhh`KR2se`$k5`#{#1ge<^&wO^;fZo#CxWl05IS zjb*R8ewXCY<}_SxCr9t=OJo$)<EdYMlfYG+tLC0{Y_e)EQA+eE1hBsJZmQBzQgLutpxUd_zK2r?$ z%`_+t{QLUnxDxU*G$P`p3TGHJQqS7Nuq~4yS%ah5w&pbayaw;~`0_3T?@u$XfVTyE ze&+byE8CKb31TUU5(FR zLu8 at 9chsylU5Iyd8W=oqc?@VIi|b0VJsMGcyBDZF0i!@f@}!2khLt#CU40QrX#(s=I?4&F1A_lt>Af+%MQ^vGMnl2R7%@^eisLlKN}Ehd~-K&J+el zLdmy(VlSEW;u$>t16jJCU^Fp$pB}j;VWR|AvfNSxSBC~<= zWA-bs{Ba@;YjdA$KPsWU^F7*EuD8ITk;QeKM(QUPwZVd8D2lyA=v0oI0TmTW(K3rs zNBZUK at SI$NE at T}HB)$D8+pT_*2Ec$55*{d=W)$9<_O*pirwTu-He|$(rb+I4AKPL% z4#-C{&74l27V-J at T=le1=t*Yv&g(ChW84M`e{u>%TuCs+U%w at OioC#`XymYxg$8>W z%tw(;`p7`D(AVI)9BpDIE;KNh4NQ~ey#yv;G^`g!@f%Pjm8{U)fZtOCLGpYMI^2Wj za6*~*F#g*4OGPmNJ>uyFR78V=5$@2atv8#7mcPdz3Y#hOp0Dfz0hY#iBx?W4@#CG`E z*2p4nuj`N6x%yz)QWILqTVLOdp%>kxo zgJfxu+7AIoN_wk2e5=$Rmn|*DfCB-OaY92}+a_CLiF*mB4lBn=rjg44Es10VWRfhc zFtTwhOBiEm1*9dt1sET&m4|PV+BMlykEj+gYgG!o4=1Oap7;g9BOze4B6;sX8)f{) zP)2jwHQ0f#gG=zc9I<9G458n7NwLk$1I5+}3o$P0S5-hc}^}J zM%WivFDs5bPn3bw=n=x*)PB at dqPR~sr{VXn*tAE1T;>0cTn8){k?YYbldJq9a{V7u zsm$`frc(KTP9=j1b)$d^kDtDRiN%02&Xfa9WDP)5uRy4m&Hn>J1>7fDNgnjCWT_ul z5?F at FWFRt!$sZYrBORUH at i+@GEg-Ra$m?lYHrn07O2)vAlg%3GZgKCVxGAo$jlTsY zfnGaUiK19$6+oV>L|=IDvt5dNC(yyu3f^@qp79lnl%#CjRk#6Msx|xd1~sOKj+4zB zy(^77t&{!*=FMYd2VEnEOSnN497Q(JiKLwrP1;F|lg9qTP^=EOWyBZ29r|)&_?_+` z!~)Zm&1RoF<}>*Q$)*y>yD{iNZ=BUrBX$5FM=(v>4>obaroFr$>2?{D7!6 at G{m=sU zVT9OGeFzQlWWb6Hak9ckU^0KqwzMF4(YMtzEt{AF&z*?ZpG?}G&1u(i3*F8=KFUqe z2%}Xm30H2FXVIYGJb*bGVLo~ijo>Z8@>L}Y?|B>}J$()?z~e1PKq_A(wz(TiQahe@ z6p(udm3m at O63Ocji+5;;IY at BhP&_;;m+{4{2nW=K!}w?wX at ZC^8zAN%1(@R&jSOX| zcV<5`RPxNr4qnUJ at i3adf_m_53W7YtkMPBZ;T)QKUN#H53M4lGFwGkznL?SS`GdwS zvIpIse*|yxgEj%$;l8RJ;P#JOgp|wqj3~EzZ^}GpC05#U+qsu*y1rFCZ!V>i+IbO>6KQ3X^hiIp3`T zCKZ(8q928o72xMD(lCxK={poQJ-27v8K)YPVZ at xvtl{M!-Z_rvw6W9tY*==0E}lf4 zp+0RFfIwyPfAm27AY&UDs+Tg)coE=Of+bj`dv$D~FDyDs6 z!K`Krb~p{C#IG?%>{&W;*&vw}k5t%)_~k0gZf!c540A at xkvVyZYw(qO8=mrE0ja%P z8w+nEOY at qG(MiVxXyzc2(1h!f-PEtcYc~folt@{Q`k+ at xO)hNNvPEWnefhfrG^ZS# zAgQOVOTQtmO@|xv_4S<~_v<|^A)BPf5(C1mL7OkXHIYH57)b6`83lC%2p6Ac$C8b{ zNJes9O80p^oM at -%9N_nfPan^vQ}+KGMaz?RA>>e3%J!w{MDzI1F?HhLU at 4m<<1sOP z2BW3}d7Rc>=>?%SNmje;ONP*%ja8Gp>Lj@<_L$dRYr>6GdW=AQp+u*ypn#A%Owb0= zKEo2b!mhz|4Oax3N-}RQfuS=kleH)&QC+#hnxxKf$U6wh^8tG0k!hK7q-0QYpA72Q zBnQz4k-AB5%qd+9oR^C?4s~2s$T3cmLm8wKQk{K;?+-!;?Z-m_v5yK(v^rD_kDHYLU{Xc%^r{CvGHgD|Q%LO4GT7K8n~MRmLqU2;Ru1 z%LZ`B~OLeo+VBKv`!p1XT*fwpW9mVnd*@ij4 zo@{#0-X#+tK^{T(PviyM9|zp~{IRp<$dU=+o?g@(4LSjPh0Q9E+CNwDto}{fIND6`SV4Zh9}l$YL7|@escc$mce*$16y2NhjXvyO4$^Y%lz&SL;v!zYt>f$J&dYAIR|b{cno~Y z+)#$)graI@$yL8%<@^bDQdkLMz*- at sL!)c!UN|o_{5 at ptl6?lTo;hb+&jfu39U5C z1yvW9eIa>vue at 6F{6h at 8X#%H1ths^C>4Tb=fY#W6;W;qdGVi8_S>(*c(5}jeoVg?f zCgyo;yxY${00eFc4iwj!v6jV^krky-ig(0fs7p~Bps8I;_Ci&`@sj7G;DA7M>?k^t zpztC1k<=DFaciB~jPBvs at 6x{f!fp8DJ|1v)Np(n%L}q}U53sMKI<&R@%q+3Z^f9RR zPt_H!920tw_GmHa`rUvUu)!es8vuzeAY69n>guy^0k*cg&MvKr0rhU# zR4cno(9}}shWckvX3Dh#T!|qo`$L-`ag}vit<{BLm#K+9K%?^fddLH&EDcSzM{;k) zPwFAP+CP`TE1T=eZ9i;jckg!pLyB0}NS^(nQ)uH9NKwCTEUrkHcOI_U6FQTBz|$T~ zj~3~}o1+uV2{Sv3s~o_FUyq+{)*C8KKs;*2P}#Fh3?Cu>#VI8;3jo1;1X)~{sU&Qa z3Znz;na$$!IV2nxxLoq^FJ#XG7g#%X;~Q4?{CbJSWse3BatR%uC?}L?X0_x#iq5TF ziq5 at NU|ZWi at qDy&2(%TdnF|~wd3LQ#*BkXsmR+8YmK>%g0gM4`t3eD)Bawp$0O_HO zLhN@@4PU^GUuJBX3?8(jsCMLQemp4!FrHL9_car6IJU=b$cM_Ji2QSNd=^?Nt714T zDgmb1AeHBA at Im}ymP7U=f^LxcCO0=Gy#f$Y->MEO^;Y# zxeO65CV}T{=$F_qC3ev4H<=MNFuAkixIuyTbao$l)4wm$gMWPhzX&Mw{vse)js1?9 zKu>&A;O9tH?1ZGLxIs1ciA8ZYD2&drk;FgkU~Td0eu4nvxh<}N)1r at fNi)HTu2bn+K-XL7I*6`U(N&=9$v9p=qw5g5E~I+D zMb}5^`WRgo({%}5gLGX+*X4A5imof at y0QoU&(SqZ*XQY4OV?F&eUYvMk5Ic3)GoR% zpp=<(Rp>gNt|RF>gsu*{n(6u_mHH=L_tLeE!=dY&bbXDk-=S-muFL4UkgoU9H9*&i zbj_n{(HD3fL)RPWnoZYqx}N(dUjIec97@?h_bceSlCD*B{SjSX?2*2hu9NBdDyJjW zxSX!f!F9`)MB4a4Xx_)X`~sqqaVtHNT9`M8F@`(I_HI1~?+N0yBF(Vm(vuHEHd zZ!-S*#Xs$YWG|Rmo%_J at 3ib)WfQvZ5+AL))e)Zs;{#d+EXdHh?g9l5nUu9+G>eWi5 zALs$QUvCY4iAH&PZ9fGUKDC588pWYr0W-mWfAwixr at 1r_^GEIii|8%~l=H&xUibsI zsug}T_&W}NU7@{+HGndnfg(2cgFh$%7hVKz_Tq&K!LNpw<9O)`?KobQ=@Q~IK%!l~ z{b2Qi-z+}&Q`~xv9q~X%EG_trj+iN!vC5hbh}W8+0Ua at OP^@H-04ljMLQ1?NW({WX zBrBy at u{&aMTj(x+V?hVPny%1G>XPHwThJ{byPq{ue?T2n0rt=-OswSplKA!LuN>&F zA_NHXG~Es$bCig5Fo4~}-rO%K0u4Ao at C6q^f7rf9k~nSrxgTf z1Ms97Sk}Je#%@%xn*eo=ZEs9l{c63PhpEB{N(|RvU-3$ohd--z^$RXD9v|iyL#|+j zku;O%m|;AYbmx$aq%l0l?Z)GXRE8WQr9aQmk3Whv6M$f;R(%b<6i?Q*|7{jR{ghbD zQP~;O^^o~gqY`U%#OK`wd{EOG%$v>+5tCgD!T+Lx znFgtoDi|_{DEj at KY#4B&ChTs-U)*Q zKfwb(evBu#`a9$POCS=sw#XD~P3x2CYHWfZ;Z3n(iOzUw6qt5BuEd6axA&f)!7-G5H_rdwODpenu1pcL6wN>}OEmXyB z88-F73rgL)MNfUcd(HbF`Yr8B=O;aePwenDif4x+PTPsmSBnzqj~#6sZ`TdKNy?^3 zS-X<9l+Q~WHVl|EBd(-FEw zTQ@%`yt)NJvw)&V6Q&75)e4s)kSg`nd=|`<)N|$)o8jtuc9XPf6n^|TFJJdZ?>9+m z9mb4JE3c!YZ*Ya%23!lKb%X`_ka%9=YCo&Og*W(4TxV6(gLW9%cJC^;qBkbqV}B(l z*IRY|){srzW=`~hTX(1re~;f3tes9T*TRz at I6q%c+zY<=Im>CI8(w)AX!I=Pv4#f2)f5`f zn$&~lpuHN^N7WP1Wucoq=a&uF&VyuZ7H+^UgM2}ox?N9Xc~>>L%pH5L*E>J9oF`KI zBl9qWIcV%QnJl7xkje$H!5Fw>I{yf13-gPE_jbjz`I&Wi?kIlQ(z6DQ zzs9A%!I_rl|4T4FmPT*)YCB)y%YBy9SMiqM7ohOy at 9FTeC9#qN1Rx#%CGb;9x8a$x z8a{avqB;!&n4U&aokY7x=H{A>gO at gI%XviGvwNlbjtm5Mc<^j z|3Q;&Td~$btGPwCoS+_#|| z;?Nd-)MipDw$iz)8e7d9yBI04fl5-%kw^KlP*89TFBl@(vRL~eo~%-X6?u6=IekAO zfS&}|Tq#FJO7x)U^=?gxS|tOO9sobx%`y2C9sZoZOZ!E*NB1nI?imT)u8o4K;y390 z&_(_^@;nqx^eOW0vAP}&0`2_w1YtG*$o51!H;*SbeV2A9UVQGY at c||@^-tsocahwxYSy7);Y-D9f^Wh5)ab zPcj9&zteV;}w)_)cAjC+D$$2H3y+vGcY- zw6OAHoKX2}Xz3%L&7Q)n$BM-F0y%bxzNaA#-v-Dn=dkZe!M+%|A5Y at -jkVwoOs(qs z&|y{;%YbedjsJBf4aES~t1nV&40u^wYCm62(E5`EWWpaO3rcSN3W0H;1-uZ+yM z!e1u*r7My7z at YPU;4hmFC5_A<5T68a5M^vyt`g;kei0id+sRQr4%K(=y}ot$iq`1$xo}Bo zq at +(Giyqe+kK^XL7KAe4x-irS at lQOKJpCPq*8<%sQw3u93G~OJv;gu&dapZ&8L#G= zXoAiaki~T~T$AA%a49mTOu~dBeDP$GJ&tgC>#veHiatsjcm?NWD?yYb1Bny8->b4C{PT^OWQquJmcbV|%r_*Kzmh z(kQv5LmD9z?8Cqzz<_&HI|tib{(2bj*Kc2HP=FaU4GxXF2QB`|yC`{SfJG%}FTD|w zH+J{^)u`{ryoKhBWfGDB6m4xNTX%K%epww0L)iq?-uj}&RKw0k#oiXQnBGTSP?T9$ zpy%tL9X6b&28NXQIKTZcWYLPtaQy85I?5u3IMtcxm)W240e&oCAD=Tm##EqsS#Whm zBl<^u5e;qo1CLdmjv`V)4w|Ljz%1Vfxr5*0SgT2oyoj;k1gi)nyqe at VjKR$+jp-B> zTQyFp2mM^g=X5C!{&q3pd4At$yJHk1JSvsLhjFZ zhjSagE!3o&2$UVm#{nn at U&7~xRcYL|2a`D=ZATP5X9Hb<`4K2es9COpniW=a$bTR3hs;jT!=sDF_)Hw%fPB{(liE8cL7(4-kXiV!}$kuX8`@^#+@@^$Zp^7Xqq%hzXJC|}R%EMLF&0{Qx|&hqudX!$zz$GStvXcFa? z#N~N--$C)2`a+iADd=D7@`2G8tp1yl@!AkStoRPPluAR;+qkpE5|s`}GB1yzTif7i zCcO73xH`)5nvx%1>1`JDM$y$M*)scjf6nad;oMcQszUTPuChh>%Kqqu7MI`SLYqC| zf`#TWv?gf5&#=^@D*IHNK>l9 zJ!4ynyxJZ_NzS4R9dLS-&qV*M#C(5la=w3BD)W|8EvmW6Bt1;PXkH zTy&XylDj~$R8}kricy)Cj!tDR+SW at SM%t?E_{DAA`=Qa+hNv>(b(Aje)s5Sl;ac5P z7~{)2Q2 at peCyqCn;_8EwoB3o}8m~S0XJYl07VYSM#`O1l1vN;uclY5j`49=*`U%Rk zk+|GqwLhQ0rVB=zLCF^2Tl9_18n zn^CA}F(MyEX`=R$*yBnJWQN2+i%_Ae5c$^C#C3;*8Q_3?fI_YYT|E1<$5pxN|3sxt z2nge5wh5W~IIq^*TY{Ew6K$m^Q7OoAH2CC_NDvMA)`I z at Noy~k%VRUg|ISK6Rk!BI!w%A5oh!#Qsr%u?!bw;4Oh$2&}uOWJ+2mU94Q!IjVt1+ zv#>}!B(OmhaAlVkL>VhvE-#$L$NHd!&88uMP>M*)HJwDeBrEMjcs&uX8w`J2jS{2; z5=*i^|J-Eq+O^k at hx~4Jdmn*!5$q!3P{s+Z^uH)9TYwh_`O2R#-l3>?+A_7q_4pLu zhH|?PQ81_13)WgeU6yPSWIbj%kY)L1?MaGq!va1%N36u5jOIG)_fx&Mh3nato{bGz0S(tv9qykqv68eJytGtjk2GtmdaB_zqlQZe)He>0vZH8EiCc>!QZfqx9-BnpgEyKHez59j8~W18@(C@(D9n ziYg=Svb1i7lf{mQZP at 8*;v0s6U at ZSdW7$y4S zEWDwoBU4MKB^Td;!|7bx&BEkAjweocaUozikN*QQqsdo(q`CO1C_ES66-CX(iSS$~ zk7t at OeimhXJe{!PA#EFbrSPEG+Ja<@_7|2WkdS79)vP_u5 at v=Ie3+oVX}yOATLnS$ZP&ZD$U^-nmRujDl#-;?%lTng5M z+Tw?Lm_qSd#@L&Sm at r)}iZM^~Pq-!@!?-|k>p}c_WlzOpjpEg?L;!(`a;<}^5NTIE zND}rB3U9KCnm(p2FbJs)w75!^r#*kGA zL%O!7@{5e}$q1>u-GQKr@{eY!h{dHr5NQGV-)HlAz at t1$Phs$e_Ef#usDA6i5%8cM zTq96Prcnul@$jl1D*50VR*BTPk{nh^PNzzq>Zy`dMkUvDu0&v!2%RdK(NiVY8I>G= z$f(4Fl_)b=CA4yZlZF9F=&6R2W8etQl)BzblG4BnOfec!Xp|N-;Zk!O?El~ZcX{tT zUn49y#R80nyUZcz7Ey-@%QShvIn8LxSdY@=Rt^U2B_$CQ)e>m6N=DZXU2c>~?_Lcm`cS`d%cj_2)!x<2n>C`);Ir z{o^*y*J7uq-kk3T_LR)|V%gUrobT_r at zXw)7VzqHyW6$jdmXO`j*O$OokhLn)&bn( zu~xurM{bP1Y$Um#LBu-8goxOgcp}ebLH?jaOG5WYa3p6O<+J7{7FF=_>cqJ9Z;J&& zBHil=%2N%@H=4&;7#!>_x46gGaK6cQJUq;z^;375Dc=lCcyA$Vp!Zl{G<=}ClDQ2_ z06VDDdhuC8GPe<}>!8+Tqt at 9CnO&+pZR?@RBkV(+X#|!nq)(2(b~OJs#(~?=-hqBg z25=jHh6j`rjXE3Hf6kb4)pm2$F-uy5nj6o#8v;k!$mVmtW at IbT_kcTXKj+(JqI3%k zH2xiz=lYZ at t)a+k0J3@$P;0xH7Z1f93V$xxu)9DwmtGG~fv3rbYECjGZCCR|+a8PJ)reRhZ8J-FW$&fyT+mL~8C98*^su8zw1j{v~C at oLP8A1w6{8^2+ z?u$}cs#cCHt&DM}Rk~eOMONPWg|ahn*2Ja(8v2 at C1!uarjfe0WuutG9 at eG2Eja*GT zj+`s-uXbv;|5GixUgW~3KMgaP)?W+l_OBRL8oUYGtvY89H>ytUw+#&%msZ{lO)qV{ zo3}OuP=!*PIRV=a{Fd51cR#mrD=qh@*|6Wn`S!7=7|wT%nU*%^J7}!&yYbI8Y))MJ zxl%WIxDkdhSO>scNh=$fI5a%0QfFC%{UAd;@7hyTDz^?>UrhJ7h6hvhw^;}b0nOFj z=XIU56FsmCR-=_tVa8Dp-ov8niPWqYsE8!;z~2-?HoSz{4v1CE8sg-9+fb`QiDCJb zy>+Hkk9nM^$2+Mo2H#?FJ9lf>qaUaMfS1t}+`{%1w_!mWjt1;4ZsSdDv=b7;JE5 at 4 zP6(KL*a@@14iB03iM!nw3 at s-p17@ zA1~y5pPNEc_LebIMfhhr?UBupTdM{hL9>rX0JCmS1^SkIx~dyU5{N{IVUWNGh9UWx zt;+rklF?8lt-7;;$f8@?ba&d0z>v_6%sAR*H-=`=0W%ozcHjgA9>5=C$PS&08nT_} z<79d=X5HIvrpVWDWBEhga$Xi_RgBoHHkiaxVmm83kGk7YTmv62ZR~ z7K#1xN72@@79GHPln={@@;>G9=V3fJijNo&{Q1c|S&Z?nebNBlbwKJZDjy^15riY} zVv%geel5n4~h6-gNIAt!3^669{cn9 zK>*sV9OGTUmF>mr>&nDz3eH;GuM=t%|J+f1zdnL zM|2(Hd{3fy-MR}9cyORl(4akY6y4}m5;IUK#nzjUcNgTEM93}OYxDxa1xSEIA;&Yy zX*x3jD7QLS&nrE;4vw3ri;3bIZ(5mL-b+;a at cPa&v#9sN$s zrp+mx0-B3s1asDf|_rdGI%18V-N&<;FNggt+qbmu7 zmy9*==(9*AeiVmeab<0{W04DEaUB#bx6)YDg!&F|<<`(kpgmOK&r~4|?x)*(tne$- zg%#4fXgwNv$H9F)@QR5IV+<|?d(er4H7mF{Dyc6f>Xvcjw|K|3uo1V_O$G!O3*2+AbSsnzm!{P`ib2X^ia_T0wXvp-}M9MdyUlw zM^&+FxYxm~iu9WDek}GNWb_ze4^Yx1G#ex^m|djd%d>* z+Mcv72VcgR>qU&Yp4&<7w at _5(XR>g`--Nhpre`ZC#59hK%?=8_D=U@?5d2SxRUG`=I3r_dY*F3(8P<}np~;1r1vNX=TpgpNu!B4z0#&o zk=mY%^kGGwp(2@da9WvU?Td=6_L-Iyjr^qjYdO-zDNLV(7}T_YOlvpgaA6?;9if z15`)2{75K#Qj`lclXl0Ba3;uOd{3wE3gy$Z2|K#f(>*M;J1+vuYda%#5PlXMU3Gp0 zb!MVg9M$iO(Cn?!6&%`I2w&b8(R~(~$nB8wiT03D21y((%oav&TJ)^jE=Q?nxc6*xM_~EjJOUx3NpoBr2=Uhf(WS31 at 9e%AMC;JZ*Eg|d5<4{`e`EdyZOGX( zo-z6f#qAl7v3|VquMR%PIOEY! zA1#qS-gxom*Z->KyY}&LWA}~NSR;daXvFr5`uNyWQGHxm8tS7h(#P8_-uxeC{F>&w z_VG+Z_l*>@MsAqV{g%MbzieM_ellub%06RXV)@9vEW9`nZ%_Y~Ky>MA?;e_Qux6%C z?|wiXzi2++dm?H+{~(9v(-E1^^7 at N5zcc^WG~cz4BYJ2gku|cohei^AQ6CTdE~=03 zJre3;Vx*6Msk>zp2%xs^5ZOb^Z6`iuLjZ;a~eH^oL at Z|&6AecLYzMBiTvM3=ta+e0%0 zSTnCr?Y@}-zqqgcqWgMwz0ubJo%;Hpnu`K4;@1MvrLSvyXeO0yl#j&jH%jU++NWuc zN9|K?eQ2MiM)qk(^+lVX_^X=Vl~GyJib$DzqOwN*YCWn9b?tX)4-Fe6Se?)_36{~A z>2YRuZrtrU?6u41 at 9^5meX&v%0>#j`Rt{@N&!E`bRc+*BWKb77 at Cbb0R$X*kU(o}6 zF~1rtJeD0E1TxQFzko)@s!0?GhpPFJrtle9(y*4m?d714(lmCr<_+2cC9Y6$a} zMAnhKez3Gs;AVUwSkDNqvnvA>_Ws|3>q}__I#o;+(!LDC$8Cx4hu6^nR++n>4nTSX zLR!1%YFqWPhkPkAeKW(q;@q%nMeG8}{h8rgvJFN0UjdM$r`YJd0d?Z8)!I{$jn%ty znJ5WM)!e93Sh5|_b*yBGdns`}lC at roygjUW$1lGP)-LPMztF&RCsp9<%>5NRVPPPEkV_1mk&1lf8j#x z+_V%FvDJDZZ6{8wtE%V$r~6^*rusjisT1{j=m#fXj`q0F>d);k%dXE?Bu at 1& zfC=`$8OjAkIk~MJbNv|DLrRxyX`yNmEj5KLJ&(ecT9?(jtE(LTIAgZk_ZQ`D161~$y zdX&#iU?t|6nGo=3NC;TjbCKSx$Q4io2NxdkN&_(kg)D)wIRNbSrsiCvkiIm|HYc^O3lDv%$J%35- at C2J0GTgdiiWnV!) zse7zVVn(%CS|e2jJo(IG80OOg1=Q#Fg^EG?R z1m@~65;GI_-uoIFDZ at 5e{2Xqhy?W9dcqpmC?kk&taCidFdY)iB?@8_ zk8393Z_6wuZO8<}frH@?;#gFESRmO}i%C!V at mVt()JX#cHEFOFmrR46)btEXv;jc- zy7;Dmw%()ob9z$Ev*^xo*H&aP10A=TOrhtdTksj^iWQ at yJ4tS>6cYPdu-+O6VBzH_ zqI(p{j#z;TKrI7cUjgQiL)orH-ybR&=sXrA#)O at IrFP@M9_7T30e}_w1e-*$?=K>A zLTR_)H)zYo{hDp4bG8+;q)ekM*&g at __UUdw_a23&a~)BlOa8Xd85Xj&IHsyNRHNP&dF1bDM#E&E6uNV3C!;%Ir|krF=lpM zR&ReCU+BJQgba^>4omkE0!!HbGC;5~%S5LG-C&_s_-6KTGk#p2#V#XI{OnN(JphrQ z;X9lNKaz4|DxA5?<24s%&5H3_g8#*Y1%kq98CguNc^LlsV{{-V6J}t&gV+an&BWKZ zEOh#P+H3c?Gzl6y&8+I#Z+f^v1CU at T%tp?$G#dlqN4pwNS~V$~C5^$PfsnKby%)u@ zfjK;jISjg at -u}qLY&>`%{2f~5EWG93s}-SI67KHDo-(6%+yxOEmz;==%dTCt*aG*F zEeBq>sx!@j1*Bnv(X1w!12gE;E+Xd9Pe*kiJA6NrswHJ&#~W}^F3n-5$fR2K+iYdO zqm1`4)$I49_t`H7O~T*1XssozM?V-Jjl+Sp&st*XVsD!L-b2t!1-KCHzKMi at xa?@8 z6KFuaqWs%Tro~zI>r-{zn=UybDj8OZ79i_nFrW7wSpWLWbw(~q>M^=E8_M( zE90|DT98D1x{~>ajrQ4ZxI||Tyrw*9Hf;*Ev||{wbeB+IZy$y&jopSn*1D2RY)OjC zI0^?Y#+(RF-^v;llA}{I}G?3H0-0&wCM;xYR&1)fXz$3hRx$v^1L_uQq49k%UJ7+Q(?qwO5;c zoTXjVYo+1k9x7#bl3*k zo$x0(NNJHjpdm4N9q3B}5_f60;5Jd}gZ2vSk4I&<_M$RB%2Lp5x5s#r19yPbu!f252izTzpYWz%1PtH9fN>|`R+rs at Xz#et@= zo2e)D!)k%WaF9+CIb}lq_e@^VNMGN;E=kV5)G)IX`t#!3pbi!z>r6nw$aQKB=n at r zjpTnT9u}-a6)f7j^_cbb4KP{*LZcPGkwyzgX8r~A8Jr<*!01~2b!2jYnDw>mXo^Qa zj5A)-g%(i~k{~_s9OjAEX-L)9hRjI2vENN6``v^ifK~aBp`JDy>wsY$gih)gxkDCr z0&3>W1|+&KID&<2`?3xPbV1iV3!qU)M|a^S(j#9Cq{=E+X7# z+7}6ic?W5qMD?OC9oftufR@=)u3#I>g-A)exu;yUkV~7rA8okZ{;{W5qkE#gy4#<< z;7*GPe)8 at _)R54p1?U2?K1|T$kbM+}@^ojWb3Vq at B~(Ch(X~fPHQduJsiRiCy?J$& zCGZI?^n at pkOm^+hZ{zgs)yz{&*1=nJf3 z=uAl%2Tw~IC-~WnEOuv&T?#4ErApF+ at T*iWt(;(OFun$RDM|Ao6>~k0xtxl9GyLMP z53FY zB((2TnCGwl?kr|R<&DL>?y|y(s4a+3=@-_^s>F~E-PM_3)R`2nGmbJ-r4HjUohHaI zDbgm#;|72?T9+e3Z?yg{r#I%ot6Vg~nV>Ez|1ri;&xh8PdS1OXTU6qmno!fjY8?PH zgJ{)@Cys_S^&wLrt0x<{YLYSM-Fq~#4-O^+>7VI2Te8YyCZut`)9^aJrl at z$_&Vafo*Xb?jfYt-& z8ET%{+2N5vb1rix8(xmm0a?yOC1UxUS*dX=Uww?4^UrgobIcSTRlV9Ge``%U?oCqa z(G)65pWb!Eo58DPsN at ab0#)Z?jBocgp(3nn2ga01iA_TDf>U|QQ~%sP$7%{*0%^_t z!)Y5Jjn^AgB at M3)>Uq8TY{0GT;Hz3=c%=%eb6XoAIof`NS1R3UJDvyNtkqR579PW- z*6`NGdn?hp!>#%pBVGWa&f_fX-sYuhX;Taty;Q>)w3<(=v{t)a)$3#O)Y+ESpw(^N zC%4+UQkV!+>4`|ccT@$2S@*Mkk5rY5bUT(;eE)2~&N}dE6Fj+H`_ at Tl1QC3I;FgbB zUDdyOOt)lk$YtwFa3;mw~Az`rR+Z$k=%wD*=7P6|<(GGaTIEcgq<7d4BJ zno-dN#XmPu8{P{IZ=ww&NiARd_ZeN!Vq!^>Q=Y`7wyHlvC9bh^p-FGNYwV)i&}k$p zb!Vjdnu#LAQ@{Q5)_f&$7)7{wp-5HJO>NE>VC`o^v3&1P(f54A2V+ilsw|1Os z2e)A;S{=C>xQ$6 at H@9P5CcLc80LVf4x_Ex z6bJ5o=?tx`?tu*Tt#MR+P`v1 zxb#O#i_^YB+^dgO1G zwtJL5Vo7Vxt-8LpkM_JR;+KDiP_g$4o*avNTn+2L;orv-MX1c?`2Fnh=rf=?>IhIh<{x=AXB$RwDrgYy zZF~|BzqB3jRD2Wg*Ve{|=0gdwq^daMD|4Pw{d^P>PNurGPAJ~(YVxM?YB}Oz_}m>L z_TGZkLG3{S4x}C`4C8e;V6eini&bbRk&F1 at tykT&=cR_cWVb&TkiC6g0lIgq70GW| zLX-#mf@=S)A#P><5aHg+;{WT=(HFmJzYDULvOroM&Rr?0f-Trfuf}*e?yP}DXY?IV znNYC9KPxdWZAh8hKR;eLJ4P- at HL7XWSJ at d@QRySW!C>_w;V`+DAffxO)V zT>fdv09tGp&>R5P$x}Lk6^=X5U3>ulEZfqi32>xmRJ#3f-MLsTdk_Bd zZS5ELmmiUde{JqjCY}b6Gnsg-V!v%RV92mAJW~FZp34VMMwK7hL;1UUF8 at Y!`A=tc zD&LJA`5dOoeu%055 at oCo6M^EoJ1PlNw%bHG4;j1p$vby3cG}TAmXoO+x81 z-gWgt4_jkU6CcZ0Y7{}V2YvXMlZYaMLj+gN%9skWw at A!a+$We8#9po729v2PqYiUA zH#DcJ-3%SW-}al??+N4Ai|HOUVeKpw?2F2Nx0>T{#Y$;lwomSEHqQ-N2; z!NJ<(sEU7 at 6#~wm9P!PVV+3U(ygfj;%oE`awBjFhUCq5Tn4)!D7OCg;a6O92Z>5^j z=STW-;Ib|-R7aIvJ}c6>Uj{?li4Y7AN7XYbTu(F%UHnGl9zGX7k?<~nuCp&(ZqJ>d z6A8^uqfey2J;7qcY*G;S;Iiq0!d9gpvnDY|#5ZJ(-B$;$siBxUH2H zcr>_Ol|>`mX_b04J`IMa3RCIVX7(BbKWUXgW_0AA)xRPpZ%j2T(u#$^?i)--VhBm9 z_QQ~DAn1FW5I?)E)uqjVlN$&*i>lZaF;j(M)a*ypeD)ga0L0CqnpKa*)=lVjn3i9gJCU3v3G#>-eMUg*uHSPq!$GNM!_ZLn${AKh<-W?7<^gnQTN#Io=$Rwv6 zut@{uK!Vf<(3)h$Fv~U@#{a#9{@NV)x3A5R8DAKGT2SW=5tP73W)c`NSMS=bo6s`w zsGzP*4)`Cx`1Bisntk(33u?!d+lG~)5u70ZVD|nbsA>u>PZar- z+p;LsoFE^^FWp73?s^AQY$s{@Dj^&ew~$g!DWZ+MT}R-claptMndFCdZS&8+G{#@p?g-Y;!9++4TazV>KcNAa8~A`+z!buGb7*WUII;v3f)Q#>|$icj#YPG#L~40PY!mCQm>QW~i>rxK};I48VSYD5Ig)~DMyR=uH!rO)yoW=I8w?Q<= zwA!?o70PrzS!f~DhCTVLuFE41Vw?*3e1~^Ly}j-(CN|ZRPOdZ? zioLT48pEn5(nQ25N0k;=jW+>r`0N4f)5|K*g~((fWy)w#$14!$@Z)dk+Ze|_xh}P}&O_^>p(BVi#heHq at Ci1Rb zk`0KnL4*&3{Rklj;|U`M?SvBjljGg~#g3rWf4f6a*Chg)BPJ5?Ti_TDP0A08fV(Zl zm>TG&{L`*IyGFsghGqA|$fm5B0kdE|!IRBRzUn at aC@KwnX0mi`<~*}>HMgZNw}m&m z_N^KSTl=~czTC=NKj9r_OwG6Ma_w9BJqG#A9O&JPZgKOipXH~0;(Z?muH;AT8$t@` z{zsdXEdQ7w#q+K<@1XZt-`;0^d!O~~ed^oo at q&6wqNo;~uu-SD_hJyqEk<&z+JfVD z0vAWoITjGZ18WC1@#mXx129)05p}JFL_-RpJ at EZgO!0XnoDuGsc(<>lSFR*_69CR*irZ0kkb#6VC#(1ya2W3F5q=i3M~ zuoaakwb#<C6pV{2?G3dw+gDFV4VqHapkb(` z;yOTIO0Las-*!7}yIhCg{x5on_uK!05C6t1Kj3h`>*&zsbN00Zf%f6vb5BcL%=>-9 zYj;=y(_)t3*DPzvIb3#Y2SB!R_rM{O%6#S=PdL+8s8~~?BN|ydNGRA_?i+|_G3J_? z54q~`dl2Xed%ed39Wd$MzJijl&BOX>*W#Z=OWu^f(O0XPb>cuetf at 4)MfY9-Bd}1w z%%4f<%w7BJ8C};lpGHE67&Uta4C{|P>Lzz$VbNPqnCBrGQR!Ng2ld~IZiuu~@VDOn z+qDb<()t)#qu9qo0<1gLJ{BJ?pq)xa($pPBD(fNC!S1x2R2Zb-iqeYY(T z6eX1s8l_9+ER(mdHvAb}R0`Ihy at f`$ijv$phdC-oJKg^&Sg96xI+Ff5J`p!ZpumN5_BVpu7v1(n*P#1!Wrw!717q|xNy9{VIYrK<#$#Ml z)$RbuJ+6JQqwC1;RtQl0b#(t+>(@)Eo{qGFAtG(wyFBMwHlvZ0M%(19FG;pJoPK^reOSloW9G8iK#oCF-DtGq>s z#AZ#H14E+lfQc8(!w0~`x8g$yI*|6;C*oAIsT2J6Yk7Jb$=+&a&|40B%btOy;;Gcz zGY~J~8vG-)9F|QJ*8K2lqFkrZZW}^J%cb;132ZFa zvhs0SGFb$Wvg`odw3k2)BZW{6|2>B_P>D3Cp(5er-?yPJ1_~RwQ*-?;yq*HHSV;1S z9*j1pFVW(}&8Sm3ZMQRuzil`X#osQ}YEdcd`k&ECVKXiOkAJYBFwz>@Vh}W at 88GiU zABO7bQK7@|4fZwHf!Kg0tsZ5%K-nfRpTUU=f_bHt>uz^Pd`AG;%e)&Dk^eH~C%|1T zsAPk#a+!XN5~D3|?BQx|{}HIV#;Uj6Z0J5EAYM$)#OfT?h;)u zcCqU-ycH{Ujq&mxHP_4+1F1fatX2i}am4X%b*iov{iz2irU4Xnk8Z?$7W`+%iNNbb zZ8($p@(Iq;6W$?$+>*n|Z<;W`r9Ou9q3`h at A6qex*&R4>y(j0Zp z#Ng#}yT!W#awM*}KgXv_y&%ig-n$II2uKfl#IMmld!+~X-Z-r5Sc>yq0>cHBaK7H? zeNtWEH0!m17hnI>Ovvh)2Ev?N>5V$=#vTQo3of)#iAZX-iI?>N$mQs5Sk2AB at lEll z3F9$xTm|zJh+a<^`+bO%f at JJoC}Tpm8Q*FTD@{d(PwUR_GfMavZ?ts|`4?-`CSPV^ z3eQY04X~-}B5 zn}L%G;N&Z99`#RUv;fA=hwK^6Kn&gzl~?;Sa8sRK-7?=z_Cx3(zQ0pc@=aRH%O+NW zuRyI5R~?k(@;cB2Nv=!ISNezwJZ(=Es*c$`>at`3Aq;^QG{8*N)HY<`Q?7%Ae2nN; zX!s{CCOPB at -qr4fshu`g-m8nQ-BLfL{v=mrw$^)lW2&}i17 at GKNOT>9Z+qcetaUGa zTco{%-~21)3jU=~MQ!kAWIg^!1$wM+-9_rVi at wP;bpEAt;lBX?XTtwQp>P}No&Egg z%$n0FN?r?-3MAYRmNXrsly{wYD2qyKKI-cohozv6j>l;(LkWvV{Reu&&dc}@b4sI@ zNrnbix<`HOES(X+Ndbk-`7nx%==z at X{lSb*t=c%>6NEQ%y|dk!1!nJbnCs;S%+S`q zai+%&MZK5poxK{vme2-$ik4$-QlG_c|CR9n9t-}liLRd|E37sc&VY*v at 3gm4nJQhj z41HNK64)IPYCgP~3Cp%p2a(ZJ4rtqr#8*vB>l*g!fxL`n?fY}6Kg^Z>mom at Beo<_1 zj0gU~ZdPUoeM8M#j1Nm0xc72w+ptx?8Jp~b99CwA)JH67BUtSD%Fn?VK~1^-J~IO% zU!86SL_~$O=`Z$x1X2#-kwX?ry407^W+Iv5Y3~%Vi`agon#xz$2&z5W?~8C})f&Tk zY)B6^*L;FIsFnpaVBy=40sai|yil?omq*kBVse+%&PyoKLQ7~zMtBLKv<@(vr{EmQ zcF*+21>*r^gYrp4AE>CzSI7kDPB-(!hCA;L#7%e?0f)!n|Ysb0;abx7g63R>U;by&k9t z+Y~|Bho2W|OV;3ZzfDl*m`Um>LP;BZaci#(?qT#w58wv$I2VaffJC#XPwWyf%ALU4 zn&h{=r6sIEx>N at qnXICr|5Sq?T2mf>0j+3!pBBMS))X6tZe=fme*^o~t9gvng?FV5 zMF)e!@=$SBM4P!##z&*`^Ky%wE5)cD%9Q at Ry5wQhqcF2>r$Yx}!`;8vYzm2Tk=<11 zJVJUEY#yflgSwj=`npwzKZ`GOpzukMPnf+w0O4DHqlFZyF#}&gT;7$tQA!K*^Hi1p z at nQ>+p?@hR2QyP_3`XTqeD^C_D;VfH}9e z*QbZKKqYNZINV!-HAzJ=ZLC&_0!R$REfiGa83c_wgaFP=MzdR8Y({fSAHoE*l!q(j z>1nk&mn*%2JzDPIO4I1DO>*yH)JM at Sw)}BZ_z(vxnkOyDG-8W0U7YW?Sd?z6JnD#! zU5IDno#QCnNI*;qvx?KWMJliqS8Q_vv zKMoVfvBhgmF0PdM8Sk*KpGuZ1L|fG|l(y#i9=6WZeR#~misT88)wzeHo3uZkCk!B2 zFhI!XKxhKjsn at _SY#ca-OPe|0izcQIJe8ucY at m_G85^~hFcwZl6u!Dlf<=zkh~)bW znh)b0?NkeEYa8D1{1&HZw4lskwl~_F4D5jfA-lykGuXU#IQD`7Al~)Vrpo8->$YRC z_0oF)z`$)3ST|6hUl^ApOj84U^pg^hTkWgTkgL6d5m}=037S=LT7GhPct>i&R}ucB z>(voZmI65eSWp9nNj9P-Vqx+^=OtTJAYAp}R{Tuzzf%Jkr(%4M(^By}jK2#HmJu+? z2gc(@IwuW8GjGP3&s+(F?Ugj>tv?VO=27aDgIY@)8^9rGuBXg$D1uG9TO+%h5y<3e zH8SPa=KsikCt}1W0O}1HCG%+Jm+Nr*Q^P+s0SpYiD^Sy6 at Mw||1Ar)ih~b_`Iqp_Y z!8E`auDn8X9t(-yJeS?w+5UMi%?3tw)gG{#LdJT9T01}_qZdI_BJq7}@D5x`oFHu` z+(3+XYfT}J?HO8VC}_ap859|wYrWy&IdUS*@%?EC>NVH0#jWi=kLUNXh^1g05<{gY z0AHy|GqX_pVz-w0EGnJ9B3fYOF`Y!7%iHZw*aRsU_K5(c$`_{?VUpFy5i0G|ADAlr zPtbl?8jHSt-M-PsGf{TGkrqAcgPJfMCRux#3MEa#374zmc@#C{$E%<@ZGnUUr;Hen zMjI%)O%v(K;kS>VCz**1;>RQGvLQ0)NT)YLWUy%>y%{2d*ojn($qd%Q3+u`nKs&e+ z_G)7Rcx^}!Mo|6>cHu`69Xp0xH=^(~%A$~X7JbCi3(TfnaBS%#lm%qB3r~K0>iVnL zAI?HKD)Q5iwwAuh-;Y!h?t*l=RhJUE1r*A1f0pk(tzqgiqSCV0g8S9mF(j(xdN_8O(Z;={7U0tB0WirA1GAc)mG= zUeM}dTLa>S!~H at yN6JtVW?);&K0WCc%DWR%FU at GuFf4+ebTg*O(;T|r8jR77t*1-2 zy?WA-dFC!s3`55DAQO&ZgAP?l)KaRWL}Da2qBAXgIZ6iAB5FoScCC0lF-HP>Th89* zvbVe0+YFoh&o1E9!)^r)-WUfSVxVG-8r$)Rbi97t7!rcp|xxGxy`%ay$g7%o5}s=Z(= z;@cLfk37+YT-{!6pcbCi+mqQ*_3%2zv`6$F!aATz!pk?X1?)tjBc~@lKM$u{L5 at y2 zl+mOoZJNhug-sE$D(#DTY=4y80>8#w{cbz#!9$nQ*|!Me2-B3`GY`%8vap>NT at q-? zFay1p`-a!ewMxQ(8;o@`bRJr!NkduW_z&8!l0oyr>xO)7z~Wg$u9YJ;Q(eM77PJE6 z2}fd%sO;0$KLo^|dWV at WIgh(+RTA?Atdt>o;oh at 76hPx^OFU>@%mG1gxhVS}d2qH)3q>vvHw_#{Nw5;5IE7{Mk&1ITs!x^Qu)n*9t z8h|B8N5WiBdIEAX=O-Z at I6+Cs%SFSe$FLH4#5jb)a8e4OT$LNShblsuP&C-V!QIw_>>*OolqL)GJIktDXKHXxNwQKJ6-&z|DHVb+2gmMz~} zIYV*RIka^>W&eCTjlzrdC=yIerD4-P1H=@}+xj!cMMz4!*=*20(scrE^Q(n|qk8ybOD+`0V|=W?F`7O> zgiL{_pj0IOwUTf>mRx_95yXiC`WQj;bB5_6*G}E*o+)-a&>WtE>WmY3$EKVjMYw~~ zSP{dG)}u6M7Yu=`7QNG17t0e?XG>X&v#wq(WsrXir61(>!b-4zh$na2A))HL_3Y6I ztI(-8LR!i*m<{p-KfB;Q`7lsZkR7<8*+NzvU at E!Nfx2s%ChyNGZzk897#`!Vag0`G z&XESGLT}Bz4S0z}tr49s_+#icf}q1&8?Po@#-Z<s{o6##NZF2AHqj!~kcJkntx--Ih&!)n08|Eq*vDy0&w^!^kJN zS~wqaii_P at i!6eYT{;el(_JXIVCI}~L_Y*+UP(~S^2&D6)rJ<3ZNY`uExpo{b*1-= zUKt*Z=VRG9sI)*E-eJrY!S!2p3V7R~ZK+~h84d>qYgBq+wr`D~#2)`}#c-D7&pv+x zY8JF{rLQxY!qFShhV(OO8kCSGYj<9TWUJbBnA?zxhe1{!&NrThezLGHKLES3u7f!iQiAfHXS-Qs6#}L*Sp#A^P(nYZjv;IN$viw)oI9^ZRrSqsCiN z?6S7)8Y3^rSClnAuPl=}G7E at mX$J?Y-ZhaAGv{V?}7RpcGen1cuUe zc&+8^Q8m|sk;gC!fv2D{GCCetB`5zGQrWTxsQ=Gl3=Zd05d|0QgmGv9vY^3%0U`rC zfJ9M(SqbY#BM+Jzx)&gNnmi_8r##A69_5tVP`X9pW#e=JwaHVUxn0M-F-kCSiuUnt zBIUHvF(l>9sPwpwNnbN{KP1Z{HMqm^xb&o4sEclGYNaiP3k!JWN=sPf?=n+ZU75S=2HEXOu?X%8(&cKl5zaxku-H%?36i~D?(iOKqJgU__` zuwE%17t|Ci33H&-2F_q$FG#u`b2W+nIi`Sqp3br=?!815>MkyA^8PHORSElB1ihhK zUwZbNucIT1PNzho`J1HcBL~!DRdhxJj<*(1h{=|&hrcFiOz3=q20q1mrt3PLPjC!$ zJ(_~o8b{Mt7sBvM&!#y01!vQ1|D>}iQ2GCOHYMZP)a70jW>Gl~OO{tY7hSvISo+iM z&d1WS at Ue8_12~p23X4a%EZ_Al=Q|KNmUd}1F$_)=Nr^D$zJJl#bd2-iy|+7aiCIv_ z9sxQ%Pig15r|JdQ*iYciTPUC-iCWQh1`nk(!8v%S;Gs08)1hRug at yqt4;@OI-w7Q` zpMM-R7PT-Ic_z&FACLbUq~r=Qz at 6Y9dmGAhTxYmaKW&{8QkExc^c+Z((zV!1+D+1Z z+Dp5-oIAzr-05`vnCEI|=MFnfTIkNg-g*r-P%G7W{3D_2bMWdN$Z~wja(rjxcolNM zh%{V-=gkl3cJm2A>4WR9gHPKII~95KiGs49?!9(tr$3 at KIS39VzPQM4%4TW=eC7f> z;OA!vLR6VREirEc)cgR}oYo;!>DIGfvb$bx!v>s`toxzFBQ&sQfq6S)(*FAZOgeOE zu_tTU855l{XB>FO)Uz|jeFno^(??if1^@1J%5d_Nv~?5O#)MCrJFO<_Wl?Yifbz|l zFeriLbimww#+2_L6I=+5a;0?Z;%WzU{iQm^0tk46ucJG3jiKudbiGH at Ez|<%n~SVt z!CsHw*#N7x!2$KcFc(6T?kt#f&R1@%(BFjA`~`F{^G~{8Z9yQH;nyivJhZkWA+64| zXhjUScD}k at hWC0ENNr;vUoq_y!8+Sn=q?*2=+)2 at hV;gWg!H_9;5^gj?1-SYz1sTw z*)YdpgUjIsU{z`Y&$lzgxQL|${?cyH<0Pj^K;-1ehq=GnU1rv-I}973u6&U{S(~;M zjft3!lt*dg%T1zQ$zy=FDqp44i;OmoBl_x7)>qrs2o;fi+rMBL?}+mMq9;8v#f)p8 zc{g;WTmuvuH|0=B&ZXFgjzi=2%wgPFS_4dkDh at IKa!hSg1SH9n!A)Fns?oD$9Nk zHhnoZ{qp4Krf0CGd2UJ at s$f at ky_blB05xBFhJjgq5ex#mtG at pAaNn;%xfww5)mVZ8 zNSeU}#ft_MjYy~|rvZwedDqY0kNyV~7mj<#(Q`&KIVL)eO4me?08%-K3vA~H;n4^I zGdm2-<9X4*Ob7#Wh6mLAezX!$4dakQE}Lt*`ujv<+p~v-zoE6X#4X-bo+#**z9#98 z*J8Y<#fp%>&WJBiIE3?+20Q^h)*ZsxCNX2bIQ)R53CheCD0h>uS(;+F>db=YYmDd1 z(1j;^jP*5pw+gBosbcusL4VunZyWtRPk+zR-&XqDQbUoUq{QMZlN5)N4>*2Z)yq$w zzK~{^iNeWqM%4Iy+Q+{k3oq9fUbnWQF8aI_qM~bk_%GPT7ly88cVCNeEHQ at DOkC5m zotat79o}KMW_D^tw}lEGB(Ysc^}e3l61Uj3N6O%~R5iO3Q*3~!^_rZ_4Cy&;iFOU&7p#ta0H&TKi at +Fqdv?MQQ560)j+Z`&Bim4AXc_lo3Ri-PR>zg+42kWnaUKr zj})!{rkiA@%LVlEB(q7o88YJ;Sd-|wam9Us8|gwcxL8ykO3gSSrs-K at R?dcQB`VW? z_PD-Uek1GNiW>x1>+*QP)v_XnZ_cx&dapq>(B8-dwn)Q+18~AuL(kqei~e427>9go zJ+JT6YpJC%%l}cq?zl0Wr!qgC1z}qupm&ET7nHlY`a&QaG-tq>@|nEG zVfKy?3hK7K#6ef;fNd)lRQr8Mn5yx>-Nb24%W2p~L-Og%Eff_Ly6iesRAUTVn2-c4 zlw)8Yp`ae6U9xjK>XIJq$qq5)&Qxq@^zX4^1z6j0sNFMIUhgntPjB!x?{!_Bo}%pvgk*K)ui;KP zFIaVtI@${ji*ivrtVx?v7hJP-Bxd=tC42yI+T`je4cyzvaig{v{%m69yw}h)Ar6 at E zAd!0m at L2$Kqs2vvHU|?$|AKZ?us8V$g|C}{`g&#D##PQL_35t%$co275ZvY61>aYt-b<|4%GE$xpqkFUE?EmYB($6blij(Dl8Rogw43sj;Z-en$ z(WOYxzO|X8xpOAq62Y?mAu%v+muh+?js>v*{i}3cPBj_2s@<%KFuVjRz`4Se at T>rE zE~P;jy;-28DSrcS>Hz0agtOh$>`sO?It9Q@)+LOSatVTaRVQ!#5lD^^ zPfZA~S3~b2IdXuBNGB at a=Vdgbrb at ha_B>ntys|yeh}SrA2wfvUw<$x1@=o-j0L{sI z4yU5}r>8)lstjo%MJJPS>6<=Pv9$S07y`qc}&IUcoaj~l1hE7w+RgI?9R~@svtr`k>QiB5l z(axp*V1>}}hoO={s*c>t_gpEOMv&zhj>#SP={w}i=9N`96mM+-a z#T~w4tE_W79A;pvgm#=do^!Xkl^-!To4XUO=*qd)ptcOPi^3?ii^y7!vJn7+8RmPn z)?AI(uE3C{a(RciZD03UVJ+TS>}z at meqg*ujyIcJ_1+{s>47W?bnwOp%%Bt{3v!Fa zYcJlJ6LiQeRxcEAXcCDOPh#{HxkL9}s<}SEt&M6b+Dv%#XU5e9XNt-va27syPS=Zf znu&$kV+0at$&CaOP;3ol3lbgpTYPt7W^w2NV`idllnLti4E-n7g_YwwsqRO`^o@$= zyGUO2nn_;tCj57p)aRdqb1T2#lu+=Ke10;w;Wi7px%b#iCT=5=UFu|AZi(X_n?yRA z9Rs+>(7TnV;8pT1%*$;q?y)N<JR&I{em+?;)=A&+sdEp!yK$^tGgL8&O|dsmWEZ zHvjMHhh4OKZwyqu&Z5^cH-C`J4OBOC^ruuaUw at 5NfnjcIBXgX@E0u;brp})JJmw#T z0zm%SWJGGr;UD=Ms>Q!*{LP{|VGkUj6GUqp`)SvH^Df?jqH>?Lf|S%Qye8f9SC-{^ zEw!gCPyUtpRVA;B<9o_=Kjtc6a$Z0WvjH!71S`6cu7ngbtOUeWIq1-A0^*NM*tvo< z%=oT*Q{*CNx=Feefyvb3-lb+7LIHp#SX(hhF{h2*8WOqTNfh#Hc47G8UEQ8fhVnMu zb)h}8o^<#IvuP7yB)5831IZ_UM5*(kJRpl<-#T!su3-|nKjzSVnLnWz9vJfWxDKtz z%`02u5al?XugmQno9AB>4+)v at k`)Vo#$(D%Nb!h>D;4{#(S?`SC<)i)kOS2s=UtqS z6lHHUfyxBE-c?iN3vx=z zGI&Kh>9MOwq^z{d%G;IS(ajbm*&!QP0+ZSd%b9M- at 84TIGV zM|3a|O&7;tUZLKKdPcmy9k1nN-O6pa3Bz$DTz(_c=bJLjNc&r9l{0^*%z at tu;6m4= z=PL!7VK%Rek83sMbT*PZq~1DCP#?ot3#Q2H<4sbmpw56(X;KFE%L+`?+z=Jgviu8F zSGCPUB5ycqi2Z${gC!?8_ZS#<;>a#1z1;QI#fXZ zZTe}ivy?@cvWnP7-M%N;Vmh0fj5?Cu0^mxo7=cT at 0VBlxF5uDFtE$(Ft*Q$#O;5sXEQ zo at O#KAlTDMtjTS=D>)uGl@&wK(DrvQgCzyY`VVku7dTBcGIBv;D0)Ij7TP>186y?p z%6d4_C`x$rT4)K_+PD7+ZDx-0_GO>no~Y at _2_9X)yC?rXGMZVNm7JEE z(6fLq#`9u&j`C?@pyz$ew&np-*suU~?{L}<oK*&S8`n;=nJDCDo at d`&ww5kHoM{!#xF+kTDK2q9+jf*f1o|@|RWuV)HdF zT5B~0V?7G`&(c2V&|yw8*L$zR(nGQIKne{N&8>*mr>d}2^Q6pTiPx^YNMC;Ya?gF? zmHNQ7F=)dEgK|!KFQ at z(Uitq>dlUF5s^oEejtrSxbPxgoM56>jBN_}!k_noI9_fLJ zprE3HqCvzJ1)*DT1x)OTWYUg!;<4-Ms=Mp%cXvIPYgKYU63&Dm5J2Vd>Y)(=xH&}9 z|EhZ3Gm}94?EZg#B-8y~^*ig;tEyM8>J)l7EyO#Hiyvr!WE at vTxio^#Bp_9x9l=_yUppeA77Y^Jm;8-vbMJnA4rSx&?22pthx7 zJ!HL<_!eYU{Tv5%%>eGl)5HZHhvtBw%mvEb=EK$2gKlN*w;tZI9$x8%uI at lwDu9PV zs90&A&8=LHR*?a`YooODTmX$EmG<$>=tXJwa)GNTWdau%Mh{b^hn4o}T;N-JyHgsV zwBO4G(&(+23!v^Xj8WL|%A`-(0rK?4CIy~%`F5|iN-zISzY>O^<4ftvF=wQpL z-q{{Te=InfQ^IaKiySf}6(paNctx{qV>WaS)*83|SdvejY4dv8c(ryN#LVqfcN}QBd_v6HD(>viFM*N45vlG?Bcdl7^+IkRU>1!k1Us3v z6$ph8R;hJ(^BG5pTZ;z`NH2H_%;F7v`}nN5n`?zke>NYw`4sRNMfy~pPGK=mz>gC2 zu|9PfO}{ql&(;uffh8FKr*&h7Fn1ep86&eZbPGC3<}tA24&Jln zNf(qYWnj?CN*}D*wv&FfGBhq*Y0q2k20gti1*{L2z~=9-Lh&#qXz3wz&nGS zGLVjFtEGezPd2;o0UrU6Ce%8!!)U-L_bx0s`+&@wjm$F}$d`6vWQFCI^P$gYl6_Ny zw*4E_4={J#s3M3*rxk5_FaGm)Y-~}AYKl9>L8A#o;H+5OO3_7-_t17Qsb-0wHjwEJ zx5%d}gjn7MqQo;&cGKjbUp&|z27E`G5Dt%!H!X8IS2hX92q$wC4xD>YJYwKT zn6K82b}1EKvWUY6220fYK&nF`kPKbJ^F7#Mr{P{ZH%rPCvf3a&8Mb7!&GxICU|Y`6 zK4?ReT0e`~;>XmzT1y+ at t6LfXf8)A*kWDt6P_&R!nFr)Xl0EIq9~D(y077CTLPA0~ zi>tvdcp43&vdN)6_9tsa$k(VZv3yUHbQ#9pnQJ!T8TwqC-$vuWdw!PxLe1BQ(huxO z7+gai7-Kqx<)mZfKv35o($OqIh1})B>g8YJO zAvG4D?I#-X at N1puKjQ2a@<6XD)3OAD#D!jgWUty5UJ1YBL&>Xg!xlo4*ce_$Ij6$1 z_2CfSq>eD@$kK74JITAvwz#%t5Hleqlw5+}hXk<^0mAw0(+r7+zeA-_ at Hb1k6#kBs z`oiCAt}LCE;0|+UQQ=r>4&|{=%(-WvZ9+_fA#+o z-SkrJ(jFT-Zxys;hv7LbkHCf%okSP$7!zy(*+_js!F>0CSg-B{O5-?1=VA at ohqqa( z&?(U?c+9FF7dP`=P2OmV at UCw)M*In-cuoT at +-8M>IzPX9zWY0=V4ceRmJ`E)d> z*_Y`oaL6~b@#%O=Q at T#g%X&Pu%ve5BDiTPyj9;emx*c`82i%iUw8d^gGhvLG;dl9$3IKB6x zG~C5{p?1AqySkFjvnpdQMRdLA8$EBzW|w@~6f8PoohoIZ_~{w at +v^=RF7!02{fbYZ zed<*-6Piu>%|x}I);bPmViutC>Zyd&u4}HMan@*xuH}_ZyWCI9!|euS&0)N;5tXr- z`d~Z@>JLB;n8!gZo9Bc!JX#Xfv|}T&lzvB{;P23t6gd;5&5BLa-wz?}?6kutKe2IR z#|U_iGAn8iS!4S9^+ztLn1k5Ti2(<-Ki)!(-m1Nd7S!$dbP-g?4*0BFfK+4na~4xD zdOm at +CqdCFcZ;a**D8L7ZzrXT#VxH>PsszcQ*T>mq%_q)%tk|5tyREOYkMefH{99#nshX!<2}!OX{sv zO^GVHlGGhq+N*?g$5&PJ+qiQTgO+rJCU{ZHO6iW|< zdZ!Y+pl$iU<38WVt=_D?@)*WHRt_Ij!trI5oOdhiHP)Rayo<=QSlD)Mbt=UNu@LnxP$^Ax at Wka2&<(H&c+fEI{-1AVzPjW8seOwxfn( zY39;7_;(4f8u(k_^Xvs4VC$P*?Yfsn*qXGJj0aeqip+L{^aT&}5{L%y0O*lS8`wto z?e=uqZNOvCAI{>y4Z)2(-CtaJjv_2>v+jgliD|!vA*{9OpQHWiS4Eny;o8U^TetXG zJjJaIr>8PmrIHDFn&*1psl7H{Jt&kf&CK(vC$O`lVR+~9`E^`iJ7=@~oBR%ZG7P6= z>SK&LP8YIt-9zob#8T$O>>#~ zCr}MLCESFO+H&u=ab*v&Cp#CI(i at eV*r*vo`KOsEgW`)HrUe at djh>Ew3h_ at iUjZ!W zrzE}l@#bM+g(j$n%3(eFoo9G%^~KPLszqpC0 at Bc9<3qwfY(||Bnm4|YnpFXUaAE!_ zsR=5W3*Q$Y{TGCacd1$&&MAV*ipTDX`CGWMA;j(nSa at 8^R~AJ~HPh6>c1uhTqwgf; z%oWV$UpaH5RIZ%yNe?S${L-DunVYzPjHK(#T@MZ!`GqwVuKaKJC27l;e|fI-0)!ByecNxL44}#3r%*E zG)isSiuOMs`DT`1?*2ouoqr4 at zGa%$J%AmPlU|OqbYbS(QUO3LU4z z8vqsukn$W`%i%HnK2pz!pb0drVt--&Q8}d~cdE3kBzL^Dgs(Wx>kiO+A~0&#S8avtKB79IyL z{AaVVeas at r7|E4g?82Difau{tE+T6_^&lUbZ--3uWsXaD0oV~^M0%Pb87y5n^|*pLZs$tk(!nE zk at EHDmKdGO^NiC(tHcEf=)+oR&yq9MO*Br_OxeY&C-gq%bZBi>T{xurtXN2C2374m z`QH!Z_Exj<)9y%j%GzRasO at 2fL#r48$s)5WK;}+~Lkpk=t at j%9Sd&Kk|J=Bzz%C(= zK{B!cR{T7nyda1BocOhrZ`MO>hcrO9022bQ*k3k*PAIa0TAtbo;C z8~R^wf@&(JW#-WeMLOZwQx304F3K|Kz9VzZXR$TmBuKPcLA~~Js||sh+%7t`l4Z8L zfxR|13FT7ebPR3rOs0l|78;kKDOrXA05e&qMrF_yst`gdL7?X)E7B-H60n}ekl&y0I-iWdn>-zGbj>C#UZpAI1~?`AbdrA6p}Ti zYzZj at cNjSba%TeV-Q5d1AE2d_C8zUQD3^&`*?yWJF3?1D{-6NVZZrjsRE%tSve)^8 zsBXvoeYAGXKL5l(|<35S>zz;mT!vkuwGI}Y-n%|}2eT|ky&R!*zn z`JM}07>ASbHG0jYtG{JGIvI at v9(FV<(c`r6W0cb*L&F}zyS$z%F7QXExxthr;dzmf z%Y~jrjcV2R&hR)VtB`dkwkP-hWc4K6AMG@czCL6SdXlVFecIcqF1J%OeA zoCmO!@Q0|oWn+8!3^w)`SYvN|Xq6E?7C`&j!1I7mYy|M=N=4q^c>o8PXb;K)T;OjG z8XGAYND;I(H~f1hT?ys6;pZLZ3Ru^bFFXuPV6L7R%|d3S7bK!7kdeieZ2{7kb&}Rn z60lbB75l<#APIKd(SCL&*PuOrGJ?}@Q2_JNt3_w4UI_Ek1|sABxopWu3&pB;sopqs zMoWwF|i!A}46EBJ3q6qCAGzW_<)~#yvD8mt`;}F&*_4|2d92pQ0#Ky?h0X zg`7+^j4fGae?%UG;&pzVbanXC7UWk@`;QA!A7GN at JwTRc{}W5?WUmd{t?-(2fHrZM zho$J35gpq;eGL^LkA}gT=c$q1$RFhIlAMCtlKcD2X5453{act5Ofu_WCv;(&G+4$o zDW4J`JI0FvLjB4!q%*-|yc3tRW4uP@?6joYG2Z{6%X)s(f1%5=W%jJgno;}T>$1A& zul5%I at A|8)Sv}~ls{j7K>#r`mzbE~bU;WY-yzBfLte5t8(_pn0h2FvI*~sZp1RmI{ zmyj0g6l$>+pr3!V{PL>b`|1?!tYM%E%NzW78$8Z|-+DZ~Q#arSQby-EBnrl{(D_k-G8CWy0^#H{U3Tx zR_nqm`Y>Gom8zx8^akTM#i8gqLtg+%DtFQs`lh9mE(@ zktLxb3nV~%nhvu9v*w4L0oNd=Ps2Zj_$QmMXcZubX|teI(q?H)n{^r(>x-Zrr)S|P zRq~!nY0>yl+`FjGnr*4GU`yxoTcn*p;%6~+781=06y>p%g8GT6%bE?MetsiYHrP~V zF%O5P0?Slpv8Yi at nMFsptu|AcwbRCwSry%sS&Ms8W)U+}vOGqaRSP5U4>C$07GjiH zxuncmips1L;mf)xvxbl|>qb;&T>zyyM$1V)rPjf8S??F*$f=lmjhuj~;iF8Ib-3U` z>8pbI(!PQv((Z!k(oO=ms)kmeDhr*>;@~k=)-Djcvcn(K0%TqH1N~mWS2Xkan%tK! z$)Cyv6zWp`cxf45al(?mE=98iA^0vc2vdG}gbO^&o{FV=;O`UC9dv(LfIqNheamAc z3EYUBr?op{R8e(O3ZmfNS%_mB<*x{@t=Z!%zC@=zScQJkTBbMA^ite0=8{q?HKrtk z3;djHcA$d1A6FtrtD&S{>eH at 6 zEn3CtaITBVwd&UqO&ZYF0})MHCaTHiB8Ntd1u7!4bgxs_)V z)J|wO&tzm~KACi>o3f7M+r3ng9Y{b|ty&;6Kt$zhREjJ)M=25@?Gg~Pzgvp6<63qH zG9mS>E!vS8j1aBDb<8N^d6jCrZI-qPN+aUKv^YoFyDHU|M3rhwm{N^3k=^QbejRBd zwhzzm4!4<2Oh{rv6l#M0pE|wLDsfF>q|=^Qm74bBU6D at jP?4;9TDd?`7wy^&_L%-& zV`|rybm?hCyJohhdpqK-c3d4*?S0%9t6<~LEwoDy&!c1esMRcV|9N$6wWwn|9?`K0 zU3F~5v5?X|RQq{!Y^?V45AHQq{dY#ShF`bF4(@YzvcY|^o0`qA)NFrwC!%J9VZR^& zcRUHD$wTDKNP;OBGG`0rqa&)e$G;_2+kJm#s+QMHBNMJ*ff)5*NE26b$+ z&~_aNF8Azl2V1${lP>L-1ze!Fi=HC-wO?c|kjm1QaDf!kuK}^W7WPc^i&G}KNw06I z)>?T-0|=#gNJh%8jAtq}Bv;{!u at U(ikn&bE!z^;{0vdm}ADJ#W#b;EbLVg;(GL>43 z%~Yvnrz1ZL=^vX~H9mKc+*_#7p@`Z*<{3!I;42*YH7rUS at a2$EFjBt9n}0&Oldnk3 z-zrUoBr03T4 at Z=1+l7j-H$S|16trnK^k-8y<(eL&T*KA?>|@Q;5^u!`OT(s}SHspq zn+dk5Y(8n&8VsP&xehL{n#Kgm2ropTtpXSnB#nLetQwpZc^>W^5AYQSa6D;8Qw*4X zoK|BKEJ@<0f_;xp?u?4-fdgDwgOkY=a~a|cb6N;C z*iz61Zl at S9feMy2pDSx~nCiL3mU`|=%=^?lo#LIxsDejyGKV8DQHzj-z>g53G2=^wRwv=k*sgA9*ta_$eGni^^F7z|wEmO6|AaLJy`m$OI zf!~|PszycIEU7oIZt`YnsA;PqOcC(}#aec*V+6G58ZO9ZP z+t1asAwr=sqN!;M+oGDbtvEV(kmkl?t^8AL8CWVeeAYfoHT at lu(rqp&-Mmcc_L?n5 z>DFkHYW!%98HFmc_d!0sTdKFEKp%vbi>A!W%;|FR&(S(I2ehm at bYv7;WYPcSUq at Z!%rnY~I;SG7RxX z6{LncCG`ce1&z)QFD2a@>O|H;l2D!<{*8lSkwB7y$=SkU(c>@`xf~aePrbLbj=3@& zDWtiUQ*kXP!CFRMYVR*Bmd#wjj=G=PsP1QNj4IAjK25%r%)B1$u85mF?Y~vTO-GAH z=ScV|`Ox0U~+54NPQSaxRt9Y9{75yAh z&#~XNr1)cfUu!AeV27Me-A4HkyR1n$tjhxH^2CT*DtwD^PM0%(Z))8FtuYEWB&av? zpQFG8tY|H5^NZ}}_AFlpOKLW$-3T#6)AcOxIgV%=(Yi6 at N;h?FlBsKRqpr>AMax17 zH4yVM=US3k9*D#sVv``O-v?4Ks at iTeRc$S?BKBj)qkKj$_=-Nk4SJ;Aq_=BP6am&| zFggL7K-#w65x{z`>_60CLr%hKE(4MB5jmrx7l`}Pz;HUL+weZCx#o=5iPa|^qw*>7 zM0TcHTcTxMOu(=Q*hs9HjT}!x1#tyCP{GzNeoh44+$W>#fyiQ}l1%{HtsohX^8YG4L859v(e+#g{E?=*uKGBmx<<8%rc|YqO z(+kFQ4F^NN7zt4<2s3nvMqrOo9e$GbtE$7;yST+2&{+R^GzM%pP#AXI?r_-FIY>ye z%L#>nwaACbiJlI5NNeFNyEH%>vfezZM^D|U_^qc#x(LdN!)LsI>}ezaABjfVKzLG{ zbq9u{&~n!yPj(Pp6IOM&cyzoHO8dc%2G+ at 2iXJ*JeO#?D&}}O_ASL6y#osbx^T>tR zsNESEvy+{s=_)Q;EZ&D9?=RH0J&s;igSpx}k4MZY>y7YcoKnMckb7p84Lt$QgjzYJ zf;w?J>JR2lNLIeTSbV5;`Xp8O&c=Q2&vq+^?Q)j3=y7yzq4^`lqH%1jRrjj7tiAW5 zofY)-IVz!5$adSMBuIOjtVZ?TT0*pC4F+U%ptr+1{c@ z8!hvmFQ2Z6>OSdGcyMD3AYZE1G}tgoi__6B42&cNU`@qnLzbOy*Vu7uvj+n{I*vf) zS%&}}$~Q%Hp&5{q^J9+TRW-kQ1V$W4NTJsZ4fg|H#Vl)*uhJ$$^DoKOhQg0{NtgDU z$o}vHOt<+7x$8aSS5J!}*CE4h^Hp^MR{U`BL^ZhuSI3m1hm7fbg~a6+I$8 at GI}1xX z9T+yW6A%+vsJ6!U?9y|5tH8N4q?DW{bt{>UKK2rz+*WP;!|bN_NxB>4DuMDRs&Op< z9`7yzVGr;8oOm7YsiHCIbP&=jiC=Nu29SAo^utE@)MSo(sm4hA`Lr345WWKRgk=Gn z+A9>V;K`qCHt43`r+$eXv=`ah#l#YT82lMVA3 at +U#m+9JOsPl$B2vqKMo zX}e)>c&V0GmJXO=lRzjD2KYf3n#q*!<*+^Q%52EOX3o%kctv|?JROFPM!z>%H9qG? z5q*(7+h8~EQ(6&5cWI$l=`uGLc+5`HuYRHBL~a*BYV$0BTMaJ~ zP-+$Ub&ON06Ea7*OhKCYms zCpMzvP%ChT&-%r=G_w#`azFPBvZgd}UJNbvzO75Ch2`_`UQo&hXYCa6z%PWnKVcn_ z;*GRRsKMnKV${J_lBSppCM! z*9q}-?-onf|74_naFPh^DtiATpz+FI5aE+sXng>}Z^1k22Yl)=LdQlLUO?4f&L%8MMVD20VXik7B+5zU{duES#Q&?{|MFh=SlVIqwb>RnikHm5 zXl?=eTu^I;tV(D?GBkl)s!$)yaFZ_)jJ3Lqv<;^Sm#=lAYf!TU5m at _T;Dtrtm!3hh zZgtc86cW1Fu-=4G-TpygaMre9zr%0QEh}`9^M%#3OQC1Kw9U}d!qJMLOz38>HqZ7Ni>HOUscILn6X7fpglM|uQJ$7~f*>k#zru5@nCnK~M?fz5ZevXm> zQOK%gBU0N!6QAUiAkowM4aBqWj)?aIm>zr^a0&IKh+CIxkJC3PI*7Daahe z1+IczZT6$M952M>`1qsbdM+$Nde&LI?(q!mg~)38k{PR2KA2c7+&sI+_BHR6NSWyo zekJ0vTs`Dhk489`3m!E&m+*pE&gF{;=kiD5T;6H71LyLx#kriuP17G5`xYceIG4D# z7{+D&0^%xOT+kC&@zp(yad{YqXVVA7xWu(FzNL>>-RPs^wl7HUsi$d^BIRhasAR^( zjQ-GMVkWWbGJCAhB#Cjx;++ixjm~I$eVGxHy3|J>{s}Gp5rN(h<;_et` zE3w&1mI5BL*iG3czl@&I?mDNOoF=WY_y50={A%@jC%}e1FH-C|_HvY7FpunnE;jS% zWk)0rH{!6<%%hi&B6%3#Cj7$-ERSARMe!ZnC{4Vn-yW`C%Z3~PKx0++usG4CX*VaCdOkEu?w{f0kX-`&jq}FHw%zz at + z<1 at QAtc)$)17jxB1>)h_m-%hB=RXB>DNQ25FoUPM5NjaH2Fs>4 at XX@NS70J}i5i^bvcNhExiW z$E`mRA4a*fu(hs`D+`chSQriv)IohQBs=6sl^;5l?|xAl9NhXJce>KlauK zB3Lqjae8lV{SV2D;&PhwICxKn0ifQOxvBlYxvoZ?tJ4~6*x{@1!Wd>wQ|Pd<`0Zt7 zG^I7pC}@diELVo%52D|uRnWI2RKPwm?G2_nfbU#T`2~6rfGi>qw+S*T3gQNkKKc~^ zGK)asO_1JiuogI33*rGRHMSKtu1q`29B|C_s at nv$4t6>8I$45B>JMILUw?;J?d at Z? zZ?oGjxzUYxHbmtzV4CKjf2}zqY{45Z3_g->1}T|^DmZH|V_yEcuK(1p)xT+m{Z9uk2uX)R1wv7ZEZR2kNGdge}Cz*X4qDXaw?0^0Rk+4ylFl{E7?NK8s=F(|GA3= z8^u9#qd`}?0C1_kx~dG!WNT#6ZpmzME*zWx!}JB3%0oBeIE zE&>`Mi=2hT!ap$|^{bV1qSg(57G#Ad7_q*~y967}IZ&kT^r at Ptp7N{v{GP3_xoo?? zt5=H|5glrO)~oOe8~T8(kzAr at m(<`lO#z;+Vgy8#$QqQ z6#;`X0kLl!?!04vr7V6H#xW)*>W at 2Xoi?StQ_j|=&W>C`PttCj9d&cs&CBY_sf at j+ z;4Rytz9i741DD*oUq!_KRvq5e6bYVZ*50m2w(#7XwAyKPfIlC0*vE zSjF4u0e0jX8=5#ZJ~l;rw-~KxZnQ&x9=!+HxpZ<{>StjQMzG!kw?q~gD8XVU=WCA? zqYJ at Hxw6+uz9}X>3|fq7(~2p==&*Z`er*@j470qN^OTnj<<$xo8#Ho*$WL;*)|VA6 zkJl24(Su8do(JQbTN_VMBem1_#fTL-v1;1y^P=Gp6|P^dmv0IPGhDPcVAEH;hSy-DuRc_DxdzI!i at Ld1GcCGGT(DZ zNlJZ2kWZ%oUP`?k9+`)Oc&(@e0~m`cpGv0c4cdrxc>Xd0cA?u-)q3qDFa^O0ZrnF9 z3_EE(QJ>d3A^j=&9{iwfEnCV3_;Qq9I?QZe40`BcGEGO#i8(^E>H%tU`qazCieEdhu1KzicB___(? z4pdY*W3n5>4AiX!IlUh`<4_KzDwU}T6VjCj+_vb9$83B(#mxa$7`ElrN9{JP^eNiW z-#&_)u%<1fSD43+o$~EUbq|&`L6#1rej>rMK at 9CV$oAAa^o7& ziLRJL~42LUw?B8^2)=-KIs;&NFm<5N5?HI&<*U$b;}$%o at NOG4G*O>@Y14BaDfm z3)|6M*xyR1e?MqAN;|aQ(JSOma%(GD)<(+u8jI7u6}odtcnzNh()1FHm>K#o)*IqfU%dI@}-vQajSh{%yCZDGL1M zom-03ErMs~vMYSpRaL>J@sI*dtOv-Y`%CkIl2)q!Ml)wQ zxlX}fG)C7SE6oQsv(ic{#kBiM^Pi7NL&BloRGR-{Od8%S)ALL7LosP+@}gf>n!hq8 z4ZSSs7nJ6|fN6;=4G*-{7x9U_gz`pXklF>i5)KY5!ypYr_?u2T4erS=^05(XF*=o} zUQPfCbRjBfVsSQ at lD7q^ZAw1- at vxr)_&JZC9SjkwiLU~A1-d*0Xu~fQB0l9m at S`1i zf=KJ`tVZP%K_-;wU#x-C^uH z|K%ix<8QAsaa at c$ACmtNgXFykh_D=*bSpF|oQ+lEdi;1PJh<5X40C;HZ&KQOk+k!~ zwJM~A;m!G0RDO=*0)9N5R(^JJ0SrK)bT~}^z8z^?AekQea{(tk^x^`jC{Q{$(`ju7 z at DWN!oRpw+BynX9JkWmq3AS(1!8e at -54n9JbT{u+L}dAD=>D59HrfR%(O)_9wnM-h z?X)DHT5G4HVVLw2KO#x9Y?Ze_=7W%#_c#n1P{h>8@~jp;^$WEwuZvs=<^b^wnezu} z{oMhCyc2qN8 at xd-SBA#nV(?Kn7A6+ElCfqe!RItv<*DbC%Nek=H+-=jkM1I(zMx3;vODPd5c2i at +Una0k≪WCfkf>PKx* z!VY$^QwhgO4=UjV>3SvHOX8FcyL2a^54nATxxX38(MCVcLSRuxN-1N9mh?Cg(`>A0 z0YHvH$iyh5bQeN>w}hYuA=E^GNKID*USm+J zYcY1T*6<=K<-V0&uKBt1?v z`Al*!I2~DsSrlhxMosh_t4sJiSlg(|T9DJK?o^J#u#nOeA5h0h4<**abMyeHzJea& zq$1^LFX>9&xX6*)Eedf2qf49N|h at AD!e{28~@UpbQ`^-<2m zNy&III~NbN7wDt>>gRMjEl9xv{*2Ey0GIm;>T0A-bx-48jFyX6d*Ktz%u`dI{{(ii zo#c1e75oJEGTijU;w=<$?&-G}n$){(Mm1_j)Rb8Or0*hsQW*3Cnup}~mgfy)1MW1Q zgK~+wFpO%NO{A)K&nE7lNyqI|nN^V6IPHRCsP&z?6;} z*iz2JUu26UfS}lgsKK0_<)f;J9l-`a=lCMpiYSNOijTBPi)Gg;ovO%X-jt-&H1~HHZ z0MUIE-&vxM+3$)WgP{HBkS~E^2wu6vW}|aJ5T=a1P+33it6MCCM6C%PRonTcB&G)~ z?0TD(DTiIPZ$>P*m^-Y$Q*b3O>_Tb_h>EcOm=mp>Ry<74_NsNT0!Q%b9x=3(RDv0} zgtcd1#3TPh(5wfIG`;~z>~Fa;BfJNhp$)Stk}`^lk6BSLwJqgL z(+p4LKR(uJh@~5G0Af$$DU6Drbp8I~dQEnlE+x9tL*WMC;?2 at ug3^Jv_+wd<{Q4!+ z&^PzkhpX&1)?~lhfWw1Rrj2=y8F)Mj^Iq%4Nh$MHms%QBhTS$l(CN z*p&^1I5rnLc9ev(MNfNqk!|UAeHGz+S{32E`KuhuHPU{w9fzbDwM+V-u>+9fOCk=> zNNd}USbhL+=w$Gu6}I#>AQRY2b1BMbma-&0P9CNfW{gFZwv;yZ68z~s_EP+bA8RXo z%`W%S=AQ=2(^WP>U$_*#@PQpRo0%1r+j5M&vA6BF+hmuvVFpgmkP&!yI^+sB5yvKS zLUV~HV{t->$0p?f(YU$)m&S|5#~I at R*m>pC)+KvsA!-HH z-MHL413ko|I$VHcs?IGI*NRRUBAfg+)Kr7DLM0cU0{m5mef$yG9&3k ziyuhg1OV2)KS>|vObaX&MG1o0z6ViH1AaR at pX1PQ>;oL zJ~({JMt9DSIDdU${(dZ6eJM;KOq8nWdAxy(683}&XL-D6)N!kGFlUE$_<5S#zTE*Z z-fy5)8Vof1AB82I8DwymApa3z5^5(HHXXhB=d|KcUEmvN1s>eFN<0ZNg#kWE>04>r z{8n=Nf(4n_Jl^O<6Oyx8M=+zR#4|%`#U@`D*dh;sHQiebjklNNUW)8evz~;rQPzs6 z*s?RM_c1nO{k>}AXP^gkXmZ(RSw}RHCYQC!?t%~&G#Ue=CVU5}1gIXH2~MWs*cF#g$;<@EUOnh{BU+rO9kjUw zcI;tGU`4 at g^vBWshL7>Wu= zq)1-u2~#7N6hEV|e<&lavqIU6o|B7aVDvLlR62}BH;bWuCq>WBg(CXj{_v>?na}ly z;##8Rl8u5{>H~PdN*xW3UHm>Y7^b{Z2o8Awo+-3c3@>WwJbO4dCs;GEW$Q at 4#7J8PIcmxVNWrik!j53d$M}q4Th`M#!j~8p zv7yfTo>(#nrzS6jGNmC z%*rs*#%)G|qw$_&5|7m5DN-<^&Q%%}Edsxz0)V5K2U`y_z3a6ZZyRislgR%GNohY} zXos|s)Y4jgk!J_qBj3iA`H6B5iS&RADrk&QS(q}h;dC`ND4>7RZ}bE8uN6{&YYn1d{QG<&95A;7a?L~GY&2Th=~t_Luq@?tzQXAP z`cv-k8P!0 at uJkFIT|TO3c1usjbg7q53ESmwv1+HcJh2ElWQ?ayMI{O4LLY+<6;9D# zMZuKE*5H9v_+e8K+5P-I3!1T|wJKg3Twxzq(JvvtTE0y*s-U{t#kMLm){wt{&i8Md zo&GDG80wcWr}T)y%_;r4om;#W_?L-lzXZ`!EpPCxH#+IR<$hn1RCpc?&jZY74xW?PV_cwBR#B^Ke%wuO zrHs9AC$07&`ri;aPD&3WOL38yH{>WJfYAD8J{dvW1|ao+W0Z6v1_t-yGWz^UMgm#< z?`yPw;=8Brv2;i&Daacub1Y7ob~umr$X=-J)*De}9ujixF at fM>-0Pf|{~=E_KchrM z0UZ8%W6vVc$!ifyV1X%@u#Fvi6t8c^pIS_C);escw{GdQL}O^4)&(tZ;w|_5k9K4>c4Rno#8eku=|I|hSqK$TS6W~o+mz+QwgjJ z>%wK4M=)s;-rw!k3fcAhaajTcx6Q%Y&TpfT2fCH_h$Z at C5rY_*MX{n*zy^8^!^)R);9Z5`M1 z=Y8RG{kJ$aqt0|0n>jc(BcCua-yh0!;Bn)X6)~8?+*^O25sz9x8Ba_-tQj(t9~g{JJ=bvpEmA&99Cd zhNp%r`_5srts|K|3A)99iZ*{_nvE(7yu+p4LrTFt at a|VN?dF)bc5OU<0}My0i1L4n zmb1h>Duxe5Jdk=CqeXjkF0hOqzTpBAJ)GeJ57EPEE^wa%=MPF$Ys&3T5CM0LMYeS5 zDYc01c`Y!~uHIm?VR2&|bctz!i(7G}0}Ymi%mtoWj32rD>f9Nbk4cv!`?ENApp?O_ zzS+)uMNg9*B1(5Wf&Hn>_gC&BWE+e4ik&i zjj$sfOk#E8g<|+fy}cg*7othjS_8)^v=X)76dE1PNQ6+Ky$BisOfK_->}H=Y?dkJp zyL at hb%CAKO2`b<&vj7Y*oChS-7y3u14V??jwDINlJjs{e4gcOmtrTDW2mD!{M?;Zg z4aF5S6#ZZ*pi}^G?wR8a2E5oqHYnd&gVN*+y^QtpYdcLnQ|lMNQioo#k*V*Kl-Qsh zro>gTi957yUmz2_G8>r$&sNFXqSy`j21v=pl+rMks7*aWKq86qRVCVZ_CCdW&p8q) zL>o at e7#cET#I7ED>C6xcGJ;N at HNT{mKM^v zlIx!9P=b7oHKbHziCf0lZNU$dSsFG6cS9Dd4E1t at _jSfb3pT@IFA}>ce(5Z2>b-Q{ zO-f8p%Ba_X;p(rJpdEUd>;FJVklot0BGL$|rBq?mUm%OxvKp9DJptppmUPS4+GfR; zz5CVJvL~~$7no)9aWQA`8 at hb=Mwjmfup>ak{;jJ-8FtfxE2097OoFWG0>0)ph2w$$IAkxrH zz^$bVYTBWHz$7Ap%Q1 at 7eg0rkssL=9pq>ie>IRNP2t8s5p1ty9f5>(6D%5RmUvDGD z0qklc==zS4_SRYq5F;gf)!jmHxl*FfxyjQYpHwy*yjqo2#b<5eJypvRg^*|$f<+7TUV>U5 z^um{WxWEj&NbA|l1*W3QA%Uu=Y{>DSfAtl*`?tZCu>3A`BQ)-iudPi~+8qo1 zlS2L*QhlE7i?4#2;Y3f>VkhxThg!6+-?h;l>CjRbe%Rgv-@%yG#c$gNOD|PB_I0PF z0Eri1IV*Lk1XO9q_7^SitKL-FjG?(g%s79rhB;l~0vLu-z12o`dPt(xBDYs<0GYu^ z>$`?*YC&G-JuO_|5-Rgn3?h0Yagj$YBg%-53%qn72f*bs(e5o} zCrUt4H{-O!0Ql8PC@=zIq!s-OQL`S9KThy$mE+YjVRRk_&kQw}-vi${y0J77BYEl!N$vZ#Cm+-Hq8?rofyZ)jqWJsW0DOsX~whXUlqve;QEieoku z2Xv*VxQf(%+KFwQhM>-jGg}Rlg+~k{kb!2+UiAs=*4{YcFb(}GHd!zNaWG9dCF)*Y z-A)m3w7VcnT?QG4aw`3vL!8iV&CLic=Rl{SU&6jN>%y;Li2Q6tT=fYCctVr8(|9Da zL$kvdz*k|c*>|)Z73iS~^e}XPhPA!SJl8&D0lJUf ziJZd}pSq6+7Vo`1P#p7 at D5$@W_z#~VSZs{xdyzO8HDLM&C7tF7m6VLoJ3wi|vR=V_`Bd^7oL-?bMzIBW=q^$XH44;Mm5$00qC!NL%tTHa4Z| zFBS#gAp}!ChBv{pg9}{7 at Q@1(p@#;p3~jGed9LTQ9FGxh)dg{FGnc@;O)pYw2RAXi z2AWGa;@oSb9r}ol0R`lPks9%z5lYV$*P1x{Bp}4%JAlq+MlkzYi_j!Spg5v854{;7 zx!EEz)aV~GLUJG9$4D-8Fj)wWK$5EisX9ZDDs2uM5w{zPoRwPY7DR7qHoNb)gY>f| z6~2OvQ<`5bnkA?}#sHUL_|y;aDlwxZmjfkP+}vp?9|ZOO1yC3CQ+DIPz?Rgn>o@^r z(mI!t-7%Rf-Rh~8GGU6a2|zTW6hXUk89Q!<7VPz-IO&~bHkHSQY%{60>qDY)o-^#E z^61`93PxDu#zpW!11$oOzyNVnK%CJ1sj-Wo>l&C9Sp$WQ!uV=*9bm*mS^&{Rh<^EM?3Gt_!h(E=;Qwwt80`f_S7g(51OLYZbVrQKr zw7YJP<(2YQ#_~!Zhlp4DV!Ubm%Xm at 7XZ3V0z^z$0j$88^!PF*^k;e}%o8{{w#Jl-* zqfo09y03)Rv>fml>JA at dd6&~?h3E8bvzdQIv}`dp z|F33#Ry2P~Y<>{(DRnwRU3pIV51QYPB%oR6VCIjH z<}ZlN4}Z<_g=qegF8w$2y^;JCY$J+-{MiJ#F$z-N4MZ_PCPYD=>jpB*1QDYkuXY0& z`!yTO6>kwb`ZIm!4A&sDl!?(&-s at IM+gA)^QWWHaZXjQnApR)G+HN2pnjl3{kjic# z&zc}NMM3Jjfjne_jERCYb^{SjklZLpb2pG-CP-csr(d#C3ZkX7cPr&J6J%@@#Afdb@|X#7eH6sq4P>ebazhj(wHrvb2~rpZN$&=d zVuJ8dkc at 61M-MQNaZ!*F-9YM0kl|5~>~0|Mnjj;hAi3Q at N)MQ$OB5NC at PmuYA>IUV z+TCU;7e`AGsgzBTQalIPo!o4Goio*DBbX`OU|w4phCSqJSFwi$+A#L8M7xk4R3t`PDtkt%qs6gjiiy)s zd%Q}{I*+kuBpuoz_KcK4`+_|q3DD}*Q}&FD+T;~fT)o=6>=~D-_9}bE^{73= zo^j!6CF~hjm?p937SbEDXIwMd4EBtRLz}{$aTRC+dq#BEa at jNDwRR&cCGfWA|I-V$^BZGSF)i% z=;@jQk9-Q_H&hhb`Er}jsO0mjRC!E zr0^_d^>%B7y75n4jC at fAe^LyJ^#IYBcgKbDfV?}>F_kX?BwRvjo~s9xmPi7==H!WYQYVi#s+5c*q|+)g{pKEmeDEXb}b!R zr`HA3^X|Toc}Pc~+X)EElokckxi!nLH>p8yQl at +Xk`7b%AK!z70=VG_N5-$?m}tiM zw(WcHis-UbGcPrgm(3k6>ozu+}?Ypfw#m~~x*$2=5;6L$8e{eN at 5d7x|d#u at Q zwoiTNT+`eCM|@<$Rt!x|2ZU=bCxr8EWuz2RcCeHjmNEiTHnNmUSPDpZDeGAZ$5L`3 zyVIlZ at QcYe=n3d zZ_bZ^;7%wooZyTicxdupwfwsoa-%B>q7&g4jm_8>Trdog?rr6kS>@BolK8%!cA3 at w~L5LQ_2N8(EU6E~lkOc;kMxC{%XGHS{ zTKPA}5ZtI%=R#T+>+pY3%jma;G z=HFuF-xiZUE1Eym%D+7(zp#mDO$OosxpqeSSIj?T at Pr6pe% zm&r_CpT at 14ZW_i?B-o9j6p5(N)VfY9SDR3W6zR_yM3Mg4g(5{;kzwb5eUwF_i zCrt|Zzjylp!SuvsuFx_=cZOuUr)_zar>2`_EB8{3Wib$A6xMbti=@i{nm_rfA5A8xm459}i*?q+zGhBI^PX_O>i zq)yHhLZTZTA!dZ8BpGQcxe=1ap&mU0A&>7x%tA>B#;@qpPSZe at EPUW=`jRKZ{Pk#e zV5Iq&uOig<)j^G&m)UL1tKFeys`F1q+D&f)di)I!OG0T|AfFEv+UIx at B~EbSrC0~A zv?ne+e!7O;wXNvmSE~SD^x>g#Z{iAfEq0Yu at 6!`Q<2Jyvv!uF%`+N&uk?M7BzA at zA z+!$z*ck}Gpa!ykP;%NcDG_K&z<-M-Fw_xDnIHOt*tJSghyTsCC?4pQEeK=x@@fM}* z(>^8L+g4F+*YKu;x)NotwtZ&LF at D0}CbeE|DLvw9F^tk`2Mxox-=l&WaU%F8vgV=j zcI2wrsd#7_jK?P*6V6;AhFqJ5*==(?+0sQu4Mqe|&Ll2uQRu)tF1ThkS}v?Xj#?$r zuu5~#ooYO0rZ%Gg>-FrInSvmxcg1*KG5s;#dRt5<|2(ftC)Jaz8>NR0Cw>mN4;xjG zI>@aLCmLz;@667`k-;WS=l#GQdRn9_J!d4qydvBA2D(NMW0v-(+X1#&sx~jFM%(?% zIz%WIMo=u>i0zB`>rN$qXfe$`@z6PQlQAwbH at naFJU7i<=jP9^qg!XsCOI|uK8`5k zW&T4;E at p!Iegv)F#FbG55E5@<%57^_w+?P9J>sBp?NshfP%a2Se}hsABc*Kr5KEEM zO4)qE2nXN9$qeH?qE?zwhx}yT`_te-^7 at NcOk?ecmT>w(ELOhUOk{}R2)>Dkp-sFE zil=Ynd{(f24a1Z7?D7b8w-`!!U?^hOKxvRsjW!_4&xl?1c4j at nieX=@vq9^IR^d_X z{{ObmcfN*=;{qR%(P2!hcYi?r_HyfKj1yQDd8DL}lDYMon>9e6ZT5Yd`MI|E)<~BM ziMH#**=O?x+15^&$KZ>w&KrXn$+K{-JSP74vpN44N=bv>7g~<7t%x4 zLL!`uLC0ASo`a6h-w;8^8!-af%IQ6!W9$$Pc$Fw-$|Wlz$fz&x(!=2UL^@OQXh!71 z&=k9Vxv~LYY_eC`fP-Q~A1*Q9+{(Tg9y=;0&(KcL*P<;n7_k^|z9E^unyu0Lm^B*l zvlP)GRb#-3Ccw5o{fwro?N08c>fqE1Y5t6~D_;RzADIHSi$JQyTPS_IMqET7W!7p`{blkbzT at t>xq+{UX4`EyQu1lLv+(KQ7v zb~aLR(W-O1_bXLxz^Z!o2UUc&bw@!w)A+H-LcdCrTGlEjmrf$aAp8vpFE*=_5|wNT$S99Jhb3!olEsM(^*zTxmK5qJ3ooy<|*R_$l> zsP#mujVpVJDoOe4Kor|+))!)N8(Rs17M@$eRanBE_=G;W^eLo=0aj!*vLaV&@7#=2 z$*hpse8N0J>5JR(zDCN+=J*Z7hU$Im##29yw78d%`^f+Xh}y&)uAA0hZC|4a_TbIp z(0Way=wajo0J6qvXEA05Izt~Drbo2&;MUX|Y2U13cNQ at O3kc=r{9#`)^%E?&>_ at 2| zw`P3CoS+xJ8J{^PxGWBy9cTeea{k(WZuGI at waHieL$1qltP5?-9ggiL8lP*~QgJzM;PsA_4fIw`XV$VB0K+ at ctek#?3{6oik^O^h$}QYQ9XZSaQp zURuHZ7O^-)iU*8#GRLw3Bb;A`Zcn%qa^>P2p|=&540TQbJ>;;u5r z0d#y5ybxrJ87O1SKpA5O${3sVOH3JqFyI_P0|ZJ3pI;;I*DvC^)%AP?@Nm2cfV+-> zXdz$hGpf85b}z!=446X3h!0I6!>3m1;aEMabypb`Fg%8oIErqVHjW|pNNT&7H)Qk* zyN$W3hqZD0g?K~zwHIvW4Q(#)455G8RTrAKw98(wF=rNwn0`@PFa`-m+S$PfutN;G zzIhtUnE3+BzL{m$MzXh2_Vs4=H7t8YB>P{KeX*I{cMK|Snj!rkPqVwCm!O=@ppCTl z=NZ_s>&RI{DZuEdFeyu(W`2=e^PfgaGGqaM?5UHA{hou;-T1|h>qx-89W&GxZNqh@ zf~XZXdZ;De*n>YKF|roLm0FinQM-xN~-48Z06QfW>x98 at wky-Eq-+?+8G5g2Ju=u zS+Fn796`!9{XXJBP>wA at 486#rG7A!dCe*ZR!O*Io^E3ZaHeh1V)H$b4onu7Xk+(7Xg)Q%@aK at k5{K-lw at IOS7*jzR}uARw` z=(ybmTrUsn>0)-3g02YLz0ELLMdEIs&lcjfw&%U`9v!3N0tvC1Pc1dt&HEhD86|Pb zm~LE*aC+qPswaPg&ZtBZ#C);fFQODD4xNJ7^V#Y6| z_y)@{BKUu?(kcoD!ftq1yuV4Jky=sMOee%poR>m&nFc};Emicr)#Sa!@9H-ZKj3&3zGld0f~A>=C`ux)yq|%z{_ZthqQtNx95M{<@oll6D|0+MFwlI!6yXu8j(AGCw3uhue|pFFzDa zkWT0qx^9<`_+nsG&zq4-D`Eqn)^_yUI$G=GqCIIxYeA>QiSSgXe;2p`sAhmDHE z#&$ovntMdaN1Hh89&9h0`DT7MThuw5E4Xt^Er6Gze-+#f4Q*BVl+C>$9o1UJp$Vs zaPlKF=Q=i>S*{_xf#*<3z at 5a0+e>Vw={PE}KKEuLmC7z1UVRm=lQ|&ICHX at qjAa~nFUB%JAU+|xj} z)N*W^Q9?x1${+7&w0PX&om z+Rg|@Lvbdh&Uo9q9a0&EeI#K)ZRN-2R$yHdp{`})l=#k^LTlUDlKLihzh7~xu0j~!9NZawb@)C^CyiOfQiN>X{i at _&baw5J9noj) z)hE`+V^dkBHrb6vKbBLI_1!%8LMvj{C+gUj;4`-)z^HrSOOD%=8UAR!eyF1xd;QV< zii!>b&aOS&kqucCEw!{qNA76lfO{VDo)lF1F*1? z3%Mw!tJz3nD8 at JOa#?MH`HVwUzA&J`s5Mc at E>akNYf at v`byMat7ncHu5i$*IM90!c z)cT3x at pf0pA0bUDv;Bj_`%kk;{`2kvJvl%gg0|oX0cb$RV?WnIb_)iSzx?l*E;UP(zj#j-nP^ln_TX^$oI(FSqX;c%dk}agxCT} zR4)5<+?RW=cH9?Hu5?dEcY8P}H>B+crjs}}Tcfq_Lt!5?$bE{^?4DD+21e*9L4 z_yt~nMmtpItG1Fa>8wZCaJ-XF=dzw3H)~mUo3Lx|1Yz3-pP=`RlQL7qLDwuYY%^D zuRPkrN7}>Nopj6?)3{E|i at mckP58?iJvo5JOYw~&RD?%>jT5=!rADhzID%3h5DFvd zVY;-$*$7DLJNh+Sy3N^`!fos}rV54cLNT|^ALZ3n;K=tH6M(C^+a}L~hcnV(QP}xi zkg!{q-~GjX0C|XIQQg7a9ZKNHCb^CNIF$WQ&j&8;R|5=Z!=7j(8sdVYKL;hqb9Gj8 zlPK>a|09B>48H++LXFssK6*4Wbw;Zih|K<*<`e7azN%|eS93{em{r)G*oa;xOZiS{ zNdzkHsT(MxsTH9Q{h?Ai5%csA*IOImmj!hmz>+!ogVfMu|?&-pYF!Wv8xNuFivoVvKBW}!Q_pzLfIYQw}^pGp1I~((b zLS$c^jSl9h1C4DJoq&pV+=H<`=yqcz8>DQnQp-`Ch2k`y%drVS5M#;S%zmj{kF?DC*Ov6yIqX-}x zZ3rnsUT2Jg^8*t(GH z+L+K#hix;miUXNKd&fa>wC|oXeDKJM1g+aJUs|QthRcVNJ{{hW%bd4{#wa_8*M#k|5 zitE%j;rE)mMAz=QSSqzzDH)B7Bco#IPO43=lN&sp#NBV|*rEi2bI)8ojV2(0Tej4C z%ul-QZw+8Nb;~VsHC+q_Dl6A6SJK^J*9LZJO+IF!JAE~x{6|dbx*w62lloiCji{m) zvJR?N=1 at J!5z9%C9aBoJ?*ln{p&TA_jBSylz&zYxq{%^>m9SMD8$&>Y!()j{2AZe{ zFK^Rij>Lg8=66O291inUzeg{H;*TiJ9I(yP4O0Ci%3|^;=)4rBGMSX&qNE5*R0F&Z zhOL)LhWEnuYf`EjPHN{1fgw?G%bG)Q94~A;OdFW;m-Xnr7f6&l zkojGN2TAcjXDS1JS5+7}Xn6eCUxY$GI#ct_&~%Na#$8OVmv0Sq^tN&&3K&Xop}Tvl z+~i&Z at kCefZrs5wu2r@gcNV?5;ZD;E_7^$21SmjyPjDqLZF~QQI*$P0k?aaC!16AO ztp+o=?_xzwk_h1-X(WVE(m)7 at OFbZr7K%Ev8jS9yTdXSg at 9aVEMpXqI+s^KbEXmJ( z`W73UTnuJmkc@%NDqn;?u$}%h$fG1)Z)$N0B6&|i{-z*9^eMrUdv?8#ymnPYsAc^l zp`v^mZ)fip3vT8Lg{Va<7BuEEA^^sbX>u0a%$K?VeFYEG9ex-$QbIXAU_v<{aiOS; z)?m3%bP66m%7n~mQif&hX~_(aIno#i9n#$pE|>0taF#R(il+hA8(SuY!()!r9YTi` z4B>LA6NIxIi>Ve9*3y at 138PvBs)e=S<}7LfR%ODf`chS4RFyzgb-}76AP{R|p`t80 zQIr#U%4IPX!p`%ddB4OQtS>V;eiY;4Jj2XYj=npPn!)ZCi9LlE%8KgXJHiX4<|?W~ zF873>r_Zsl6Fy%qqOU0&P{3lL{|nwLJNf at o-s?0h-T!aAms4*<-2pkiv7#M5EGd}y zuq_k4e3*?=fD2=LCUE)8X`V&C0DEZ?(pe?kiVyH;fOG3O)j5mtYRb|V$lQnXuxc-1 zcfsY~6U=oEv(gV5A5-6!rNN`jwC{1rND;YA;<89XzI)yI-B1MvnX)kpb;y*x!{zjxf?kH6zB778Ec zr>%=LsfSf1$A}5$Mm%w1TAU(~Yh z at DlEnO{(K at i)&I45)aIv(|%>!MuG!q$C@#kRe*xn2*(f at 6-OA-3Fk>rCGMEt1#qSe zdk0yUD*2Rp?YSM at H5SmoUBMCCpwoIMntyYwu<^IrC&e8|ek<{`KW|`3l-uq~&|Bmy z&=hObZ`zPx8}6~f$ZsftJOyzPLJ^vN6P-&J(1AORN<+=;5guE zWpF$UhfsKcWHN<^6k1;}M5RLE4thooxK1eiCu6LL3l^L>A1_);UM5_CoG^l~`%~b# z_Mx_{F24AKLstk?-#T;+H^LX;)lPhaUUt{-MbhnuMwP>eP_zG3r|;-*iMfCOjijY) z#4{|i5n(w#kfBpMvw^4V{z)4mX|l$-dqn!W2#jNk8U3os_v=F8U_Y%|u+W5}zxva15sHfaX at S6ZW;B1tr-MS#BmOw~#`Y%v zpMhLj at LT|s7Q9N*f=zlZEf}Qd(gGtr08%X@`9MBkS50D&qvsNXsR3MK;Qm0TwW;h@ zi;?f;+pxmN;ibEPBG=*gjg3Oj!on%ZfRAAOCQ5Eidq$pcUBQzmB7f1*tv=O)-x=MnH zi!Bi|+=TADvWeA9HnEg1&W!OAAbD#<^1S6SgpkQWw at O_ODG z_V|@_MwSUzI-PJL=gP!azCw*8l0D=lgmdTsb8v}l7PqZQ!eO-T1osE|xg zH*ONy{atW=B2*}S$m(di`5zY#x&?Q?gLTl;wwukpw97hoAY-#l%()OT+|#kOT~W-! zn){;{TApk9sopK1GiT%YN)r|LYTsg$)9_C9)}WvQ_~r7SXX5&x|KDZnb<^n?<& zK at pP0+-MP|HUdZxm(7Go_Xqn5k&;BY+8TA!D?}R5t`N!3u&>yV5OvmbRD&;+C1Fib z6$ys3niR<{I9CzdLpY8JlClvAN1e6k0aKwQ=`r{XTLvlixEJ`N{l7+Pu!hFuD<}s; zNrflD5yV7J*sXEAH=4X at n2)@v_dr?}HcnEJak>^FCrccoIvm}#trPR2blDTZCc%Ea z84-FHoDpef(o~g0!Y1o=TvVm#LzswamRCf at ywvzesaPprDOEj}QuVc%n at 9$A_CdW) z*%r)XP_sw|#bs3N{U`W-V~h7~WK?$#LRevQf-?Z4064+o{F1s0G$}#U6 at O+qu;`I? z1X#(w0<2`O04vEyfR)SySV^P+4xBwC~#V~9h>K at 7-OzwX8uwJi8nt*R#fubhVKV+gNU<-8PV%UpO-WS&d z_eFe>CfzYEQ|do1N9sM!A%%@wE_E9>OA4`Y7Qvn9$C?!C{=|rLqpC`={L;L4J_Z%L&mi{LoU?DeKydSWa$qzoutH;#f^LMS{m){F65IN0Hmk1GQoV) z5dh4kluO8r2`X7m$- z(L8HBCxf5$cgc(y#dQoNi0=bVyJ+JT05;Bx)^H(m{BI~y{tYeUAx-C)ZZ+3ArX;2w zh*9n4>Qy4nE=|mXjZU{-x*dbw81%$Iz#tHV0Oxf-ht*y(G(jz;J;zxdo at g#xvroe( zYK7>$>4zjMerNSWL=rd+&cmwvz00bqeEMCJ>fQkuNO}LemLkekUJ>QBW5`UQPsA-( zQTT0XEqOt(BUw<)Ath%m6MDZEOhRuI8u<#nNv?#K)lsxWnvAK}oobV#hcXnt&lJ0m zOG7pKqWwbg7KqK`e^{&sF7geUjB_@*!B*B3V0T4+3(3xJ2iO*$os}T_UlVrO!;Q`h zdPk)4^|xAOZ4|u*A7hGME79*ngsMJ+Me8l$M!ggTNy})zt5U`Dnfo z-DDS?mBN(Qq3)7!Wu^BM&Vwoxd_00&WDHVLI{xjyGHC{q5yxpOwXFpx2 ztgyMlK71S~F#7VYv+&|K%uCP#ne z>5IUMt0l2Y`bFP%(k#ZP=5xY^w{af(-~Kqx_ z4KR<^lSF;E{=+qJpck`_vg%B-VJ%m?WcFktt?fIWjX)LWuqI=frtJqhv&c<~Z3 z&yAj5%AN~aP0HyDSho#O3gq|z$6DU!8A^7};gf&A(9tKquVJ6W!QxgYa4MS(kuw>y z8gR&h4BzR`(WAR^>NY&FoEVCyl_Ac_;l_OvBk+Z%2mJ82xh9$*f%M5SlRPohnQGLL zFLRPNH|wUN?Aj)uk*^Cy%*pHlWmzmqH%G_o0Z9cMUIbBU9V~oR>JMR)bX$UaFhQ>H zQL;=h1ec=8sRQ+5>{`d2l(#SC4MT6)kk?nv*|U^noFkMc&o_0XO1#PaM>Qq(f zQvJkmy(1XH0_g&TevY#?yoBhWYm&!kS`0Sx#85}D^G`;d<10eI2Adj$VqAD9g`n~8 zAeQWTCB8UTooIBXhF^wJ(*u&<=W%Ir^JK4XGz<=^eb#DfpVjA at I#T-#XU+Buz;SGN zx(OYg9D~&iw3Ui#hzFItzc3 at gZS-z^<@8BD_lEHHPj|a{FE)LsV*n{DW}xn3Yg;9x zVMfMX at OIGSYq$m*Y9u-$NzYH%);XiZfckQ_mYQnp%HkGbn}EArw4%?UTlR%76GV`e zo|0hN#joqvM2qHMS4GJQ{_r+U$ZX|PLxjT7Tr)9V(@Y$M-r*nrrim*>w$olj2DflX_cEPB)(+A25b8oRvm0~~ z4ca2x{ME1vv*|*75sD`~Zyh3AXYN9#9|)rta95P~j$)E?eBk|h^zr~Lk}`m;=@*X% zT&_1cf|cR-5^EL6QdFVvb1x9snR!p#yLYe)tZzL+7g&o*5T}p->^{BDPbey;S0%Ga zoa9*TjQq!abg6djBRZY0!aCaECtr1VD$VsO_d&-3Xi1a$dLfN*$m;u9W2ER-4Y66| zQZ;PEBh2+-1`eO6+rEIi?&H4aF6}^QXbcTG;Myqw*dA>r^Y+ zDHtaQ3>c%=aSuG`rUR`g2izQuCSgM6-=o)QEuIgpXN~@5G=2);1SVM6eoWcPF2Th= zTH#*Ie6G1fQ-#;8VJ;A1q`|6uzoJQ9r((nM7m!lBb0;o*{hDz4G&6Z!t=z6dD1p~_ zCH2p!Oa~2L?mVx@`<;-2=0AjO{;_T(V!c+(p at n>?yAZyj{p#?|4kg)zeMPf&fQ8kgb4a!`y7Sz(R~? z(&#SWYxQ?!Av)*-N)nB<3gvQaU-L0ZFwqwo~BQ7>#`1*8yR+lC0d z&{B5Z7*y7dwRUux%v_A^$(=`bs-5FqXbRmSxWwJg#@@>e&N7o+=II<$OKXYw$t8Vf z(z{0;{FbM%1w>MbpB9LCE9%U?_|0fy&6T4sS^hHiosL*bmT$Ed9+HeD%Xf&|LOq>f zqH`_l8%SQFgvF6dj-IWEeWj?fNfmbfAmoKLRO;e8>l}gWRz)PE8yv}C4ZMaInhdnq zbh=V;P!;OC7MQE0(j;<}B*l(LNuV at zJRUnqw~t3*GyVcBEe#&8gGNbR z&E-;GH>#nE^3R at bUm*hb1b&6GXgv8;V2F(3SH$?iuqNf-zCOS+R+vWn% zWnE_xEDF7c{>4kZfXltq2ZGC?&i($Bj_rb~g7Z~gaJiC{{uSrYXNkUL$WFha)HR6)o?;K8h4xdqI?SL z9I}r#7F5hv!(N%rKz|mp9L&M_=QP#wKD1`zm`J;1eBl)-u5GQ*%!UC}HPs9Cvq}?u zD|MJ{sX=zv at L`X&zVnkHTlVUZ4QW!tZl6xR&mV=(D7~;pvF<~pEDK!D$I}sX9f_=- z at 8VVGKgR5Dz!xonSLuWJWlOPSG(yhy+Y?(LuCI)+6{7^Z=t*1`h4n&7 zISP;puSv`0AmCJ-2UO+hQS3|w2dlRd3yoYC>qJbG1Z`P8TUFg|B%*?R$d>rxRT1&Z z;Vv{V;ednU`#8GUQj;SrP-N`gDRRECdY30tWX)C%-!^Es~fqF)`Ms5CXG z3@`rw($(V^bVaTlR5o504=s3bJQ}K%hQTk0BH@>xPKttG5JkW*e;xS)_t!aw6f;E+ z&w$VMu*$Fs0H5xb;;QDO_t(9YKR*JN$7*kGQJ7O07oB~oPW&%s(JLWCe1CMeAE3cb`+cC7(`7# z``0U@`FF0PvKb#lHv*B?%2_Oj$85g5^a&UZ;mJSn81$CE at YGM#Y}UIME>rJ>!f#k2 zl`Xi;Wel|0#r&DvtsQnc5e(CW*;5lB{wKG=l6CAiMl2YqRFWa){CiD%ee{CALj>r|d>P-HkTaoLyC)Yo9|% zHqlYB+gLF?!{fTVMf;^#v7u}&tP-Sk at R}k?5la3;Ek}1 at EuQ&!RA(XIhDbmnJuaVQ z7Y^?v<4T0wVK at MhlI53Fpr6b5NQTX9JCbr&r8~e=kt!LWQwTSVlftWM=o8agGBG@{ zWU`4k47z-s=$fn~xF(t)way|NfhEK1=*lKs^UydTW330}GR6#WyP~38W&ww3x=@!vQ8O>hkAM<;JH`c?GT193x||Gp6>wmokozen&1n_8J5 zms;^F(iHrzzr5G;7_=rnc7y{M$-SP3upuHa5Rf&)5>%QY%B2|=vq&El>4RcVPZT`& z%8P_BeAxg<>Er1w0;|cs7zhjrebM7jrOoAz+cL~2ghD6X(fnE{LVILx2Lydfo#*}3 zD(|p03vt>NPBFPlaI^h^HZrd|x~Y3zvz0Sg&oq)qqP1x;W4L3*xWz4|*t4}sCDxEl zarB{%rg-HS|6z*h!W~WVR(}+P(G*WAwDj&T4acGG1|usUhJ^6`jz=@(8qWhbyD;d7 zJs~u`7mOJ}RZvFQ)(Zw7GWO{&4PujY!qcaDl1^a$P6!SF3ph>YqmIED!14rO=0YwN zYvR{gwMM!x{cp$n85-~8h)|Lp__BYn5r|(lq4+JeOqA=;_0(u|tb`21o}2S_-+=76^AxZm%D1eW=nP`DnRHv0)hf5ytqr=(iT`c)%i z#U02wS^ZS8Miqr!)p%?bhTh_XDoJ)*fz6eiRG)_GmW zt at iJ8^i_=XRkB*ppB_oYV|*vV+^->DTx)Sn&?_JOfcgO;>Bn!OrLD(ou#kdBa-U=GSdsJ>3agPx0=hrid`j3*4nI%?SR*{O-5=#10W*)?QVl;r z^;bw|8M<8{6s|zEjRMtADBJ;D0L)oev0$|>(9yZT9&PmZ1Qeu28*c&)m>_?hD1V<| z*h at x#>}Ex90?VuW3K=MIy??~GK0+btRK<_oD}~@?u!;nAkK3bTBA$4gT4gt%&+nVy zvP9?$Vgnsr5}bSd+$ck_%jex+K at 1(d;_Vf|kt at P-zJC#K_up zCfWy)F?-}YRn;=VmjdBSlHlnKkLuA|D%1^Kwwr-&5&rx$T5cTR+m3iPo_?M#I94<~ zvPX=%gn%FvUGXDUrcj{^iPYJsbM=M-hcUr$j=Z1)HR=g<-tb==4vo$00k1{FDPfyo zLhP5i*B&6Iyqw@*(U!iWb6!rxpDQwqy9&0&HX84rz zhF>wPfK}br8?=FfR2ZZ<=M96SP3l;zDXPxXlMhzI87q({skO?8Z%Jz~)-Hd^E(%9| zeN?f?2NUJJNN>i}evZ~8xs%50697&XXmT$#EOH{z*bAWP)M&hVYmouNnJa9rfWOt; zQXk}vju&3oXSh_dD%wV>6XsJpaVbk(GsL(Vx(Oo1pS*x8Z1<1Ia5e($ zT1gVSR|?I*1Gfr40#CdMoZxz($qTxE8F8Tmy8fiOfS`M$J<#3Z1zqwE4s~(Zy(tpJ zc2&dTCeWfS!sBg(U!f4~S^zk0t!@p&lc;kUajafxaz;tidgf$O`!E7BBz at j8DNd`V zI5~Q(XC}gV&lXj|)>hKPbDw6Uc3(MeEPy}_%Hj*EN?D;n1E4|PkB51Jwe-%IUJ`|) zm1zD^`12M7`+ at C(eJ~qoHnar!G_4wdz^tG<&cn+5g*fwnG+6}8_oBSVlc|Pv6OpwI z0OTLE$9r&VqDNBfy!{q3q)QwD7Wqfd7J!}zc;`0WLUTW!yOjD0+ODcAw6d*bp1nV5 z;^qNo`S4(mR{W>4ZxJ`npSa#aKjm4dJmzdkxRP1ntH6L)#beHzZwebO;&w8A&}7_r zPZHexXqOxK(YFbbMdx<|5*L3*XWy`l?It?>9-+im(6LRoisqB(md7 at ae#|($_mFw1 z5ScX;VIw>AxlvA~kCk_H=+mE-_GAM^7GU5f=M(BJCZk^JW|1rL=)79VM>ep|6Q-;$ z_fEj8R5eq3$TyJM!(H?qzL#3wQEUJ8k at tkS-D7iRf3#@7W3Y02d57oB3qRrq{@syX zl|vQ|)5E^6hMgNvVs_+DJ|~6wKfl|Acj?ysycr;+KA?V(UZ@;bT_F=$|7cv zGLW2{DAN|JYJEU8Wb>2eX$qEV*uMKYMT at sj$YoZ@!%d_zg!LjE;Rc7+M)3R~4E8`e zfNGQYS_^6pL*Dp-zNO2S@;Usm&Rp^$ksKE at ouTFfUM zcQOyDoosSvIoF?6EdoV{UEDWLa~w+y3950gS*UsEzDBO8XSMJeJF+9Mv19JiH9P7y z-;_S$9%Fkb52SiM#tQp%=$O{mX{=Oil at F17YSyALgevkz_}Yr$_K9 zn%o;`PFy{x<~)S&j?>3$eq-0g;a401%D4q&&8UY(PMn|E{Egmb+;S3i=)(2VBmdcj zYb&@(^1 at 9thnw?r5pLKm2d)~&JpV99&Ig;F6rW_iT5Y;^d7EY{I&ER~j0UTsd>s&~ zk~O!9xThh&HJ=p=R~h;{1{BpxVVGvJ$;EhlHvzVhM+Q}*y*gO70YshsH_&X8%jKh7 z??A2sSaE05A*hy!2xh-~Hl^{rhUUBzym<}Yyd!+``Zee6<<0Bo&Fklzm$yOOfuQXE zk<2rC+rd(yNHt4uT?X|n-Ji5BV_;?e-lB{_D{~u`S=(HOq??oqWfrzyW+s-I+`7z6 zRwl+|g`%Pno3{JrCJ=9bSm8JqK#d-EE- zdAHp1-jinFM90?vCufvFk20adki??1(kOA=pZwo~_B)1nr;jOJXEDeH*cs#tJDxBv zKmj)Q3ad1CEetot)VkNH)US^H-y|W4fFN$GvdR|{0m9eMZc-Bgqz#EBBNB@)ImRln zUv#+3t$V*oZO1?r497Xt3 at -Xk3I�}MRPl0*46jETGg(>(cPlWg-U1xIs5$XuXypHaeCjjy| z;4}Gpq8w#1%b%Ef99;xdsR<2N?Q#{i$qJ2{EY_F$OMw<)SEcAwqCNe at hEjxfX_RZy ztC))JQQ(b9be8V7n)l at QaUM1%n6KvzMz?{bHgoyXe$K=GFzAjuP?}S}*XS_8uLQyR zb&TqHB0)Z26F#g)jZ4FI-gBpIm&zTCLwm{~(BdO|EGT0=e>7jQ373yv-}SICr}dNgLg zUzzK*pN6&=5zK&?V5JZ;fmk-*YL at 9@p7Fm9B)xN<1&;<0$56EmJ$SX9yoIn#t17i3 z%K1OMRdanvlIoLsl=9pMURRlY;~+r_Q-Bs?9{u*@? zZI?eozTYa}0jmoIo((0dfqzX5wa7nN0P~d0HJT3yg+1ts(Ts34?1M2(B7-MU&eh?- zSRN-l)>20ai&HnCf<|^SSc9vuB;-y}) zI-*{dnK<==dW(Px$L%u^^)dyq-|Wjxs%yF4vymv33a$`U&FlaY=`lYBus9lQEy^L= zsqT9rk1}O;6Q4M#t48=#gra6Ne&Vz}m8<|BOf-}#KR$@4#%hEww5*=g4fQdIi&YWF zVL$PJ4U$vm~1!*Sk?&&l0y<=NQ&p z)TbC;kkSY$ztPw$C at syjrJiE8INxUmP7@$;Lc10C7@#eWp>Lzh#Usi`v(TDbgD05g z4T#ai&=S4PHMyBs`^zkD9W^l;3A5xRv;mrKYvwc`C3?&*A4R_qA#&*r+J#~&j%;*H#jP9>$MB;2;MCY*!+Y)t5 zeKqeifbF)f^aH?4-K)$$jg~AbZO+Sj$q2CJZ?2Q7qw3m0m_QBtb)Z{&NW*KrZ%3Ug z5t++7m9kGd>~0`*m)U>rk5+V#YbNOrDznJ93mTN)=sgH)WgAkIe@&F@>~byOgrZu< z5M|aUO&$6OeC-WVgF+L^IQPdY{qW}Oe7U@#4lSoPoVKZDc39TIN_VVqF@@9Snbk zG<{4xoqx!67V{DLhQ*bxt^ww4Kk7n69m?xdJW9{~iU?(%lkOMS3@| z+wFnOf at SZ2^w!fJF64|ZqCetu8>awxF#Z*Df}z%Y*zqfH at KI$V^v?XXompsH4BK1YEHx~ffbOIin& z=z-8d-Nue@#3p~WnZ}~FWQI--i-e^te&MIdbSx!Se>-|RUTw6xQdRRY$5gv3 zpz$@b(SZvNPa|3H)G%=<$vgr@`M4D*5WT0j8fJxl%3;+5v|62w%SFL*%p%Xwm4xjW zfD$klN}?_1gKHik$l3?c;yj|phD%)%413H69hc=JawS2QrG({`i|D4Hxnj*2v`Rxo zn)6 at P@|RjlD5Iw*)Cb_Rx)Mm5w+&dba at 92vg-ajeISj<_;yH}@xZ at j({I4BUx5v>r zLGEgiGyS1yQWpyvwL$wPR&y0H8Wrw22K=#S4LK{HNy`W^PW_LPzlXi8vl=X;~Bhu~i41YNh*3A*ST-oCNooxhulcyljIHfsZ z>=fG6nEim8cG-jS)u05qlSNMIX at Qk%k>6%;`z^vPB+vH;G^^~yyPNVAbEQzIyTvpX z)9o&8&;fhNhrA=HT)3+8ehP)Pf2c&sL*}j2rIRhPZoA5l=qr#cu2x=3giY=hDg*yY zJ^omhFH<(htoL3-pNQTNjDyiI1CC)RRx%@zxv)-zm_n5&<3CihyoOBh2^8 zGvhg)4^3e5%*{-m`5KpJ#v?k8#oH8`nMh(Qx%sIUa?V{hRJ9$S9o%n~M1HI0w8VNxWrvRHK<6G-)ttz+$1a?fgIAUYbjXE7fH3(gdV0GLk6&ENqcP7cRP(FXuK6kNcBl(E@^9>{D-MAx zbS7Q%t5$-p0(8|S%7+rsl?|#UiRwwb#&-&M<9`UBCy8E_Ge|{^Z8(6v>)dewe_itp`!R={knSSmKx_ItB)+&AK zR+jz+m(4nVw)wbYVfxCDt at K}X0E&83r53hNzc&bHIpCs^T%Ox1IxPE4bJ=)ab_pxH z#kVZb5F!6C^80PUcnMGHq=uyqqKj{<+PrvhkWTX>0cC- at 1^TiqQLeGbXIA4Ksh)O( zDvMm2AOk0U5a^15yg-L%U!r^(cwVI+pbFGQT%+evsEFLrc5 at 0tJ`A{g$(n>z5(UT9-nJ`deZFrTx@ zC#*u^K1iNCj8wOw%bQqB*7Wt9RZhHxHX;KYLCQbh(r!ec>=O21D09$&P5u22#D-{t z4bNFs_~n_gdM=qGIRTmOE7Nr3k+Xq>G2b<@8}!3W=3M$lXQHObOuGyLrstqwpO50Acta?D8)OWw!$Ct}&aUTAaiG(tHjdt!!m=Da8=) zrhBt(6 at Y7=B{kxI=*TlcQLXSI;-uk<#LL>>>{xmDc`EBkgZ{4mwu#Q+f8powT?u5B zJao(5=m}N=nwtR04c}71D5Wd^$`5aJ+`mR&SiH6g`YBgm=US2bU-#9|Kv5VoP4GIxMStgA2p1%% z^)*dUa98`L38IvjUMJm>{MS3O6Y$kDY|mK&gZ1`>CSS`0-K_E+kt`FuO!v$^VM>&@ z9wnY?W_AgBUZg3$i{8WM{5$;IlxO}2^$IqZb~N1C|Ggo4p!&%8X#zKX`k)+qaKd_v zK6a9 at ZI0gPS1PXimRMt9SB-e|#=0AH4QLj`kSf_A#`{1+F!s|)CXD at c4%>tRyWUvv zpzMEeLP44?b{+iI#p*rLt3*JY_ at y_l^@M8ggYmsSw!jKBQs*7`Esr2JoatK{ zsVmj#0zXfRx8(-3u``>u!j#S$8UDU+s{7iug;Dx&xm)#-~Cic4J|_C ze6ItD?!=9zZ1&dH=F`8r7%a~Pdg$~w1j|si-qHzxIfM)*yn2iDgt{sVn%hJQLetJQ zF}o-U9asOX%f~JX*BglDaH~cZ_JwUI@<|GdDO^wC1`401 at EHo9rSN$QH&VEX!j~v~ znZj2ne2v04D13{;cPQLU;rkSRK;ae&w^H~qg`ZNmjlvxi?xgTb3U^UhN?|#Ldnl}= zu!_P16dt1R2!%Bi)>3$!!jlx%QFw;Je^Z#<2g6wuK1ks>3P(^_+#AD{6lPKQ7==j` zPM~l!g at Y*!r!bJhKf*Emg~Ia`)>62K!fh08rtl>SH&D2S!dwa$P?${NeN<;GJrAX@ zABFGqM%^XmGd58^DxWUeFAX&xkOD+=mE#U%R+e+6B?}_5WOPo!ueE<$f}q5`xgPSh znOKP4!d$Ro8^P z5^5i<@*`czN8do*bRaM2Ptidai&RHHxfu=IVdQIouPA##q>L&O?I;)&4aO6))!Ch=o-k&tiFUc_1%05=z>wGihj2g1!X2S zms!+N8}>bg>J{HfcP66IAIdwfqr88A3fo()Oh+Jb4eLxgE6UfW0Iyl(NcT-VPaHoY zNY9L%T7(JbEhUk)m|QacHb_?106#2;%OSfUO)V=4*#@y(CPwWUPxmBxD05##Wk~#n zJPyeZ&&))*GBIke-LQ|lp_fl6!9RA;zMD at rsY;(0iKfGOu2wGTX`Wq*Kc>cpNKWO( zCj10zx*xydJYVUDpWCm5jU(5doTULq!7it9tV$F?1>LzL9|KI(A5-s|qF2s9JW?-#plqOC_n>p!d7bpYgL2RF^%KIK(s*cBq>Y&5u-Eau9DK1} zgcrSS&J{y+Qg>w;8Vat2FGWC>HI$|2MYOSHL+K!X#j}YW!ipytkB!#o(UD2B9KWTm z8Z0%uWk$McHL&Ez+{>gX_b49V at Y{H}q#b+AQ_Or>n=5FZwTNS4#kl20#{hCiuFQB) z%bVKbta661EeJSFpvv|A{iR668$pGzILj^?g>7X)HRh{mMfgvuC)5V37qZ^;bTa>H z6D&6&YvF!JX{^2N1)zQH=*b})Zv-G>_z_44pht!)BmTzd`%Zt;=#n5g&?Fyj?>_^Q>=|Llxl4>WYj-6_gxjNP5`_uJ((Q7; zNK_0;G#|_Fl_9RXsJoKr`nwK|5H55}~7h23zH^$495NE&U5wYEinOjKA8&?Xy|)3K`WyLfM3Lu*^~h(-rBVU&iW zZE9mLzUk=2-gaIPd;UR3FP>}X1qmuvc2pw8`+`GDtAb)jH4f>xAXRKU+7=k7;N==^ z+ys}R_m%I(~3^baS z$Cl%ed94>q+=Moe&yam`b=!WXCYtajv>Z0GAKKaIc|e&qp;h}^bb%@gYNsMOF_4;$mTk=bb+G|xhv4}#xs2{v`xb|tdFGKe zZG%+tNSmfPSLf=a&hResNSpS-hpaJY*Tvq3_F07IE7&1$Ta5VA;WpK>7e_mKv7_w^ z<w=kzn#ayJpO~f-@#+;Z|7a?_vX7=rf=Z+R`EEO z$7wuH=COsxqj>yMtNI5=vEQS4Y~gV-kLU9^kH=5)cq5PB=kZP+AK>vfJif}~PQzH- zhsVQsJb}j#^EjKwi^lMD9$R=E&g&b at fA`|Cj>lI}r}4NGZ~u*4v!@sZ{YDOJl at LVT|BPk at fjW~Jifu>;F0`$JRZm6**wnX z at t=A8GLN_NxRS@`dHgev>v`-7SBA%-6{~JYF at NuP?s7gLz!f(|_Xe86F?t at s~W_!sC~Dyq?FKc>P)Y z_iP^9c^u2*VLT4!u|JQm@$x_O_&kqmc)V*^%YHr0`?-q8Z?x)nM}Irs)R9$3ou8iK zmtSCU=-VuA{b!u&N9mu=Ve!jv>DtZL-rtrN*Co)W;Qzz$zwi$~9bMUnzlnM2DN?#6 zGcP?=%E?<{8WNd*7p5nsp9b6Cp=#X7)nZaacW}X)G0p6JbikyI4yZblCD+0 z=4763u}+_yJT=LZFwHtKdFr%BTIFy1n!gv5k}P7f*z$Xc)+saE`5qyqqZvOQsf7q*gSOta$e zgzS7NB at 3o7Gbh`WkpiQiHUi&g=a}*xsf$c(jGF<;k-a!OXIZw1+R2mi at q4xh(xvHa zVkS|UB$yUam*L1xrMk0oBvZ;#_&~~ntaK=|C_O7HX4HtZtSqW`5`Eev<(Sw^nzWfT z-5HsGr)jt;JufdO&lJ5plEKgPbZKTz-eLe`?;03#SL;kHUqWh5wmm16y4WTUychEp zI+mnoOZn|p0Pij7`82q!I2)s3?X(9w++l`?9O-#060)WAyo{98^dSjJ>3R8?`4TR? z7GIs1!&W5COLl5{N8iiO&tC=qGqrwB%)uoHgP*yw-7=X}CQ~ZIhE;xy}=q!rSl zoNOLV%*jii6PY$5GHnhA2Hbhf}f~>FkmI=FMB+ z$jp*5v**oY at U_C8lf7`>q`aIZ59eg2B}qJA(h4XvZ&FU)k`#&khT)%=l#-X9p6tj) z$k6i5n*bH2(Rb+g#7P{K=1oao2EV5+cpT<^9)O)FNqN(yJb(pVbNckw=?P160ix!y zC^09^K_8pu$j(M=$kxw at 5hJ|g>BveWpv}om&o<@elXP0w5cebK(n(x%nBa|f+>)R|NgE#o zxxAc(c_~Y#q%6?}ZYr#poD9>F^d+z&?r83xv?$$_o0mR3(|5h|o-l9;38a3fWZ&8H z`xyX2J|(q6Ln71eV&f-eE=f0OpfEBz+LV}*mTrP&IhK#nh};#rQIJl%%*34B75s${ z_%y$tx->m+Ssq|ImZ^D6I9`y_aRO6d%fqcgw8lP{Pma`-!TU*DDToZwMD>%qYUkDXI zZBRv8&N5SKR!V+8%ReH0xi zjyzLp&XQaQd|`xXVpeAAV$+oL^-HSpC< z&&iOMrNF9gXPxJ_UgQK%G}#X$T7no_H6$a)0aQR{Ht%^JjabL^vU)5z2tT+-aQL}1 z-_!!;q!qcC71l;d_QG^sE at g^L1LQ+nLF;xPPU3KhlfbJ2`Zq^|&la_N+l&LFwR=Q! z|CToQFE9NG2W%aHCYLSBgq?0#N?l*v-mWh?j+Q%NFQ#t+MN) zM at O5cr7tvDCYT6yjx{|>h37`*k8io2^3!3S(pQ+45{9*8=I3UmtngwIt$#TFxE!KK zdF!2=zJh9<+wS^gWE!+R_sN`5*l zF8D00GeGcpd`HS{(*xXnhkI8z`%B25k)NI?W{YV{GP5=Os`I562|!G+%$6e009#cK zP1}&^NMTx+rvnYCu`M{7uxmjJQZ&SznSn!+FX0*+Xj+&96;4af1xV%qng+-gUup0< z*5~aqg1Zq5kdkSJGboYXybju=v*iYKbW3tV>u*as09tBlZ^vdd0saloqt)MxNBESd zr`^HUMH=ms`KFX??7T_iyE4-eZDG;0|2AKsHxEF9 at B375dl#g)sMP20|BvYtHXW?ohoxXwKVzF)tlAdFU^HSeBAa zn>!n?K;K=%lmS$8OOoJztscIffF#Js%v;im-h=n4E%6;7LL!rNUOH=pDJ5?qZd#aU zI1x`6&ddXHU89$vLdZmokIauurFBANvndz&b!ZY)Y4&*@!DG{qJml7pP5}CJDzHpT zfV!QOm9mi2zd)=r@*LI$mOwnfKng|zXtEqH0d5Bhl&}QtL%wu*d*xES8Jh8eBYS0L zZY$~li*UTc(!CXF6=?Kw2eh(oT6#*_3LoUJ%}Yy)Z2^!CjDToS2aGG=3sXWyD+pMc znZ67cRq7(7iC_t?z^nuSt(Jef1UPeH{xG0E at p}^hU^Hs69m;T7Gfg-F2znqo^5(Hs zHV5!XDgWV`2hh$9D7AaH8YC&fsvPb?028mJsh?r7<^l!#L zM0b0$A=CrsnU%G|OIIvd!3p|&9V4VPIBT(vQt|)`E%kDz>~CXq=VilEy8g2Bp)N1> z-m|3hU#>l#JLc_F_nR-Iy)vr!Y}dDT{Cmai?i1&WPuKn}%D%13SF1i+(|P!gAOG5a z_cLjs+xuTNZGGJK#OJ?#Bkn3(ef&%x&v#!hdFZp_*Y*`1b3VK&t4HbP#c3$P9R1EP?t$a}lW!G;)Gq!k z at a-F$KO2*^>Ej6}_kVFV{`!|6e4AA_$}#7hwL0YFzaJTY^q(I at pB_9`_sv5E51p#& zl~S|&vumH;F=)>x55M at r&T8T9uXen$!*7VOIAGq#r-Lga+(92bwJPWCZuUj9{@FjJ zZ2a(yZO at 4RUfSu2v-&ShwVQ^9p1536^wARoKHJvm?eBKK8gqPy^2Ywo%ST_=2~ThC zvN3#9*9%{SJid1L_$9`_Wu^U9KPUBvYY#16ydWj3UtM&1(G=Z+tCwErl=Y{#^?l2( z8UH+UkMMit>8-9OYW&)vC27x>XDomX3)6Ry<0 zX?$wYRsHQv<()F;&Ro!NaAA7E6Zd5G{;|{I?4^B=H=U0td%}Jva5&gmYD>FOz3*g3DqOkKdAAKd*y&y_naZi)KnPqBTs z1^@l&+Gj&{o%nwH<$tfbMQAg$=tG_ at tC?e#af-!Yx%{%*M6xDIhE}6pHlvb zAueU`!gm{b&96y(AT#0Yvh4dFeEjH^f6qR7IwR;@{1tQEz0(*PpIR_ at eyidgbzsgQu^38$9*14-(gG`RwW8&R44YZF=gV?&S}L4mv&kSnjpu z&x)5*W}MnGqUR5v-Fxb at P5m|&Is+cr)c4Qf at 9F-2_Qvq7FCDz+y}5Ij{m?HfOFehL zc>I;Fvk$)!QTW2QVXtm5P5SuVlx6Sjdgp at j>yI_RDG|_fI at mu~boAUVTzI(-SL%*37Fm=Th%bEr5 zr-n~0uk4q6R=+;%`S>rox}3_Ocgj!4?he`eTCDxr7kB*S-Hm}qHoAIr(H)v&8+pnq zFSwC?VETn+$#cKh8J6|hna2^=MLWZea@)`dHsJ_ zvG|+MlH*@3ochSD?p=HJ9uy{=$&HQpyEth4yNhq7|1kT9Rgql|&PzA7QKOOGu{%Y38|A)M{fU4qa1HFgtI3SG*f}}Lk0*CGc zf|P)Ccb7S7=BNt31^iH_-^fGvGUbNf~!@5QNW!B=i+rX67EPQyj z1B`#{t-tFXIQik91fRZPYH!mKnre$Y^FK{~zfe<-guLeUiwb`Q)qV?s;(dN-_aiOzIN+jvE zcnonZPo47~MnOA6FzHe$eJE!S0Mgdz^)DAdOPve;NdqF#DN*W!KWU@$ zGJHM{^TS?%QT2d at yknArJy)Kl$A$ojNI4b`gRK at LHoJucWX-2Ey;z|u!ICDah?yZRDzJ zz7$JxszS5Z5`^QEheg{D at kGQv$w=UZhKt`6=@YY1N4=p-VI<&mH(OBP(aY;7<&^xP zy*fON(`nrA?WTC&pg{N%-`X*jCX`?O!L!Xge4B$wMb(tSk2&wkmHX>-WP6PCEKS~Q zmlrzN<&2M6U2w%&_Gw)>9(gui%X<2Sv${Z#t1m9g`QV+dOO4(oxBGmrU1_hTc(KDY zJY9Dw++`n3dw9Q&3V^jJ-y_E+xJz$3?qB2{=#z3u%KKR!y6?%eA-_7#F8c_X0EdMm zA*ap6BS-u2X1m)Tylhc#@>pLN+OxsFS8FOk=3r)7$!?<2ziIqpw!~t!+uXbZ?TTfb z&5{+}$gBcIKAEE0Wld!tk0hmIvjx})4y{^ptG-I{n at rWrtjBV-JDBoc)g)#68G~hH zc%MVvbcrO{))l2L#>PmiTkmRFq4M1l at AA;WnQ7II?K{-$tPr`ma=~AHI-o~mLwH4h zQIqa=_(w~<`iLT3{-iBKwC}72`m#<&4qVlD0%@)k=sp$;_Mf)k9;{wi#vG! z6ZX~E(0g7-uw#xe>iDJbs`#s}FD?r)xs8jH^k3e*RTg|bhi^B#ZCO6kGPnIAsDWb| zy~q^KH%2Z?NXXZb?lJHDaD>l#j=@_Enbpdsb!w= z`Tdo&!N8@|!zW$27+v0`94Pv8J(IlNin?cD|PZbxI3|z#eF?04(pC`tkE(- zyiLq_!iR@}(XS4qVuBUXqna6pA|uVSLV5{xgV*aW1x~zt9i%my5^7eW5hg-O5kcTO z9i9hYDbMJjD;q<%toY_wRO#=%RijM8T1!&pRDE@*x{5Mrx0Gv(uf+3~M-fz_wfHgX zVcwp!NPfkMf8oQ7o&vbrGl@=yX#(%gg5c{r zc30blW*=^|Gz~_>uphzPf6S`vAq4@(%AVBzx$CtiEM z>ZN;=VD6)&b+5)@{vrF$FrA#0uTF~hQn0@~xmzkZP1$$spa##q&fdxp zH%OVDn|F_mnM(eo!=Da{nw+pte6XQVc0>2V16_$ShL*&OJW~hxQMTir7l_K9RV`!P z>j^b}ggNP)XVgkTyRO$(zAv^&rV{pUU}7mSz=n`(#LrH_>rnv_!N?QqdN z113?+#H^4=39h7%x+$z$#xhMjScmwFWvZ7t#&=6TEGGYmYU7l%qIjT%>dgG1Q(?zt zflFnWJMi19TkmAevhyVDzC8(8ob~SV3t6OAD4f(bp z`JrSm`a@>%F2>87^ic0x_iJaDVxH9*@QJqQeKeYQd#f%$U4EMC!%us9QBxebh?nm+ zd7lQy$2-5s`N&fLO(XG+_FAwAkFH1vPD1IrBj080{%`_^5|QSjWy$XT at M8=vRz(UW zwJ)`Mo>zF&Avw|BJ?xnm=QHS(hxffXYZUtWP);U`EuprwM(GDW!fddN^jyQwy9{qJ zsO(gY17^R(Pnf>jYFW5*GahF^aI at KWUJkJCqVIyg=UI$Q&^F^X`8IO}J;yeyyQCXy zt{h6Di(`^`y#YNm*YM%`#(yaV`m&x$ zvv($IYjfyZV{E=Go+;rD6_$-kevifju~!1jq1W#xr>pGVumS|$BzaQj4WQ!!Kg)-F9}u)U0l_=}3Mn4$4B3%+Pnq(p%?N1&p;x6r{y at 9%PykBckMiud z_sJOX1o8wNHE82Y$t}YNTwaP_TX4Fj*gloI6NHYFw%%6nr$|tEiL;(YL3~o0L(lR1 zqpz<`wwsmx$_u5?)LVKVK z)GuG$b$GM3wf~}7BV;P<38{Uiwz*wd--+or-)M{B4;N4jU}l*1^G8HC%;K;KzKA-~ zJyo$GHkvkut`%6hxQd~zO(>(kke?(7J1NF(w!7Y3b|lr1Y5%Hoc&4iBnG2|0b!ezSJtV}|jLwEJz{#Y8NqZ8>)^BC&_? z=NszrHW|5`{3CR&RUrK)7b{yVIc|8qh9;uCa>2};r0d$ACT4S~4~xQVX}+A>yH>o> z_JYqFYq)?2_{N`(Qx?BWm`QohmY@^c;RZ*NxqZgEnE{HOoyI<`y at _d<1^3)%Q$Wog zGwmY{O0i!s_J02tqQ^QGb at M|ct()pGJ#Fug+avu=-&|ZId&!{~JLSLk{e_B!YJ-Wc zNVCRRVHe>3qLX_?X|Wi3V=isBXyUQM)Xe^OX`4-3e#iOaYO6 at Om&R>y8FUUeKD3K( zD{xirydm%(R>yD=V at 8Em^xzQ_598B?>sU8mrE>~vY`1)YGiI`uYqaoW^(9bXmQPEodz(`0n+SS?{Oig&$6O)uO**B6E99 z98o$`Mrrh0`=V2P&-OQp)*fl&y7=jtnZk|y ziIf1Lxq-*9#m_e>W z$1#3e&Zfs_#H2B{%QA%es?%iNP3skbQGBnoPCR+EE2!k{w=kHv20KK18oKdV*qii| z4H|9H2WEekHp9nxuFdDf++L`;_`rOi?t|H9CJ)=fY*dF7+-w}o at -0FE30EwuFbqJ4 zG_6-Dc%{wvf?qv*4SoxaQ1WE_gSXQ?1pcqLTk&2k(uYq?zSw=SB4z!i@$mA?5XYb% z^5#zSLvURq^6nzFk!81s($oY9_T4Q5k_j8Keeq1&Wcg1^_ zVDgh1dWe=VTH`>e6_W|vnEXJ|MqX9i(d$*sgssy2jQ(rMMLbKvInkZ+t{TmS&YVH{ zhVgsc%|AE0yFb%D>lldEY)s*1Y$`12fD2$epT$hkTF_x-n78U}wDjeCY@*a=XibC4 z=ER=bgx4eZ2tPhwA7hb*19dwNq5o7gJWyT%(_nTE%}3_;gXnj?_GPv8OT%H%^e0c} zqp>FjIu(z$H=lbJ)N-RFtC(KC;Wh{uzC0i|R zkfZA<_cGbtST5PvgTH&U5W at I!u))I6u%<#rE_chxZj{B-`NT$;$F7EsO at A8?3+EaM zt&qc_oWS0YAy&gjXDyd~I}7ekw!MP_o`IGq+9Z!etUP{-+^+A0p>Z8o%NKma8n%Vp z_I!TYZYcCX2Wjr=F0hI1_`onWO#@^GU>p&zv}lJ?$)Zu>2s4X^zvzh8oM#~`| zmX9XC9F3&7n$8;7`K(`*)M{SPgN5dj6O!l>kugv)3OT>L!2o?=abj2MzplToGlFwf z4K8Gkl2lVj8J)YrS2{}1)^%cB&A43KBmw`FOA^8nj?-X2tiV_a*Cc!YJwT3i#lp*) zOTy=?0HZ?dMI0J;bP~4f%9>rDZz{w!`dBPD8wYIjyj$P<@#AEmcN(7LKRS|kBP3ej zC at Tr8v%X8qyR6hgSTrP4`ATLvE>82&FmcUDGx0u z)P8&C{y8sbV1~e~d_2cGW--t_*hLc>>H>|Xw$|^wE$y|Dsc%0&PsRbegf9?qhna>W zTO6Q$)1C>Cr)4=dPRj*><$HrzdEo26nd+X!71V~kw>0GgMckoDR;;;sOlyNR zZ6^!4-)8nkMaDNy`~u7Ey6!jVpETs+h*yRR-MdE1Sa%(ZZ1)nI94{7+mz#p~a+8J~ z{EM$#h=7 at 4gV)H>tlH%AI?=b$=Fz3u(74)k5~Y?n2E2!P&QC)-p;2fIhH}(G_E>D)_mOiW?OMm at V3!piM@#xQ*n%*Dt z(VSCUhEb>=1!()ta-^A#(!St`izeky at 4R`rb0Y~eZys(Gu=hdUVxZbyA<5B0GmlGz zL|}sf2df;LQOg!0VZokW>a&*6rBGayL}S?<&BpwBq-$vl9+%&DvS2#DzRhru-)DYkdXKc3_Av=^>mlM5x;^q6=!mfERK!5*}CXV2Nf{9o$uS=JVFS62b;Z;$8G@{NQFFZ;SV(@Lf|CQk7d0PPjHJI-DFYf_K<1A at fO0 zJUkRntWV_T4ODdt0V4`s!R)(E*Izyo;HNA{;nC?0%!qeyML|G^AYEl zr&(Nr1=Y at 3aeXej?+)B9>D9Qt=DY8ea+TIo1IF%7vFqwF{XjM#>b3Vh4t4 zY3)61GY2vW6ZT3=06v^@_lr=A_DJ6OMz!uDo z)o5`>RP`jr1PIdnaD;hlk)A}pI8 at K5+7xgSZhU*qZ)EjOk at f)yyM>BGg z)xT5C<*wX(MPF>-3FQXu-hjY0PbY1_{6#N?A78TL6pZ()`nQ4?SLKIcpGE$6Y+p+Swu z9yi~Uy^!nvQXv(Nom_~_N1O=r?__QlQ`3gL*jIJZ2!V-O~vdHmU&6c-+ zEh~v~wNn*IRrS!-(%m4+622|2B9B|1#jO(1yhGN<`6AMLh5jcM1w9!Ln;*Nun=q-~ zwMdrsv<5$qYIyz%zmce3v|f?Ov at XWtR_E*$>kcx7J8ha at G24@}dAb&&o4RS2LVER$ zUiM`2e?;hiTbGqZ1Oy7%-MdJM$arjMLuT{y9a|DMPz1BPIhxrN_xsUa) zaI>xC=)mqNI(>ce1v_P0vh=RQaUbRNT)0{sLo0i3I^`fU+r7Mw6L~6BD4jp?enN7Y z!p6aa3%WNL$|Q7oE+)1_MX24PiU8 zY72%WOHtkS5G{UWVbH5OYGJF{d+d|mNhyw(_eGfw&_c2jEt9w;B3V;(KQ_r2YvCVa z at mx|ZTP)cf at A#3t_(6`dElTSFh1CaUXH=IRh0b9Wu7y|M0=dm(-`%p4$jhDzdGf7a zz?#A*n#gs{P;kUxS-nP0>!;+`jm)bxF_CWMg4^Wi!IFnv;>-`}H!m~ZzvT^$S(>fo zGpKv^QLjbx*4qgqdG&z0pC72EO-1SLUq;B`JmuYd=Num&%6eEq-V1Cc++LfU-aG| zR_;@%;ha1{>9d7e79XS=(Zbk-eGGHcGu|@nepa=k!uT>9VEoQ>BL2=o%hmu+{7v8H zO+jlwZXVu6-xayY^PbyGJK at UAHA#~##myZTCWp0nFU^@C*Qx$$@xQ_Nvr*S&c?!Vtf31D|1!B(xd7)FBwDc&O=4ZPGbD&^bt%d7 zw!v3Y#ZA4F-CN?B_Q9C+FT_n`hGNDl0tCy)XYN6T93L?m`g=w-K7RITM(^T`({g at 2 z?%stoYp=ton}c}aRwT;aQ;9>?aZua7jWl1fJF$}hX)kNH}*o1`va zVDA1Jaex?9d^%3w-N}j0(!`a{)Wpp0bX)|IyP1=@#UI!0ZQLzfP3*bsEgY at ft$(@x zK8z7Fqp{UNAqFmBy8$Fvm%(#qP`CjArw<^;!UfNbL7 at XV4>;YI7CR6WNsyO7cTDhH z7Zgg669G~zQSjUw6d{n|00avHo?C;$0&*Q_gArgyf}#NO4j3LCJl6u{0zihn3WjF~ z&)q at c2i>27;R(QVb5IyTE(2|Z|4>k5K;8huBjPgvg%;#Y-~yH=chCpu~cr0`egk9t}Ld2?`0Aej%7X19%QTc46~^?vKIr at xXIaP_BSn1lp*e z1cM?4@){T(tUzpiP^dvp1=E)X&wW7=0r>@(J}G!^iN6S?C6M>Q at EG8^ zHYntPBv=$uEI#nu6BGf^eH2We2t2n0g$d*;&_>jEI4E);e*nYdfagY_Tmm^8Oy3MV z4**3Rji`KW~3OP{4Y?nK^HNP*btNa^bXqHX^$vJQTd!R^wyl~$BPM~ms+ymN(_!2;Yf&Ak?=zl+w z{^tXK>;E#6{wE>n{{)i$*8_j+|L%X#|6wHkF9-hC|4k(QzmKH<^GN#N4*aeE-~NOC z4M$-Rg;BWo^@*nj7IgkU4(*H)_Z~fo<5BfiXr2mz`-}=9Wr2h|)^#2u-{&xa@ z>;L!vp#M*h^uHANTmRo7>3;^2{?8)me=G2}{vZ4Y{U1lt|61U0{oh8?|6C;fUqsUX zUf^&2{|OLdpa2vYC at 7>D5P${)g&2Z?0Z?I}pp#)hfr}U at lEfHj03`+r>IDpXfEELV zjsyb-pvFMKCdUW at B*Cl`W1xcJgTU}qi13sU3 at k)=Ofn1;M0jIj40J?zvEF*!Ziun3|MvOm zm+NnLQ=5Ns2ecY+ndK3Qzzvz-52|UiJ}LVk84O zHzenV^xRxHH)Q9A7#Ic~Bfh19ed;U^i2gQ zf{B8Sf{#LsLWx3$!i^${V*F?Nzta4b79tID&`^Me5;Rnxp#}{NXlOxm5j2vZL9~;D zvx&Qnsl5f=Kckcp!g39cq!obcwe^#c0NZ6WV7yY8Ix&h5l=+xy(MKDX78!Ub9`$?Ygl zKtetNdBX%x6%*OC`u^lTtx~N&c?kxmdoN-`Trh_Xuyb=i4Ai8J$ddy3{TWN{+%XSQ zry)0-<FuUBoa>{@iG#xAn_^^uOabUBwk124J6(~;`d0rg~T6__!AOu zBk>Lr?;`PMB;G^feI)*Z#9xv40ErKg_!|-*A at O%4K1SjnNDPo6^@q!2G4wbz#PvUc zHz at d{3V}JRk>1zGAvHE&f951H&HHLxHBSVG+#dn at U^6lq1=?S6YN7ZFkq6|X1mtpL zMXGB?ybh~!;ayl-1Rvo`JLY#XiC>_q^;~(0^|^U)d1CAcmt|uDk`&R*ySu4lIKaiv z#^eWw#Fm5l$I-jtYcVO${0BQnTi+!e0 at HhdNblA%AZ3pqH3)Ln8Iz~+5vQ_DLK1~R zj^7feTa~9P|2zh%u{g_b(B)<`>!+aq>@)xTMtHlTZ%U;q?sBOOD%U-*OfFP|xaLZ> zT={yVn|zQj7V=bqv3&xPISu-6iFlc}blgSp0S<{H2J=J2OcnTp!~x3QR10|L)xW4cQle^rW)1TSZ$!blY!yqsa&7pZ`_j~0Nq8--1AxqT|UafA<0Sr zUG0-9)g`zN;PyxT_5q35fAUiCWx_uh at CqRPliyz5wOIBeR_J&*>GD+i+G=9MRt)?m z9MZZEraz1Mfw5#eeskisOlqt9_c6|VYX5~timX#`NTnO-{zyEqeuaI`Tn7#*cSQKd zD3BEW{C#JYhB!15yuXQS9|j_E9zo|botNW~`|e==XERJCl?27sI>sTrcR_a>xlce% z?|2Et at BU%J+zEKu!Xd at i5%I%K>$vm1PEtXZIpaJiihQ`nB&4$iFwXFkQ=xZAOY%&f zfFx6cymblJa{isS$ zd+zEJUsm6nLPCdA#}kl}_OtZR{kyh|cqSn&TxTrVldfWr1eSLSj8ADpQ1We3-D=1< zq?Gim{6GY{$K`FXy(2;Y3sv8Mt;Bsvl8JwKiBtV%AlQGRD#7#zGB{SWm>b+>f4f7C z2izx|Cm^l*VE at 1{|B+a1|5!q764J8{0EZaQbWZr4^D6AM6ssgM3S7y*MWd^uZb;FB z?$<#7WjFFsVY`g9e&FvH_y~Q7ZZfVOQIbNPHUUX>I#XzFbm#Ba{@_3xpG$+;6Ob|q zFh9c&P1^VqD1r+nA>o4v{ds?Xu6gZR!XKRXWOO{ZU;>gD3>af$qy*pG)N!Wio`6JA zARysTcw z%4sTz?7R=P>-dq}1GShx2OlI!b*JtMq-cnI;1n#>&K{eD)cc4Zq6KsbOwX{qk9am5s90Sm^f}3B}R1;5 at vW>pH at Kg zvZ8?86eQySj87KcXqb`}c`1WLxgDQzad`RdMgh_852NdtYAHbv7-tVgBbgMQXx^{n zQ>`lEq4;u9FcK)Vng96?)L+rF`xE0zkg(pDDM-8s7 at xJ^^i?EgLSkklu58?*CHBu! zETTw$M*estgayfcwTNDBX2(rFI$Q3YABBQszTE1x<^iu_6Pm1hAR%LB(Q+sn16j6o z(bLK#;+tQ>aVG?GsjknPe5Yp&f0sc_T2<0ct45tKINwU4kL062e3a>pShct zh`DbOfZ?y6g>MSzFR|d5MCj+KySuKIu&IlYTx$qhegtegD7;&loZ#Y;YL at 7{Yr6bE z8wqZ%K~5SRQdk6*2b)QNxGW`A2)uuE$${muU-?38*)Dmdc>>bd1hV7FyVNXOJ#mx? zNF4uJ`>*YbFMkGqk21;6(&t0n3tViSgcORN-On~U$zH0aO~LB+FE_X2Q79j&m>PQ( z)yqf6izrcLQZn0&UlNbiPFH=XCnp1SUzrhQdJ79m>X)l4die3htGn+Xf5MwAGr&-+ z5$(NtDer-%e at GwhVJDkx7=aHw-qOF+-8)wmUkzO`-A}S^5?@?-OQ|%tsm1_&?u2K2 z;&(9PP&@Xlo}rR0F%#_8#taHOjIoqf>u*rZ7RH5E<=ly7o#%s*d&EW>&-yw3F^`yX}64 zN(Zr#0Jb!?mY3nZQg+TqG9?9-B`6q58jmz at n<`ZHt94w?--gN^Qw8;@*Gz6jONZZz z#^L18^tDF|iRxokmQ27V<{*B3;ttQ6I!R!tm8)*D4^u$1d17+lMNw at Xts2qI-KuxQ z_eQg~a`4_VJv0gkH+32qc8lwFPo5Zm1Z^~`m$+4`yT6gbTcT$9N+Hi@(IW=~=ivJL z;^61=gYxOD%Z6MoYL03zgi(IjepU=myixmX{bw7M4y1^4=AvSS|2yTF)jBHz{))#$ zpUo6%w+{n8uXkJxHmo%5KY65D{sxQSqM~8OJ3*=TDjj+0B#pXQd)|qIT1JJBYp=^> zgI11xEU*RmUxl at Zf3x_ik|(mdZQ+`GBaFFmx5H^1_VAWp{5>+~q at sMf;y{Y8ux?6n zH|fDz@{J(I>pgrLQXOH&SkFF=KQ#0tV&Cj at fhNXdmq6NJUqz!|&xf{hN|y%dL%2)z z%)He4so$X*s=4)r^Iq zd2!X=q%#0Fy`_&X1 zvMpM9rzWW}KJFek3NL+a{hv0Bgv8qj)`-`>rE!Rm?EZo65 z<-%Z_yU$%81U~6cUbq)x11szdU+1AyVraB^M)rxjU$JW0&ghYAZL{@|dc)l>%W5TJ ztc33-DlSW6BtG_G at K6a=HeWwFbg at gV&It?StX3$c#<3aEE_t3fK54^u+zQLW->Ta= zZW1f-TwG*(YNncKt1VL{>lRjJ>AL8iY^4x)OLWF$A%f%n7)BxU7k0%M>HyE9%$YTp zd6R`MBUD&nxqWbykpX(*imIRliG^&Ex$xs;BRRhZD&{xZE_1^k$bNNZxZ~4 at E^_g1 z=K>itZJdksB`e)a`kkVi9)9HtxpvAC1;kwmS_Q!yQoC1cW$Lg)H zs%vFE6+AL2T8_eggE at e74=!WyRt+^%wW8qd+@^lTkS#JnqHcv?fvdd>Wy^XhEd@~7 zaCzJJCN(gOIn at aHz!n at -y2q`+PhJC+hn;oO%}pGxZ`CS_sILt^yV3kwEqT_CGrB*O zA7v at 5n-g+LI#bk-tP1DnE+yfI%uG5N)o>Zhj1;nhAh|W(PtSNdl!9QzTazaaMoZJ} zz2!qHk_`}o at 9Cl>cC=6Wjf7V&=~^jahPTm at 6wB5!0uO^ z3=GT5Y3mZ&G at 5LRO0`4?Irh%+3eTWr*S6m!Q%W at _?agh;V*768j at J=dqm=i6td%&U zHV0l8)iUMTsS!6_rw=^o zf~iDObTS*0Se1WpW?wjXkfPLmgHgge=tZ*iakX;QV{-YtJXOOAJ0fv*#?h<(SsJjw zC0|ySA3ahJhKQc8xV)81PrUs+SEr)!QCOD)mZ7Uksn@*^-dNW#+xfSZ!%ICRJ0kJf zA4ZiY><0zSMlr0(mm3>*4SY<&3vC|JY1*uj&!>C5$aj5VWp!`pBQz8TTD at mao7cJ^ zk2e=QSMlznVtDKN^1+4YKY|Cg^OlSW9*N2E=zzZB(*x;F z4Z(J&nR4lvZF z7Vo}^d9~Tp!7r at RJW8J5eGN+cYqif`@B8B at e={nQ`$Z(CL}Dr=ru!Er{EO+4+ySKY z36b1Uk=&V(m>9`FK9V~Q5)&c$@3YJOOs_r$sUQOY8x&Rv6eR!LB5wG!Y-5n>x8U=Z zjMoi(r0 at htjEBrf@!=vfl7BQLcMK#ZLGn+86N$-@(lfUEGA*h{ zP27z5{=m`e3+I99QQd<>>Qhg at pZ2!oq89UuO+d2mgU_GsnH7L`{Z%p)IHZ>VtiQI! zNvg0s-KUJ#6`O)3<{0=yVEnd!$9IgxaGSq5?=dzpspmK(YZrX~c68mpfs|iyB$h;C z86>`qT>hPB_l==)1?zne>f0G}nz8)3a)aACAfV32X`SbAm_Od2R zU056B{4?H3B>B-jJ`O452HU6K(SmzgmO$AP4#|IZ#<)J2;ZYof-porF{?o-uq$BZtTlbVoU3?oY?D-NJB4+XRruSjo}Zc7cbQ zvjh$)83gqkvsSjxs4Ilc2~6+tS$cg7>XjG&U^@TUfQSBYNRq at EOFY3ZIbMQ8GStt) z8?7@$5AeVtQM70AFH3w1nFrs`+j-A;1&N(^yqZ at 6e#Zw`0p!&YAWNR{?nq<5ZRBtM zjKr%*@dfzBY8rv>#~D&*`SIE5 at ei#~mg#b~ULy&4-$kiBmO9lq0cmeS)ZcVn&VAQD z#iI#GUhP@^0CC=7Sk_?u5TAWtUGf{T|C4v-A5j}nOhD3l!1wKp_pn9S&Y0^DP+y8q zzn_dBSNRZkvra+c3C_N!NRd&&wS2G at yD%FB at OorBB9DYW)E*8(L+OQjCKKe`>aMvID4WrMLN{q*>6UP(&b~iJ&CL>}>t;dy3{!L0;UGX#fIA)~)7Apb=*GDcC+4>E~aqewxbr2^wVKLZJ+&)#+sZFefS at C0UQF zG(OMxLi3A8NncFUB&7M{+4r+>mVxZ}*OQQX_}TaM`21%|4+oMzke#s$Nn)2Nzsjgf3D<+TpeoWQn z2IMATNmp_{pfu*ePw|QA?;`Kuk_mhqt at j9DPLwav)Y)v6MXA_|pfwP4eRd9>I$av) zC)?OGX4p}M7l~F^4QzG~$;Pw7b5k^zu~#q8afp?bs}^$0Gd|?Mo!^t9{d4J>f@<@i zWYAse=k2_2suhaG7@?J`&81g)8n7%Z at qRp8YFEtnW;bYxOD=wSVjcbZGM!577SvL@ zx#Vi;ZXJ4JYL`sGmqPB~n?ZZ2jT_uCE=krjt;jyA2m3SE+5ZzlSf>pXQ$hVje4q2F z-f at NeRDAv3K_)qj%v`fXnilT%y1W zLB>t2I=;H*^=$-8y2G|phuK}*WX)m1=TjxUWZc6fn+B5^9jUz&ZHE&$BrO{3|HFBS zX^I at iBJ~fXN*t-Kufe1#US>_G6kp|4YHa2A`*eHNPOrr62K=p*YHgneeTS4m+-;)t zNG>TqwLnrgsAkZkN9iS;eWT%*6dy3S3oD_^lvzsH5l&?GDHL4!zTm#{eXuh#sp7*Z zhkVaRs-mxM627Pj#h3J_FGA~baxALojc-5crV;qGPO8?UtGmL8A4JsLGPQ``zo{Jd zwZz6|ANA{CQeoPQ92S*Ol*$}TmmG*g&D->4TUzBr{2>LxibxjD0NQJW9D0%=mo7O4 z^BHhzwB_Otzul59bl$P at BaKiou)o?&`E6aXv$b$Qt1ovksJHG*b1aQ=sv8e2VZ`N0J=wDRQ7vPW> z39x-28*g>UUp37-8!5z#JB{cYP at +D2?Q-SV{enzF>!2M*)yiy74Fo#^PfI1oRV((Z zB8r_X!IH_(1Y@;iH4DKOa*{U!pJQS_P~TC^Oih~h7qfO^c5R+yxRIuu(x=G&LhF(C zbM#2<*^%GhN7F9%$%idpgEkMsm>1La-(R7+Sx$m2qnh*R-c+os(+yIxJL=+g$qEIo zdWVr&s^V@){R#Pd at XkoSIkkw1Op>mkjg5`4`YYn=8Tan8%SL&)m+7)hX$fc?N(H>i zmJZup!!jhj^OWIvSLni>S1L6{wdQR%yelJJ{imy6Sj+dIK1@&Joj0bQJXx0 at _fX7^ zEy<-Rbmo_`gb0w%W+*=haSttrqx0e7X{tfiy;KUT5_#ZPSZHkWJujzztCCE3iles? zAx|9GF;~qFz#$1lXaE0tD!oYDb8!k1!+-WYI8>!;(pBQ7QVF`>$X at 2PPAJJMx3Eh= zvhlF8OBab^b at G8imAD5JkeDlH_ai~i%b$dn!RJ|@GhXUmJGNF1RF2PfXX4R!iwvkO z6%lxVFIBdBa97T~DAILqC8i==UbWSeceDuKnKD}Dc~f|{rA#skrz!F6h?+q8x1R3R zs|qD)qUCwDy9B=LVx{%byE1XolgGVwwD4yViFd!v5G#c6rrM);t;oB(;4*5?TvRHV zdXXyj{l|^zw9j5n98_v;HN0HnuGGy2FF#@wW>UyUzZ!h^^8Tgz484;fyWB{H2(;7< z!q^1~8t;hcQsK)=6^(@tviVErJ(~2G+CH@^Bw#gq2N5ZZ7m@^{GPi8XM{4&=S=>^C zh55{;%r%C}giu;tdy|JcHe)gL?ehSYN-tl?mD%fD8Ve+QE+3^6p`l)zns&k0 at pMZ? zIX>}COLh9);pdsN_a3TGi at e-Kt5R%Ape>~y;#BMV^vAdBzB1LVbPO^{lGJh=Ru0*> z+f=i=-Yj!TY3=$OV714;kdUmrKl8+wIJD{mvGWo|SD#Eqo!pb*+c~efH*xrd^}+f- zIvcNYcVYqBIAbDp|8C?Eq4Gst_*!h<)uT$8X8$Mkj~JHP51As%oG2p{D;D14ZzuF_ zXi%h^U&ro~PWUnH8Lmla?#L}ElQj!hh+HpXN at jlWz2^Jm4Eb)XY%D*TcBWUsWKbrN zW0 at 2iEaNbGe~D?H!*q^%V!?7>wb%Z#HvN6uU3b#bvVp)Q#Yl`W#;wPQ&t$TjNDm^i;#v%G^fF7nFdNGWJX;_=Dn;hD3~hjTN5Bnq9<>-RSOkz zn`e5df81=Fy*2Umvs8sg1WSIyr1_8*lbEZU9juY~)(lC4;v~dBIQ|`9zjA|A?0o(} zBl;8PR$m4}U)AUWs@`h(OxE#3lKFHrGQ~)>?^1 at msiK5Y#6VPp7__=e;Y%~5u@)nG z>-(o3DVabu$%po`WScTbzdwdrwf#+4>YHmnCat#H)8AZ$iY%c)6P%ay?golxKXT)XjOv|$^jyaV z1nQ~LmcI{Y6)eptHGNtkK at l&fSTfmibqz<8PV)G?HWb6@?{Nz*q7$jEkn9C%yZtI2 zCtIKPb at ax9YH_~tAsb!I!QM(!AAN_Ld|U^g(XiZB4EK{A)rX6#N=cd(cEOuI`nW6C+izN3Nk)LcyTVV<#78HdD0 zfc?+-OYajL5C-(JCL at D+MkTiz~L$KR+BHx~)e*eQk%nM_oFy&dusLeOs(D zmOi=S!*%H(zQB8v`~#n=OeA;o$R(7 at wY>C;@AZY$5DR78Pm5H}QFYvmO}qIL(diMd zm@!}}oOLd1gzj|c;3nz(zonwy-) zBj;*!euh~8)Wg;79|8a!3v)+{KQ3r_oRO-NR)c4!%^T0I(;;1d{rr5tD5UGh&(5x6Bl{mdyN-g2hK_-W zg^h!YhfhFAL<}Jzy+B4zK}khTLwoVkWjgvR42)Nqm|0la*spPLa&hzU^6_665EK#? z5f!^3E+Gk(l9rK`lUGnwQdUt_gQ;uW)YQ7At)r`_f7`&&=#H_8shPQjrIodft)0Dt zqm#3XtDC!rrnub=_nQP0h2br02k^=XX5N^Z*#VL51q9MVnJ|o z#1hGLChmx>Ku%XsKHaVavEZ>Z-LHJu+nAni67tXZYkMC~+~135yPKGuEs^|3?96U- zZXV93%Uru7#^xe6b8v8SMXcd$dAeT>=!f%H9ufKDBf#aLgZ|Ej2N<`irlQK(;PTT& zyib?)HgR(UZw>Z7bmkt2Js#*B!KggXW(0z9pKk(l8a?jma>X`|=7=mI7GtL~^{_(h zMRB?o^dEWUq*HW9ENATC|I&u{@Ix6G at mBFGv(;!?&^V9+8r at A|I|^&-d@$j=B(_9a`Pg}jaVAl!qLgY%9_s2 z*#xms5$N6C2~75{3j4FZc#!JL=J$?8r;T at 0>#V-rt-(w?Iht8;{`d9qXFA-7bP%zf z?HKYa5%cr>^9mu{Jsc4mQ6Xi++QP*7EGC3M!T&`$y=Nh{eCTz{)yZ0~}Grf8ys6{=3|#3tJ=F z+X-ZI3r`y}i{BcE at PA%U7T(UF{(wCPQ9H<*its0hmj~fr=->J``Lz|=JRLeVyoWanE;}5~2I`dk8oJ9;d(UXa7lIarCgaXZ_t?n20|V#JmhNOaK#= z7+qFY76Wly=LSwU&|{$!QrE at 81_Zgeb=0xIA4)pJ3`PLk*xDF80KnVX8$7TP)5x#@ z?9&_ at p8%_KcW2p`=I+5 z!}5>$SGRvP3jZ==>2DMIKQVv%2>QdI{Fmm>@WFo=)c?}_3QPBYy88bwIR3Rwt^dF7 z0Vu!Ce|!AZ15kb&)c?}_?g9V1=0BAmVGuLu{-i(M{_7&2m-}!2Z_E3;+{jmcjZir| z0)v7>Lc_u%BBP>XV&mcy5|ffsQq$5iGVf-Va at 3%gD{ItEZ`+0Bw%h!X$Z%5ycPk#LT-+n>+_b*`o)eGAH>GJ=dPXGV)7vz8M z{(nXNdw}m07Umpo?uhp!;B4P|Lc4GyU#h-9bqLL)qM%~eKGeNn%2}_FA{DIMOvDs z;B3bnj!e<_cGWulGpxUSHhSX?`g_;4Q*H>=Hq at FQz}7W2t|A-G>r&Ahtb42Ut%APg zk@}We>-}$`##NU4iW@@KGc+es#|NueD{HOID%1mcYhGI)eE`_JHWaLHuA8#5zR`+@ zwYR=5ZOWQZW9Wv~P=k|U$GtVux~jEyT~xQr>5G;#>K=-;#_6?@S}R~ed_e8$+CIIJ z%vwGZ{H<;Zh9ZqIIvctbwT)4o`UvA?k@$sx^!o++|>&Ln`G_77jriS`8cyn}p z?UTOU)Cs7Y8frY$9Gb#j<%ar(di%w!jZKlYp;ahT8rQ*_uQ&et+?O|9Pq`)0-RM|{ zMm5E;h5Cq9daMZ)eXls%y1v_v-q6|>TD`ofHR9N%<6gg_t|ipSn!Ua;*1fj1nVv?f zD8cHFgZ z#_HE$t?I?m>&^T293AVeU%osPt>- at X#yFhgQ?{ zEfMO;`jNcd)Q)>I16^%6`Wo68_tos`SJpdk1asVVyoniZ9Ct;ePNEHBE+;2e1J^c0 z?>PC6F{LmL4|xyej)0?={i;_5<-{MqgT4 zY3WO%`W#F58@;@8p{183`1d8;Pe};hd&0RNu=Ji2@%cG$B0m3nPsHbcXH>Vhxm!-e z=f6Fw+wp~?x}APaRKLUMdyMRhyhAJiR=>UMd$qPkr_ol)Jc?=4Z?wvUdeZr4vZs at v^d6V>g{ zlPaV7B1gOs; zZ!`MRGP}O&jDD4|&m{@>D--S)8a)u0A6LIl`FsiG_4dZs=Y)j%O-~=4KGggEr1X?2 zNuH#1uQz3^p0pZ-ljm!GN zRn<1Pl&#QDUHna9>!rrFyX|I2Cv%Cpc2#I*Q=1)9UnM=z)4=5R_S at QTYNw!{+uCot zxjlQxkXf^4-FoY-L#V65c7J<^q{yTTO8kr4WvD)M_4_-tnkKb(v=d5d>T2rh>QYjM zwuQrM!{NB+t>yFQ&6zjBP6s~!>c9jE%=Jt4!it68eg4GDxBX^s*|%>jdFW%$eeaf3 z{4{-FS#xB?GW*r7Q<~Q_E^DY?zD!SYYHg`+XkNCWX*Fx5;4<^J?kSf|EoA-=zQ1^C zIJjKi+2zVkk?bH67%JJt$&y{<4ZHHvBroWdyg-KJ6_1d-JF>g8x^T}*maM=?$tup0 ztk;Ky^Di7Gxy6 at DuB#Zk7}1m7oz|5S9$J&^XI!`)+r=LvQAu z73LbkEQ*HNruVbcC`Y=MBQ8hzmkmGv;+8y_5X_aa#iL}@d6}=L^``VBcPDkZO at 7sM zTm|V;5X_Q-K&BKFd!^uxyxvhgru<{mWo*kZ85>NKv4K?LNs+Nd`8~PaIbHb|50iY_ zGr#ye$#)eWv;M4mTB^XyN;{h}nvbA3`W!`>Qo^Cda$GMsi9 zMtLYxg!HXCOOdo{>TE))WVt5Gu%6WJp09Abt-LyIo?kpn#7~YnZ94cG@>T-z`I37x&r7grSlZEW$3QQy){s at mu56!AvJi zj%}0T=wl>W7nYuHmt7pYTOPGL{UVIr9<)V3?F(K_dko~}*tdgf|G{+ZKTR?s^qEVC z%lW|^_xXWr_xZ(H?(<#g?mi1M^%t$*%c$QH>bEGae%rNdZ()m0xufNuNZ+RY6759W z(Uq!Y9dDI2e;V-w)7 at hO!`x$w)7)bTauZ8~iHPGZt=%8}}p)aoIHuJj~H$L7-` zDJDJABK^2=&_Sy`GpT3p at S`zARFNtc&#@!T%`w zu`5e5dWZK6>rU+&8cwd!HgUquy;~2561gKWoq{1!uspA8R5+(5JI4Qnds&(xyBz-` zTry&2432ck$bt04wn?n_guY^77U=be_i_51+EJ=YQkOe+I6~5PV~0-NTejuJwlc7- z5t6+d+tRf4UWQ9DmYcl9>M`SZU;WZw7%yY%cJ2KlHzE6-GFx*~26NL0<|cS`%-rO} zlb<5_EoqWZTji5ResxZl6W`Vc7~ha1PJB+8^YP!3L6{NDVZ#ZRF8Oz0cZ011tT{GI zvhRrR5mvcc%ot$V^KczcuxG|8#=o)EX0DtveAc-wqhw4lhrX39Bg;oTl{gpIX#U2e z$(R8CigRSlQ at K4k-6OknjvTZfICYSdA~~d;L)tm?znn;>RR>z?aX)13g`6;TPzhfa zqnkJi^?SgyWnt8woVIgpVVFyXEjR0tYkD;_h4Ho9h-y=}qoYiy3fiRXa#e*0HxcxhpB`sp%WzUO&uO at +`cniw1Gp9g=cHFxGQ zcjhv8W?OToW7p^Oh+Kqdd_Vn-$S~vqWDapEM*DiYoAqF(nfLcezxg$8T%(^eA4bdKh|vQi}LjuE}qtkabo9#WGOZG+6;)8~$fgq$*~-#|KL8zx!R_G-r-e?~I? zWHJ6Q4(*N^>$F}?nVdLJyvk;)SLDX{dhF-#0{l!t?o9NTFc=-fZR+Q(iq at 1d^0jU9DH z*UaG|F?C_t#8As7ocbs_Bl54vk7MhNF(Ch3U0-;`8|j-1G`v-h?NoxMZ~xNA3{GT|P3LRg>xW77l77 zUH#hHntw-VpN!w*PQ=}Ht|YFYwJmydUt_Ih=dzZaIpA7WGi~oHM-RBK)V-3ONAiYE zdwl7M-Ww>dgYIi$`pH<rDG?^#Bgzu$N?P#y-ek-^*t*?ZY}8cv?rKi@%~eCgr~ zW{NN16(9ERixl*Z?#b&O)s-E#$7X~wLn`V^R4fF1ZD%9>`t> ztNXwJb3xqLNBK!FKNu~4G`-ySyW~=&arq!)j1_)_-It2v`;vyZ>{6F}6#1kH-$PuV zD{;x!ocLHf4V~!;>l)iGH?|gx+FEp9R0rm;nH=I36%>Km5clTVE+%=E&{EC>d z=dJeP1Fw(#nOa81Z!h)C9y}WVx97X$V!unqIq|>sGlB#=Nbj2~s^jgTX at N@~LOx*P zeLwsuV_1AN*NH;#wxbpWQ}FX(RuD zZ4`FDMIF3d-1_{LxbulStJm8zqC34SEu31D5*v5o7^*g4m2WutN|)Sfdq3jT#r*Xy zX+iFaueZYdX}X{Nm}jhOrDvdW_{PN8nC at ZOSC1(kE at P^5dvki?(@43Mc>~!Uo5o=K ztpWEX31g&Vd!y21RA7XR!hKXVHDX5azP2CudCqkk>8qb{$&a1<4Ap0&ciH*cZQ9}S zL7saIydN)on>Fy@&$klSJ%h~?iEBVBotX7ykzMOf8QouS$q$g<#`f#PId(Aa?8OrH z6qjzHe<2cdTbOwNQ at DL*i_I-G_Y?j7jC)TSe^18vdq;CwLZ5Krti8)6oyfRgLV07u zN1vOdGbb=FFdjP3O*D?LeHk0QoB1giW2aXCVQ#<Ah(^(cQY~OPw*}RjRRzXx!VG+mL$VR_s@APLB{au8)2LEN>cF7|qO#bxYa&B;poEsP|=N9M7xyyah5*!+nxB_Z%K3>%%uKUGe5=HK7IK6&TH|Kmkh?y5t4gJRwVjV!GtS` zhGUJ5pSX4QU~OmieErsK&fd~`-s+WtK>ueq(Xf^cWne=iup!nGjJK?{<3EQn?U_H) zwqI+G(EPrY{W)_ at zWE%kIytQ2CW-Tz*J$?d`Rvt3MfdO9^xilv#~8`LJ$6po=7b9j z63+T;GGB({o*d&o=)5z?Sl+LU);yHKJj7fS>Dx)X<@58wo^ixJH at Dg>E&9xS(79#6 z&x-~~GcheIe*N5TnDx0`zqDihCax>mK$8%`Y#w4QsL_15hp-SQZc6-wBv5Bix*{QBtMbKLSQa$zWT zKEsCS`_}gk?x3tA?KP71S#Ipu8~rTUwkaph7xLWV&38*#e4hF}%PPgsRmf7upN>yJL8&GzVLr{Rp6K3o0v z1h at 1c&9V83m}e~HKkbgbXM)2fx at 8*jsN>h`*5`nQ@%=l#eg<^Qr_bJN?_=!UUzl*K?ZrpnQp}B5(4!JP4?Qc%NetXB5HXL{!?v2jFng<={ z$U`3C@~X3Yvbw#|^!?RtS%Z|tra!B%1H#I18upWDQ#9;sul z>WuOCO?AUxWsF<(G>`RgU|USsFm6i-+i_u^+iu)STir6)RXWY~`;)0QK5Oup!9sKY z9E0fw&zSprr}m|#*Y`}?J1>lP-)Q`;HyAb;G#D^gVX(;HmlEQic(JV)8>}!GFj!+S zV(>PDUoiL$gWogw6N4`peBEI3WE)2toNREW!9 at le4c5KSxEri6m}lafX!KDA#b9r- zjYkX~H2AQ=?FMf*xZdD(2A3MV(qOT{2?o;)_FiJ+GX}qJaJ#|v27?Bx4JMoXpT5Y( z;|8BG_=Led26q}PGUfY%(K`&b8LTl_ZLq at NRDUeZZvqe!A^tUH~5snXAK at Rc-mn4bd#RJ z83vacY&3YY!L0^64L)J8$KY{;Ck?tyxw8#UFj#D`)ZjdW%M7kGxZYrg!MhFaGWb1% zPZ;beitnd2)8h5rrl0IExPFT1U#5Sj8$4;;|7h at 8gFi92&)_!=ZZ-I6gIi4e4MtyT zu*zVG!N~^m3?>;oVZt9b*kiEU;P)rTm+N*@&h-ZGO(^#U at kg4%p-9WRg>|7&OPPMH zx?F$L7>aZE*RBec>9?!rmItaXDViE=Xb?H&S!jPte3t#*&_)xoqFxU)YKp8Q#7|vU zgj#0TH-ySsS|at!TU$cSxTbpM)`l0=ht|$tsrTgLCZsCd3D-BS!dHcqH#9YeDr*~q z`03Tu)I*?tbx59)il*iYf~Xc~in_n#x*{%5H^jtTCi9c7Zd at Ig@{f`lnp+|bA^qa} zc(?hsd|5CUu}%x?byqdj2FkA?bkvw5!BkxEZO|Yx z$2Hsf%D(yjJ$YNEz5}7vVU2xW?P_)Vh~wt3ZK*^5tEN7;DcIUzY8AH|)XyUOjk2 at a z%H*@;zqyr4wa&Vsr)sYJk@}`ceapJ?hFYzc`!$~O)<`7O7(H6;n=x)q*nACZD^3jZ zg+BYzaOB`GeYuLs`@fKn)lF;StSQfKq53s;cztQ at oJNfHoc`_$^%sU}MOV$Lo;NFM zvu9kfzgU=PwMNql{jpz$XKizsFfA*~WWAewS2V1e(-K-82(^*Ia$FjNeYNd(SBI=4 zdMe7LKw|;Vb^Al1>-+rdl#2T1u)dmLRo`fQd>(6CY5)4dvQ_SV9aN0AkW zl?~&^Y7 at J-xRgm*pKdY|J!!|Pt!x+Lazn$cw$KX3)G}FEIjhPs at +K*7y1KFN*f4zK zVkbAJ(SBdKNEvQ(V*E5UgiQE_?x+pwm|E5x9bI?0D?_zmYXFjaEne2p(6mCbT#lDO zQ(r)l%oulj?23-x&NvwJ+oPH5oRRKwkM<-T2!j6la7cdT_zvic&7Y&csPQtK)D!2z zkaZ>zYbAG8sCG at LpL?fef0hAgO4NUYH7=5msLR)_(o~1+@|;c_Cl`xMOIp|v3WX)v z6?>qh)nCi)9}HF1H_{R_>`}Wm($X5%!j;MYN(wlqeMQfqtYRjrv!V{pYFiNsYfdSk zHAkGMqvoKuyWMk|D?-a#SFH*~{7h5Y at 4n)xZfRI#AIf%hqrS79m4>=iH8ow|8g`Ct zqT2Lytj(KI?WTtcI+Njd^%T(nkI47jef>Hi-Ll5uLRMFH5>?jfBc>4c zoXLdnn5NbLhRhu##A5luz#-^23q98G=nqA#24L*5QYW9++19na4}OtIFq8i2T7?D_TcF+8tF+iw^Ym z2xi~V+3|>D$+nY}V_!@gY9TXQSFU8~B(ll28q*qOa#u`iF++u0TeJ}_zfnFwtns>iDfvo#=gHlZ{YjK%zfWj`+icw{ln(|&bb4J?=ts~4|2cL+}~F) z at csX&T{&0Ly}zFF#fwFLcCGKJm50ur?fQf#t{ojc?i4StyzS*4Ag^!dfAFWD|8xD% z^*`4;x!PW^$BPz&VS^0@>kI}B))-u3&~LEPV2Qy=1`7;&4W=7RF_>gf44!%3##07Q z80kzJRcwbE`!?*ZZ){cV28mrgLMXL3@$V1H&|kDlEKuZ z`0*?}+l-UHmbiIF=la<8NYvZIc09eW+3x;@fp^!y375a(9}DlRw98RrP(|l#XFT>8 z)Ok(k-XVy-Lo^xDGbD8W)pv}h7)&*oX6_A(xi`v$Rm?E)dW~Bql4V5Q#~Jtc8NJNt zJ+bN?1|e}jqVbBG?F ze7Di>G5OhU()*fm|BlJuznlBNH23p{+I8X7*+2L44tm-5eS=>A^sN0~xduOs)4o6W zVUhp2`F=02|L!)BaQzoI3E!1woOUN!!^d_8=$f0?-8|0R-|=f3 at 43&$o4(R>MzQq9 zb_;jn|FN$=`&Hi{@!#~Ojim-3dWZhY3_gtipWl1*-qG^ny~pnT at Zj;^c#p*vFrh4X z_9M^wBo zQ|LV!zyIHB^i0RU(Vh2;*BE`I(F>2pKQB1-yZGk|-M@=}{;U!=Kw};GrH3++ka#0J2!E46h{VU%a{Dirj@!d(&$l17z}wmUZh&tB7hlA at 310&K6xjto2!On;056Q)0mUtyTECM%%^9`GgvlVWCFYboO=oLF5D09K$gIFf?35PL3jzc zvxK~K=xZ;b*3HUKkznPGPWo!XI zSgxNLc%&4ZTcO{X_lO^?oke at WgW#8D>GKGWYz3d1rQbpK$RY6ev-O-Qj~oNbuF_`@ z9;pEDsiNNC+pDb41!ON=@sD$L4D#q_0Wx(S`GgmO+ZT{e^$%XE4?0{PDFHvQNF*IT z11wrh+rf*$VGL}=@N{qoG6UWTK60%{1-uJfP%9FE>jCuJkUF?x>vHl5Zv#JzY=Cb9 zUt6i)fFTd7L_SqVp5XhzJ at xv%0*{5eZe$#SE53mofuB+Q1o?+AX&1TTCfXey24BCK z^`P4$C%}$RV!QC-+Zm6M3b=ls{~@FbzHO7pFOUHIFgSFxe$&e%Dc}O64jur%g|xx< zfY*Lr&vc|L;AsZ=4)_^x@)rH%+hgH8WEb2I-h%9bZvelJ?1S$D|A6d=9|vcAQRE<8 z at pa^o<{$jRR?4V(27j_u2NsVU1m}Gjn}Pem&)kD;z&C+IzKX5FQ^50)z3 at rkETjuw z2{s at H;EJC at y5SqaPUJ9rFZiYH^eOmO at CV2-_ms9&5_lf?Z%8S8ANU#)fS&-*{|4;>p9Efu z1mQK{=a2^YW^nBNA}w$q_ywc`z6C6LfVO}agTFw!;m5$C-(=kjPXT8>NcM-2H*ixY z<12g%csmnuG2F*Qej2HQp8*%`qt4+=z~>$#UHB33Pd{MHgdYdf_S5e0bZ{cF4?YQ; zjqHb4g8%YE+8VwQd=>E~d!!fq)DzSjd?WaE#0TF6b|aJEiZ3ID>L1Md5p at X92H%I2 z!b`wqNF`ix9pZ zJP7_4*#tidUhxygB6ubE1hNf&0KE98j7{*#;5U#?Ef<(|5L?x>z&nvH_!jUD);CsMJ^-$ZP)DL(!k^X8mG`6=ojUI2a$nFQYqeitc(?*pf^SSx`SgUgUocA}CxI!?GWNj_gZa;4w<+WeoP&7bRp6~i z9=rp*8}Y&Sf`58W-(`z^g6AK>w&9b&Mx+!T1|LQ$)jzoEd29w=2fqFS{SH3)*CPKL z*$m$db|G8g={?MMzoDQ(X#KLY0V z(l_CG;0)v_T(JR3PxDwu>ZI_LtT=Rjvw%x z6qi)OCxe at i^>D?%q`G7y{1o_^G?#2wcW_O*OZLFqz`Y|}auBZgD4VV0 at GkIoBVFPh z&bS1Q$#F>`d;(aOOS#}1z^@~n at Lk|X@?3HNUIQLQ&S+RLB_A2#vGDTIF7d%j!5fhP zd=r>C#wE+(+2Gg$mjvNHunK8`D{ev7!xbM!Ho&{U7tf)L8unb5EJn7$YrqGPo$&qO zNn{WF6xiW&$v(JZ$~fv)^9J5B(Iq|bZQywqxa1Uk0=OMX$?#YhxY#9maK#@Yh42Gl zFH!<$(I*W^DO~YYBmnOPTc>aj-UiB4@((`*{)A2HR^?#pbeHT>KcKsa`h+KepG1zp zw}Fo!z3?t@=Or#ZyWYa%$Yi+UUB%=Fz7?!|AN2 at VJculVD@NW=e$)@Rw}f=zik+8H zcDUkoGh8wuld^!P(hrlsqv>ChrT#amlhrw5n zJ at D+AF8Ny(WrUvri`b|ihZlp7ve`ca?*e~^OwPiVz at hV9QVdVgvy_k-@X6qOqyp{- zn~^Gb3wS3IfNudS{n!;;@iAm0d_OpB0rd}02c??4!4=DqGa4uO{6g$@Bx57ECO{tG z8^CWM74Ti)Q%Dv35cm=jfFA=VUrn9E6?d(q&ecCSa}{+3uK=$@w!s^~JCL35&EVIN zPWVpnII4A}(l z26Jztz2M6}>5_j%w!t at ody$=R#g~vy_%SfMgL`m4SoA5zD|j(@8`7=ugZ_;!Ijnxb zhdzT{X;1`i9_*U>qBmh4IR)3DVg$Kav zkRZGP{LvlMGyDMfdt?Lr7?}URX?J)5xB%I#VZm>1#s=V>;9Z}moir`*1!Ot$P)M#@FAoPz85@#w8Iro zA=@<0FS;c8F6tki0-lfTgI9vTMh?O!ZKWR|C*X>H8ccevyj{0MmePSS<%0`L7g z^^k`jaMAsQhc5w#?II8GI`HxbXj8a+lQ at xp`UlrMNISyYz-67(4_xsLWHbB>ICVGm z051ere4FtQ9t3au4rR{A_Q1!H3iy8Tw at 4NIC^%*>X~7G?g~&2^0NjWK;XA<>AHja$ z$G{uEPrC4S at Q+>eH~4X|^)c#4-NAoDj==YUul|VnFJJcpE_wFH)Cv3uxaKF=%xKmd z;29(vu9)&O@(iy4e}$C5kAQbQNnOFWfrpW0aK+lE$R|7qo4R{^FC)9) z+rZF^j5F{$@b2F;?x{O?;Y-Zd at G9`b$FP4*7knB?DPVj6pZEiI2tNR>{UiB at w}DxI zVmyRrgSQ|R at D1RHj$<3}Qm__jg9pJ|k#=|o_#n~&?*yMjHfdVm8^?8xLcP6=t-VT} z!xd|gPPpQ8$ld~7KU06blm)K17CEeW1AmP4zz>2~zDBt;9&p|n$~BgL4et6oV>?{& z&qxXU1UTzWYzAHlK7j<_hrr31ZmEMSekjW=o8hJ4FOYrk!(c|XTe{(1a0MdgPoZP|g&#q-!fU|Mqe%;10PaHe!}o%d z3fyuKuINV&!xiW0xg^TL%g-l2=aOe|%|z0Gw}Ib9{P2C?E65UfFZk>vH)}xb9K7-( zx3s_m;M3FH(g8mN&c4JgJK>e!?Z{#HR`Bv-($)CECy`_7AAI2bZq|>qJ2>uAxA=Ul z55cb>h48k^-10I~3O at xl&2UQfnlxBVqV{@UKXl`Ul5ePCdeXU at g)C4}#x8 zHo^CTmzNS3yaW7V8FdKX3jP&2tnq+oCt)iac>EO7zZrK2z0M0 at - z!z;nF$aeUqd2abBatMA996H}EN5<*8&MoE0QFsN|f*c>`vGAA33HV_!yud9<<2 at EW zR!!dE`@vsT>vMGa7Z_RSmSyl3 at V)?X!FPgdt|kxgHt+zl3$8eHkz4k_Q^0E%Q at 8Nq zYuwU`^s0aGH^?dYQE<;Px1^uvv2f|Nv^9JgIOijj9UcIWBAelgCy}ji??>quh*zJ* zf%-0uQ*Mui`hEFMLqxgh&~?x_3ZB?_PmOEMz@!}r=p&( zT?bdxGqVrC6{qOg%j_TZ+-yAu`xNeqE0I#%^(<^X`?&J;yYyqqq&(4%hQ> z^{m^ia78`u^*CHn&t^TrzC%&ZQ(eaTU$F++1=llG^{mwGa78^U^aNZ{&-6USI$TlD z(_F$@S5eQM?1d|yL=Lis)N>>Ce8xi7X^MKz;(oZIo}HM)I!aN`IxK-J>Un_M;T9qr zb-e`Y`F(rfihADIF}R|hn^nc!p{VCyZDed$)U&J(z!mijs%*wsMLlOK2v^jzpfvRa}1ero at c<%?%vDG{#}U2`uug0NV|TIwp6T-_4GTb?eYFxqAwop=;xj!`aZjD zxa;>?_k#Mp)^1S!9~&SZmks^g^~#I+fYWi;?>SEz#Jyw?_sT)smki=whkM(%828dd zj+!6LwEr7(m8(zpJ>rohcb`7tQS2l}Z-0#bALD=X%U95SI?d`0Ezj3wx9dixN!POybaDr^3DhIiSCx}gnQN2oh0I}MEBTm zXCHo4^|KG}*zxFDl!x`d at _6?h3bEndsQ$1Y at -E z?xb&`hP%%zlJnqw-fXY_7n%43?r*+gxlgqI%fz^Fr%SIS*c%I`mz7Olx&YhM|7B%M zW89Zo|Gihnr{~Qf>nD9VJMQ!5kX*L at 54GO5!#j#_Cw&&T?v6 at GFO!mK?59hwD4osU z6}XhmTw~PpSJ0}>Dc6(YL|vTyu-0o{hyE? z27d-ik9IlL98s|UX-meZ7wr)S&srVA7N=jRob*jh2xnWqgQkoz<&5g_{rwduCL2%M zbsAHzwytH54`*BcSsP!mEj6|sZQU7OV$!oL|LmIYV~a`8>2)W~ z7%*6Rmd#(YVETs#NH24G)HeH-PfMdoP8^_o_GmCrdUMYF&D7qN1Jq~c($jC5p4D#3 zcI=32znlk8zD4;=U#~9nX3ktPfV~Wmp4H=RJIqlo=X?9xXa8_^kGE}pDI8^h{_sk_ zaAvZx`?~TSkH+`=H=}(aE?jhqi=FHe`78ayz02#rOgNYH{r;|0x+?9J;KyCNEnFxe zX^~dzS7FvS(_M3M^C7jY9-A!|l8DsH%J^lY|6e3c{wmpW%%f|_nDsJWYujkJ7 at OiklanFY| z8UKxNjlGq78e_x?qa|2 at OGDJJhO9SX>ny*0<&V#I{I^t-QaUN`xs>-7`MXu#oBD3D zCLh5zI+^;bldp;^$*zyHXB!h%+HT_bDsiM(n*sG>?+D`CC*?hDpY&+^EVODOM2%?q z!_>IefnEFYEmLdNrhUh*w^r_ktZ)AIUF|71`5$G6_K=K_R}w35I`DH7gy at TfSZkZXA&pCtE$J^(b zCMuoj8Y)Gk=eF|HF0-u~4qCQpTb^3zRO at db8+b4K=t=C>v4OYhN6XPyS^4bi9fR40 z_Q^S<=JZ?b<+WBXbYjywT7&Npcbp!%f>_npDl2Yf>#Tcy at kHLz7MrbluzUI{w8>VS zeI=TSZ)J%i#ycAc2Jiir6;YR8rY=XwpFH|o+GfiF8o-azE)n8fWtF*^ze_}a#pO?M zot|hVrhlBIO^=)Q8Qks?(}=OUx9kW0vP9eRyoa{+*FkK{sZ-nTbyldeEUeXPzu1xG ztw-dwgSE*!?ECh(J;@rkkH_@=8MV#Lq1DS9*7 at 32H#9b1KE5^5_<`mXb)nU@%~Mu8 z=ZH*M(X{#lwau%iu9-gGx4O2mer2fHIZWj8 at zbXkj{o5BG at oxqOQf~gI#uc&#&(Gv zj*!iv6|H&{qS0}Qgg(|vDj_{3aZP4Ne$Zd$ PFRQ4SGw+HeOAPrxkQ-<6 diff --git a/Lib/packaging/command/wininst-9.0.exe b/Lib/packaging/command/wininst-9.0.exe new file mode 100644 index 0000000000000000000000000000000000000000..dadb31d8938b9b147830382495eee2453c171648 GIT binary patch literal 196096 zc%1CLeS8zgwJ^N;uq}*0BFJEZ15PlF6VcR(AhD52W#bi2g3LO?vR$xEQlP3z6JqZI zZERy_<<`qsDZL at R?=cLA^j$}pZgSC&s~j8jbBF)Y%8>xvB3TPPnY)vP5uA> z{tx_h^zbuw82khL)VA at j2)aIItwZ>**F*R`W5<}u{}g~!kxhA)YSNr%cDLQn at Q?e} zdgKo1b23s}+cCyBRQIJbN)}gH%8+y7HAT4H$5bm>tKq$)N0{01H{Mk3HM&a~Uz+j< z at u)G9QSH+xf2ge;>op5GUL0RaRt-Y`jh{9NvM+tDQ|MaLP-p9L)c01AVR6{#_EeK) zivij;_6p?eDH04qMu;_N;Kk!@!@>lE$KzH6qw=Q2#>A*%>i9mbqY!e5QJrwJBIGK9 z86aefq9{-i;CU!~4S>Wb$4}u at bRu6V5^_!cAzGx-r&X$Qp}jr)U1~Kx?c`d7g%teP zD!7+}W`y^~^JdVz;pgBLfcQ*|)6uv9JIX0Sjv{0$S;a`fmKa8H98k~!??r+|m;%pb zh|pS(B3L{=y$2%7Ap$5-Myam6iF7w%*@aknAygjulE>rmY28ZJN`P at otU-B`um*dd zFdN~p`QAL0)>XMc16xl+{h9%l%7tQ!+2AI122ZuA<5_HMVSw%TF`WEc7{i1$N^C!2 zEe?r&ov_)yLhn8(NMg?+&?Va#C)J&C%EwCpv?WJ8ngc{Lb}0OvoVN=Rn~Pw2PTstn zVQOpbef&&FoW^;#AvStw3m`KFFr3_41rU&XkqWRb6(BO(HdZ87(rlyqM>JUTz>W;J*aSx at XOD(%4*DhXf>xs-1HymJWr#9LvGu at u% zdB~`1NB~Q>{k}miThB1)w>1Ds}u!Qmee#;r#JuI>lgiZyE`R~J7g(9*qX z#|q5~e~%D-?L{E%#-9>lA8FYQnP3Ry<7nCNA`>V}>z3G^gxw!mLJTAb;VTy*j=W>j!Zygr!QTpdPzKLjz=l%fg<*RsmpU+QNs5^ zfVeO2C+UH0Nz5wr))2Y0V at 3&W`5Qn#a&py2XqH)y{VX9{VUys9&uurX&u-#OjsSOqe4PXo*Z^#i at n@7FHJi6w)RKY=W@ z3ZJK!$B$?jaiRZK9P}?BKmtri>n^A&WqLh6gS_yYz&J4VkP&$R;A^Gy=U)V%TFI%G zmf%x89nd at -(8kmO-HAQDY#)Fy9`ftm at Fv{n-3R3=S-I*=G~3&SuS at b4EQiSQ8BlC3 zjNt8F9- at Ka^8oAxETB5TwsD6yLu|DNBrgC`&gLJEmoH>}MoE#ywlUy7W%0**MoJmk zUIy5s=(^V_Ue9d&FG%vPrJ45Jn#iOIT at vV|(xP6TwGO34mntn5f4m#Y at iCqN>j#!s zvi7MoHQ_tRfAej$)*dXlJc&)@r$`>|I+CYAn?jx!fmR;d7>Kr4 at ktVPO2RHl=#+%r zlCW12_9$7qA1-C=eJwY0-gBPGtph~EZpap3JGlV63$ER8?S!j~Lv)Z{-q#^hb%I=Z zK<^A-$Bi`CUe4R|3^YaqGv}|dNA{{!8948L$Q5~puzQIiP_^e_Z|={qFJ?gERL~2iPSCCuDXHG59or zs(lYbo@~go3`9g^3eee@{y`E1=tvLQj|m0!W+Zh1-&KSRTk(f?Le<0#1sLvm{FKLAEx7B z9p1cAPqKyZf|-w#5bd<0^? zUo9GhJ$HGZa+(CN(GB&s->;EZtwr*WOpreZiIGS3wWwFF#$j^SJBWAC+|GKt at kwGw z;c>tE7=y>%>SGih{p#ZgJo4(}Fg&hPA7$mNZA at Z^?0+)(pQZX`%;fK)52Gf(NFSnn zYmqR*f2T+o=J_H)<{$U2hTMR5wAOx|U*;{RNL9tW4t#ilim0j>P}rCL0lvC~n&{1F!2%&Tv3z%DpJEW zV)9?24?rIo9_(+K{1<72Z1TT}5kZsx1dSLn`TI~&6b$xDCjU$DSUBC}e-ZAL9yvIw z0oA*<7FF;09?hyS_=MN}sMKjK+tTfmH9X4p}+-HXQ#uVQ?r_!z3i1 zgDG1zM}WEk_9f08Vx#Dik$<%T3o*k0{W59k53ER&>o);5qtza_{1y{exLRlE`aFG1 zW*_LcO4Ud$(yMCJE&rPh&|{;ukxZX9yhTCnz!BK6ANql~Vz%GQ`)iX7n(g-3&fCV^ zPPZhCO7msQZCV)ZZZvb+z=H62(a_?Mq*-WrktOS3{P{knjOrVuy#nHcELj_m9;WX; z=%JS#=H-lh2GlhI>QK~voSz?Ws$h^mpn4iSMzJ at uY9Mzc%iD}}eCeBUI;MHiMo@$i z-^WV~W!ygQ9rEM|=M`*5<;hhP$x1N!?p8c92z9fHBrnNuh~@UfzJ z`k={uY;~=VGW*w;x z_|q@~tN_8Q${MqGQ7uq04!5L at Dw;Tp(*bYmsh3}>ijVpBVf`dzJ)rZNfi6Zhw-*uT zWae8)Z3FaZx#|Zghx^lb=N~KQtIPR$<))6mA{XW_K;_irCvoq`WQCvA9P_=TXO58;)Ofm_u89@(@QOYKLYZ}1J5|^!md6wZz#bpHx&@L(Rfb9e| z`;p=!&tod#GJQ;-e0rsB at L``G*e`1(DOO$U5EY{jiNwcMy3D-!QsbiEukH(Xp#W(RY9zOgc&`>@f z1LB7Nh_mYvQ`c!Mw!&aP#!n+>tscGgq?Co&TAh00>a;oyw(6;REt}V%Bxn7| zV8|e7cF+_hYcq$Y9nXUa0I|Sc`)es|RD3|m;sH+(tUYlJCA|`8cf`z4 zlXgT=x(h)1%VcA!S!+W6>^9MclVv=IeqoQq?hmnTs6v6M at ox(qj3jh{tqV9Z+tK)C z(fC!eR-*}pOEnU^Tgl?+OtS}U*;n$uhK355#dZ5&)&i)F=sxgxvmxFatwkelLbxiz z{s8-;cepk=6#^@PCHN*;hIHp(6wgrJ-ary;0gRK-X?=q%PjD+{XV!=x%|ts2n< zAAZhyd%XM9SMg{zn%A@~fFHVP{R!NK zuXzzE`A`*ApkS<|X(%p5=*jU=wW(9dGN{0LPzeW`Bnn)i3;5dQ_i)~SQD3E}apeVv zHDu7ETAo4<1xA^$J4p%ub(qT=>S+{$f)pizF6#VRBhPUmukTEV%SsRWEPQ(C*Y#j~ zs-`j2~+62s20*OX4=(*UPp9IcwR#ffW41*EW<3q4EdMP-_VKziMlT8dqGVq zUIQgsAb at GmqK;y at 6Tq&Vo7;2coUZQ$6;f=@(`#GPyBEV-uV92%gO1S=ht{CNh5BK|zf44fS++*RboyzCjs04D!s!05|Iu>Y3f;NZUu+S39Z1@dP(P)4=uV}K8Tg6@?9RWC758faC at o3HGIf#IeUqD6SBKxorJH%&FL z+|(;F5j_^8(LN9yUZSBH-jvGnz|Q1v0!5pj=3~k^@Au*D797bwU3_F$DW~J3 zn&RD=f;SomWj at WP0Le1MT`xz+fBL z at k2zobG6Ze3mBIIEAuRYCp5|BjJ9Uu%(c8F(41#U`nwViF^8V?$JZ_}-5Mm9Ci}#w zN31N*!cp>y at 93&7?^CG|DFgOi1niv<){9|+_R#+GURQ~Qg8}nX%?xMmW#O^lKmoii`@L*2v z9<3`?6$cAP)uMo_tJ3Y$g9v-A97^$U%A59Heu)@O6LNfJw|93PIzLm4510diPt26S=Ztsh0 zOOs?tMJ*mzjW``foT|ND6G-iac`&7?nkf>-Bof|jDppU>ij^h10e4gxmsnst$&b at z zX9tj2{$5>bIr!vVNwfAmG0~tL)y$v`>Pv0VYsG7khyGg)@?e7|wdD+0rnVlK{b6q1 zm-I=$!s6_ at U-e0UzNtq!?)mcg!xM=IZ#nW{PCfQ{XPg1s9#_|c;?>rzj(Y*<+7GV$ zeP=C$s}eiu{4OtLQ>-CCU>!vuHx&U&p5LN#wZcPwy&qLfN!V%f?**WC8c&r^Kbw3< zWzf{|GkCWtMayt$(d7R&&UMT7LKnfyI at Hg|Ejy{A-v9y5Q66;(VicMqwR9?{Z9O|W zsbpN4wi~U#OM#Z%6U(nMfc^BR-B at 7i%0SER&t4W#X at E<>I8dlIi4xg6SdV;gpIhaA zEtny=rnj0ZzlF40&w{!cV0Y7H{5D)-^J%$2%P#qA at 5i^O at UuDZUMNQX=hboNsQfVX zONcGI7=9XZ8+9-P1D*DA_3_ryS4fka9>kSc7@}w8t1u<3i8!f7VN>iOekSlxQl;>y z5?LjvaFbm1E~?~Mv_}=`)zwrD_o$*7ZQ*>eOw=(NIjFJINHa1683Taa^wh9 zhfy=1yi}{R_4IlR8YY%y52%ZuvT~8yK{XQ=N?gaFE|U`PPAb!0j4Q!OJ%in^D#AWY z4x&vp!fBz0|OvLo%06q3cqo z&DBaK_t1- at cA373aJ!HK024RW6zT zwfzv|am$M)qP$%c=w^=Q2m3=daa5+d<;68HP|E5-%(Yc>vg50C_}F?jO6-9EdsJO` zMjfTvLtQ6lI1m{yxN#{I*I3lPSx%O8p-bbEBJ_i$Y*Mm1sq^8ix?L>Gueu`IsC)V- zSwh{tXAwB7nZ`jb61b2QrjI$0b1!O=EY`0+noKf$=?pKo%5W&OpkouQo0kWm)CY?qurykXdMeG>Y&p8@@EDbTw)>K&!d7vCDB5Gho>$+&3laro+Brc0J#@*hAaLSH)Ld}Xf& ztb;d5FCBf^DWlIgG5R724>Z43+z at 5N4Kao~czjwPOM(e(Lhi`041A^*Z1^{Ck{ois4DwY>@BqLJecJwV+wq z`-Ev=BjiDfC;W3X%<|=_EOi2RL0Y;eJdb)Gb_dvfUR)C5Sf%nem*6IBZmZUNdYZwK;)^m%VCao}!6^nrBA!e%PEe0g3Aw8}g9 z2sIbhQ8Axx>L}OZI{mIt8jcm5o>XW^7{Wmw>$1lh%=hW?}_hNLG|AIBH|$le)(7>#n0X=Jm|aW zFxo`{VIN&35lkvps8 at yOpxdbK1N5k=^Ky at T$|`b%x20B7jMc~+lXcAW$WP*e z0Cd+A3fmbz!lVG_Q{bXh;M_QHnZoV~Kbs0{rohGoFn>Ck5?hBUA90Cday;^?tBMk- zQT_G+yGo4e_y-ksZ-hxHy6?QiP9%6T! zx^M>;5!#e3236ny?rDH~WG2+6)=yduocz1LKsK>uFSdujSrPW48%@~bZCjTz+gl=8 z@#vb=XtU4ZEn8Qr?mmiZ0P^A}uJbq4gYIuq{c6D?s`;A|ig!L$ylYYw?=#f>d6BLj z;9e3x-E#*sX_svvq6g!@1O{DHby}GY1#uzILp8-$A~3?;@x{A0VZ`EEUh-WMItksg zhjQ`zv<_TDL?@eg(J1zO9b|}dFLXbU)w}J{l$GS2oKoed8y|R`!geVFsKh&!d%c?{ z1Nn6F-G8B5J)!+V=j7S}{KoATWQ!ied>0AO2D4r2Y`(V;33P5^oyMG4=l_Qn`MV!Y z?o-+SXkwp=ZLEm4o@%BK+W*8aFA`$>{YAnkUxZt77UPzjuh{!|t8Ji2Fi`!^^lVTv z(2W2%>B02&;B_kZ$q4QM=%YIT;`9p7?rkDu{ewh;C&GKak=RwcOwnrI22_*ie>d^tOHdGnN`a zHBR^}&w4j~J-$5$Uc!Gv$I%u;`}MnFtnm5m*U_jkb)22-Axt%F!oR^ROEAV=4H|N_ z3L||PnJ<)vh7{FE&&J^a;9Im1jKFn)SEw(sH+2QFt$RMit>teb*FLowcoJY$XD33+ zFMbX+V6%}kOJsxXe$KO!MhUZ;0CmmC73Qh z^GB3V)DVRJ#8q2wVI0DH`Bn#RW~6=`bcE22e${fC`fQfJXkZ zU1*;3OTE!YfbDT}Qr)Za-g|IT$Ue*%KoG$UUWn`FEuBghu1k_7`E-S`3pXZ8b$dhX zo{W446JmFMi?Rj?4Vu!@2~nHq+U1^NtAnPDPNaNWO}X8nrbH)F9#d1A?!go{2&oYJ z>SAi(@U-H7x^R3H^h=4ofNQQHwkH=ctQ(T*hNZf5A@&UY3NULCQU&FVI_l>>t$F7m%$Wa{r`A7ZBBFM)h%hq)BkTjYOHVaw#}RHG8?@;o)>p2$F98dk;UL#FbH zOnf$|&WLU9`WtjE>QR+XUQ`tB1zen#OFuzDppH#-*TVCQ7R0yZt4c{idS=Ae;b9P% z%_&ay at 7=>@FF9ulS}_C*wL02#jB?L|qV3W`?{ zftS&JN(SW}C|hdRVEytgz%^1=v<%aQInTce)20~Jw3?J9J at ClMb#!Zv9X~wlVyTrG z;^#Z~9ACP3 at dorZ^!XAxxS{&60V__gK0E|8k{^AWP8YQe_3CJLlRC4902mDV>yF at u z=JvnhXRr2iLLOm_rh|-br27&^j5KPkBf9JMsOhPOL-&#CV5LTPo!+(ayDom$ z$M0$JdwTqy5x*Pa_bKsvX8b-iemBPN)8hB(@w*A{y6a-l4D;_++%w;2JM|hi^2!(q z9mWUp5ny~paT&-}Q^y0iVtU@>f0v0j at -^D9psfFYwFP3toM;4o{}Hj84r(6Kjg;uF zcbpe4zf3#r5_H-n5`xBDB1a-$ngl`mD2(kCxrFVeO}<2~k`O4gQ~N;P)uDPsSkV7c z0fALahpq$sTfq;^re7YBs?4-^fmsfn3(98Qh*dBLUY$PzSpxohC>rBi4AyZ7wbt?9 zysKy!`w at 6NVh=)y>hshPt*yHT7?rAIVvB+CTp4^>L1igt?1+w^Z8~_5ZDhfvplq<| ze~o~p&^y8qK<2uueR}dy1M~|rWR)TKewtJjv!&~lW^yhVF)TPqEYH?_vy at rz zmd*07HQ&as1cQ-me1 at _X1Z|d%nkPV_&w at -xpcUk8%oHU0j(8@$n(1xKq*pVYwCSIv znI>vVR)e|!zg81e@^-u$HPaW=B!1hFtJVf(zHk0tpkT5|Y6HKpHpLY)bv%UMm$Vof z%V`&CX&2tnVxa9!R<3sD7h<4;aT_B?gdlQJ!y06rS+>CiCn at VZi=a+qo$!@Gb)Qcq z*f(#H!Iv4}HmGML_*b*;EZp8T1V1n=xTHH9l(Th%SXlLyQ~dm~ULAk4>7Wf8nQiL> zFsxT7WtL;9?;u0^^ns>WLpO4->8V~SB at MxFn&gVkr5lKoI%<(zAh>kK(&bs0Tmb51qc zW?ZE^A-RqQx|S-?pOR~kROCyp3#4L^AxT0f0v+&?p(4o2p zXidZgIm{0(sEX-M5!|&t>3bi59JZd6s-pI)9 at F>psXRXS z0OI44fm&Z8t_#*<8hAZsca54v{QUF|*C-IZWXFsZiYwYVTlhHgko{OwrS+K3bpat= zQL9S^=%#vrR9I};j+<6I0FWO|l#S{4Lpro+a$$%Wv~(o0K&{smMbMd_uJkNHqK%4I zwOdvON30i1s-^Ou#5$Bc|$0D zD$po04Pt8`Hk3Y>p_V`}th2rqd`Aa8VH+qR(D6p#Dv;Gxu>~gs4{0PrV3kHH2i`hk zJuU{*Bp9=+&KlCv1CZL%^?Z#!i_#=A&Kj{OMll(-zJ(jrwF zq{{42NddZ$0-XhEkku at 4dWkcJ92PujM&fcME??pnNnC-%6-r#ORK7_n=cMwLAVGZB zYv^*Y2TZLc#DQPU-vw0xyPLN!BwTS|ai(}Zck9j7Hf6=>_sB76bMdML&3Ts7?`gIb zHrRUVv4nao!sw~S?E)tMKK#g`@NQGb|3DL=IWN1=q<$&@!peR{$naecpfYc*59gLkoWmLSHvDM^}%JZaci{&Hukx|6L(X#StYo*ql at HP;u zzN5lMEaFa_!kmX{nJsXcjkIU`Tx- zX)TsmnP>rDQmU8OsKlNj=`gfm-VmcXTc!f5P|p!mqU3e_;u{WzI1NCgJJrI%8R#r- zi83btL+CvQmE+(H82#kL>34N+E6~i4K~&6*7xruU``fS0Ck!Lpiw at OlS&qU?=FIkK zaXWG!J3POS{TorXWXmU_bPWK~Z0AGiI7q_J*2SKMeu|At;HFHpvu295eXtm$Ac z=oI8Qh-O{TH=l|am~6jAdh<-h1|Gk!fPudM2c=Bd4dnzQdU70iP7E5v5B2tnye)Bv zT?lbEF0=I56yOX%QgT}4-5=uN5e86=uACPCq7{!%0nDV50_>`Jw)5dM6aAkO7-TpYX;sJDpgTD0Qs-#X}5lCbLv;0$bmEDcn&DWP;cnMqV~ z6L|gW^v}gBm*S*iHZu)Wnk!pUV^*1ll=fI*3*i!q2dp*;+dbWSjS8vNZ#jH zY)+|o7CGMj4jLd*xq(#V(yFBr;}K!TpEMHXV zZ8ugLnW{EGFRnAg%#t>NL44871KM5`^cnjg$Om?mPG#$%iJ(3$CM9NxJqNk(BqbK| zK(_S=%$~YI`^hbOYkx#XT%(mRJ%c>a^;gROluhMD0y_(S>o3F*sldl{l?gB+?C2eA zRKv#Za5}_R2V?5kXQVy`aiasUOOIn`fc&j0Y5Ydq7(j`m*OW*wrB~!i>_xzCE~(6s zs?K$s;%7i3?3KAqQvjJx{S3v4lmcaH6m+x3qX~p&PaqTy|H|}n>q*j$+h5nX59(6eP~z^4ZZ_XEn9aYpr3;xt+YTLG?_SHTa8fg zQpAv=@XY%O6jaHlYEWW}G0o(EI8)`QRy{BwIU&B2aXMlh52a_LJtu-_!71Bo>q zhqTiH0~wd-YSXaPXc0R~$2MU{5|22{P5#@b;9e8Td4epTv>-rddKTeq0~@84P6QHLy)zsCEATy3fCCkqB#q=;8Tb(%IrwnE zxtgmCF(?9jGXu`ect+I!Wu%L75_LlfeDujL*RxOkt|~ zfrVVYpqJ>|al86JgDUsXMGB;%0pyikjzMfEY?Bk7Z!z(lv z2f#++dNDUl^bSjT`Flym5Ob5>hUrQAJO8V!tK2WN&N1^azrz5^kXt&Xlbdmeij8A=j#*Adf zam=_~?3o&jWQZFsGPPh at j+2V@#N*XftfN!bX0?xAeL68<#rx-){AaPZKex}7E$c!I zs_(SZHS(`BQ#yUQTHs#nbO}dVg?A&^?&TY$)s*W%EgdG#^*ZOeBH*{DX5p9SWCDqB zm0Br*O1WgEHCXBT5R*;^^1477R;-naGe6C3omhw&3Q+|OP%FK$w!LLU3q8}wp%2F; zE5Z;p5J%7&bj2iePJo%nN%e(NYq31-13dl5plaT=wWQpLuA6c*8r%lr&`XeojfQ`v z$JVVT&XsY;#%ZG887WZv=Ux2`{R5B*f$-UE4Lp6+4=nTyV7-6D)PZ01gG>s3dlXWu zMq%PK9qiW~i#sCD0fT{p2bG?FUpELiK-~xyDN*ZxG+95yz7xm6bkKD%j)Cr&gGwlJ z46ryYn-00&)dc~k6ohog0Ht3+o_BDhBw`cKW~svA?-8bk(r4p<-Uk}w{#<^lI_HF+ z#aBn7Ptbl3H|x*}=m9w=Im<)oGig_rL&p`_qfL1#)-URA7;8u}9B%g3^2Q6$bka`= zt?@Vjk7y_z&od`H}nDb=|1 at H)1JG5_J7s>FVUX+hiE at RRrHmF zzoez}I_U?}LZ={gE6ON=vyuc}1_Vy%Kibckq$q*0po(%z8o*5BETfe>7g^a69XnLy zEZc(fD>`e!|DnMVHj9q15h(a0ba=5t07)v!?EPE5Z0!eInreRqMXu2;Q+3Y#J6xky zb~KU(0k+p6xz1sd8FV*Rw#H*5>Yu`R9Xwjmu{8oD$A=0BsgidX6jpX9uF=j+VMNuI z(b*QsR`Kvr$D6#v=>RarHPWe3#zo%r-W@$<-8fT8g4go=} z93spPiLGXa1ND^8kPnAJj-|=wcP49rh}5^z68puNs4!p zE=F at q-#Z2Na`<;>G_$f)YD5G}%}|u2MZ2d|uS!CnHv9s>s5snAce>z)d?u0s51%Ni zlyu3TB}>KDd`2xqFpKwRx7-d?1j5)$%zO?$wix8;bpHiEEtHN&E&F2O`w*WNp!XT; z3O%VCvNo7CD-45vYTQ9L^_(dJ(`FzzMlS2IxnNt6s{!Fa|X+;5)fu5fGrwSP_ zR^9)>ff6c-C9p<8zV2XLaCz4|nAhQ2y}`k3g=;a`Qr&O`;hOmk2ZILz8#>0on0KP%@D5Uu z2jH|$s$$${7+;sM_1L3)7TJo9rs-sDo~6iX;DIEW zyixTR^}@3-9}S1E{R#Kn<>k3KdDWk&Uk8~`@B1Y3CRt&YHw at E`%1m at rBuJe3P(`*q zx at DI29H;xU8(m}nj at r8F6uXI3EUvbm(Dl13<(*T|C%Fji5hre5#BlLXV_BWt`^7jO@(B2o^gl8ERJjED(&xSaEsu< zx7$PLgRuWu(3M0?{!_f(HW111>Az+ at Nsc+}WqIbt-i9^O^j>u%iosKj`z(HrgW<`X z4#nihL$<{y^$f7U_F_X*hVNP!4_@%yQd5+{mq;08MKS3|i|HGM)}U=bT2U-U4UMyQ ztSAgVUT6?k6h}MDrWs0T=JzWDtRb+~D}E_{{sQzemqRal(gI+HCbvy8BC_IZ>y49bj!L$h#KLJprns$`Zg+L` z#)+nWSb|>TB0NLFgz`-=+OL at C0f3}F$Np!Nf1J(^x#(BMm5ZX*Jd^*waI4{je|Qi@ z7|aYIAp-{IF}kfTTJ+>%7=I5~c zP at 7)9GVly4myqpcyxWg7ekJhCqJ{Xhb)mJ_8Vp9Y0Y6nhLH8ufxf|m+vV0S1iQX8! zsY3ylk7LIvO^d7L85!y^LO|8l#nR at S3394OdhKl=-kJJw*jmDFB30W^UbD?^iM7~z zJVfA4ht5@#-r!%%KEu at B+CWS3dNQ5f zLR#uuy;X-!l at f9iN~$Ur(o4mwrY)C?s*FuKsme&kO^4RHigk+hnyK at 90AC`Go3=!3 z=k3>8GmGlHya2Tdn{7QlEmSeDb|Wd9ma|b;Hm$e>jKOKQ0QkJd_X)IBDXQDN7V34owNHbmeSRG`90A>@Axc-y|-t^*CSh0G}heqDqJz z-L?}y_?Elj29`>{683?@@v;_z!%;BHt>aS5=;6Yh>XRH|qqs60nI^$3#E!!2Om&S% zbPX%yesY8=Tw;q?Bh~3~|Kx*;RA-i|E=pA~P!$Ao`_%)`?~MlBnvA|4;<89C!;bzt zUFJ^L9GGuRhh~@#9kaWlEtx=MW}{SfbL2~{H`A0UpiSroc35U~R%Mf_(T&77Ba#kK z>(Kgj-E2DrmYvH?HNJ}y77Tib`E*2AX9*a8d`FdqydC_D)_PoQu`r}ATbd(8Y^MU{ z3eBL8XivW1aZoLn)|n*=YjHRvP}W$B?i9c^zJuRk4$?JO zpl=cD6{fYf#E`ls at n;mNGo(&W1|@cwqzB*Cb{e%LeTU1~xl*ek>Ewj9KR6D|wNk6a zne)3~)zMx+&W4^)DH?eY(dB2+RzMSY7?nnG1L#Nhce2o1W&#Q|ab-)!e@;-6lJPVp z<5cMV1;=&A$XiIrj`PBQg1&<5ffu!!bixiw2K?@Gt@?d|1AQaETQ|_#jfbT7`l{5` zIDmb*?T5g9{X~Ni2GcLg@{F9kz|1hUxMXFJgVXWxb!8#$$5j^Q(-2RlR~D|OAxA at c zI at rQ;8q!Y}7dmKIOv6GNE~a4t4fAQ3N5fni=Fl*kh87x{X?Q at bk%nt&xQ>SFY3QZl zCK_(0Ay30?G^AfnE~MX7F7(r|lZIV1+)2Y-G~7+YJv7{_*77jLmWGRHNKeaL*hRxm z8v1G2M#E+rZlfVj!_73 at L_;qP*VAw at 4cF4JhK8$Y$kA{m4a;d*MneY;i)mP>!cYv$ zX;?->2Mvp9SV+UgG~{TQOGEm(;z9!r%{0uRVKxmdG-POKq+uSdYYz?g(hyH)ejWY- zrOKM#z&`r(DS`EQFemQ-=5dpAxTdu_&v4}kE}-yPJ2J&1nx)726aE3dQjHWMQ{yv- zXX-hUd04rAy_E#X729#$h;CfGq=+Mm?S!pQJfa6%K%;3Fau(u^KaDqyU}(p){@R42 z^|)oemz2hq_VV}od-xBR{)NBYKg7QWrYJ;ZLDU6^N{6U3kssAJs5qBihkS7RM7_oE z_WJ9fB2>eyX2dZE3U`p4)b-h~Z!zG$TRgv at eH`U-<9u=1raau}Kdag!zGo8uYO+Id zf}y^lF5JyB%#{#rVOB7#72nl~(R!R#cV-_TX1u)fhKUexLOmAnoE zBq(_SJrC({??kw42+H8{!nNS!j`Yrq9ZpT>3e66u7Rv2hp%wddVu+Uhdb0Gu0~4?m zN+b4Z#gG=Eel~%F3M2L*j2O~jYG-O05xAX$YY?t}xO(8~hU)-a`{5#GPY+3DKNy0$ z40jps!*Cyl`v}}e;64iXQMgCp9))`h?y-O#6-WkpI2x~vDA;HtT-k6ff(yiaeZxTS zPQ)E;(FxN&x%|@@)Vou_dat|%ly(TTy@@^< zSNp_ at eX@(EeS*L{_rY^NTqAJpaOxJE>|CJ}KcLk6kW%kIQ;J61;xH3^^#MTAUg%7L z+?fIgKofoT0eYYT+VqqMCbP+9m%(i%T&v+)3)gzMHo?Wi^?iZ%O%BjH2kzN$&xX4N z?iRS4;ckYz5$;B~8{lq$yB_ZP$$g{JXfK5O;p&F#bs?p1oI1cdr7!6F8vCXyJN!MutoEyPlub{Jvb6BpGW;Qoaq+6Y@$M^ciSOumqxB>(FtBb| zBaD%L)lmR9^dB69{suzw>6d>21!t;o?;{*k&_E}=I1;$?q#C!-M3Q|P+6033a&OoT-9r at I28eqpXUBg#CUF#`{6HB!GzaW6 z3NvhR+s@Y)39JzaPE>_JI$tNrH_FiJzp58pue!S5nMl+h{Za1`#D~~&#*)l_JSF=e4 zQ2yKa{qVCZ at dMr{C%?8z{dt#Zv`9IyTs`oI9p&T;lam?~Nij~oIytFYO#=Oml!K!q37*3x`&ZI} zP5yhRA8z!yJJ?~&I;U#HBkxbtz8naL&e~(9Aq87*BPF$ma zhc5UW=)_0B$|mX0k*IYXG=K8;+_&OIMNBjr70I^&<+*SB7+V8n@#9X;DmwFmK-9>^p1%vUNblG7M+n&}?9-%!5w$j9)g zw2_W6ekT5$lYG}F>gjy7R|abr^wr1NyRs75NXg>qvCL88iusr{rY(4y3A~* zG$G}ir0JyGD^-9gY at cTMq!h+4nU)tTWje|?3mNi9Yq5`@AM9!Q*Gkc>fK17BgFLpH zb_m3dIW}tri&(x{3zcXhnZy7kJM@?ctvaG-+P-6C_zY5F5Z7(~q?ZJfFsYAXdA6SLIb``33vUEl zQQJHKVczy$;u?1Em?yQw0<9YHWjt9)(>fbD-*m9oXW-=WMzm*#@wdCo7pxJ8%b-sW)*Z02__v3r>=+4-yPMM{H63E&-8;L4SsYg z+}U=mfS(d#Ex3gsvUo>E at iu;1aSe^aZ4;4O;eoC+XNpm?FcZLq=@d#|TqEdLU=_bY zbh;Hh-~QAU!D2di+;qrTF&5PG2GeWD#c)An?v)^V-1)nA9B&Ih(l$N^;r z31YN9rpEMakFF0l)v@@|yH+a1cwTpj%c5&7v!iQ+QMOV0w1!z9W9oaIL+7o?d~5SvK! z8NHj&lrl1Iy at PoOMzkO`irX+mf7xLP2iR=A4T|h)Od|8ab`_aK{ZpvpVMx}}QuOlUwDvfauzp6!mIL1d zV$G9(?PnM|gUU at dY{T=|Ty%TQ0r>(LY8>1I*3E!qT`x}2_|tS#J#wu=&$8my+lV-7^WD>ChQ^JXOHf65#2BeRc|wxo$rD1fXbBI+QwRJ-MCPvZ&0V5^>!N1j&C|M+v0-X3ba zMcz|B8NYlLzc7A;A83X#4i()SP>+$J^-QHF*chOu`?}~RASky_uUiIB%dOXR=b*ZI zm{4b+C;3KwFm#Vd at q_GV6bYcU^ivHo8vYIH97_hZc>LYV$fwKDq2uxR6t~AC2{G(6 z`=9tHfJXdGjE1W4fNCI8U0|(FuR-U{sMJ5hqq1KkZq^;v(s2{Z9D3_QkH zejCqDfsTx5L4&}ETPmgWb0AaJfQZFaJ$?A#Ylznx12~CPGWU^s`iILPj$a3%`knr at y* ze}M#p(X at cR!?6I*tTd9h#J|iB{w19-rq{|~n!Bjs2P)+sK8fpH<_ at PyT@#cmE(>W4`2BMA&ZVC8YN>{FVhtEZr})n!`Kj?;;uGXS(9! z+586>R>e=^F<~$YVOZhZpbqL>dG7MWcv468zu%i2Prp~c&WH;D{)|*-aLadS)p0(y z+~^Rty5-vEQOZOWJbLarXz+u&~?m*Bv2x=ky z!SOWl;{4#nbe%q+0(MhCM_wDBBe$1M#%x*~GZ<7w!jQ1QEkFAVPDc0(EFStxrc0j1 zJwHQWcg@~KDRra7Y5pz_KA;VrNfTE?0<2|1>yzJnp3YBopOtq0hBQ1;Jf76^1=)^% zezu<{lDa!Dl`_50?_Io{@%SwD_$z?jxEdBoxA(PVkiHi%1%LbXPE-YIU+BuCzW_PU zr}s!pFioB at DIv{wb4`7(?bORyZY1q_jFyaAF_?=^>T$zpDbxJE?|MBz?8Z}l$q^8D zL=|`Bs`%dg;CtyrpMjlafUei$F-OwfkiE2hJPH|_-=H5j$?v>?r^a5?Qs0+c{X8BX zgLTQv at JE0qv@O~``$*$$?bqeYrOeiw$s1PM{Xui3?D8^9dxa6XxE3syzFd!zwJSwk z!=KWLT3Tj_J!VeM#h<-njqT+sJbkTXwt+o#u`@ej zL{PVU(@*H>h#~cxB$aQoxum-cc^41IrgvB0qZ7jO?VJ-D~m8S7}lCPa0_kZ z_8sZy9*p}$d8 at yN|H@=P;v?c;(2JM^1Bm;?h(`EZ!m+1%I{8_NLeyh6nxpTslw-T;0i2_A9Z$TNxnYV$?t>Nvwdj|0ze$TWZW!51>k zAAfu!(?BUHhO)dwi5s`^@uIi(&+WM~xS*dLUC4|mioL%vlLTvb5k}JI^?n((oDL=u zPP860yDvS3%3-bj3N-4G;>n(yzkMaysKrGsM*dGPW6Piw4f-FV*9|CnFDPoSC0b z1Pe5NzTCKUa^tUmnbsWlp5n&D6a3qN2fDM2MXY)2?@5c%^vf3W6{it5t>KpMmQnI& z-atTOW23kOGD=xYQGa-wR2bXeLB}-z6 at p%1KHt>!ON_r}Ki8-w(Q4cnb+0Uf47j6J zuel$;Ed8^lB^Fs_uZuRW>KNdsdgROhq8^jlf?GSuHGYci6zRPpM6FjbJ5T}SR4pg_ z2Gs9ZVSastoUn(sYDvGw6|=qtMlnZPMk9CNrqI_Iu>8Ki2S*h`-l4ED!2KaWzN2S5 zqK^*nj`OCD64kdEzJ$jfRv2?h$l6Qk5dL!_h8>MWpm#a!-GV1j7ew>)jv~R#=b at 5k zNhpMwMU&O8A1#X0S-$@Xsy$icg;DHEwDnTvgJtx{Me_|k46G38!#wMw$v&pu9Q;g{aLtSd at O`>dQFZ|;lL5yc`@)bOkFS#a@?T$NhW!rh#Pxsl$q#F;V#P5HFSn#h} zg}*;X)_?`6EWRJlVjcr)OV^9rXX0 at l;^BhLfLbrsoe!LKIKhdk+_fo>vYOM(0`v{AWNVn^i&wpNHC5k_^rFyAREF#ulp1Eq)bWSkzcjxm0_ z81lx;iMMR);6$rl`R=F4k&$TCQ_U&lxNjoQ_rLooN}SG*=c%B1VB!R%YK5mMAx08} z7>>JeKTU|d1R*Zi6uI#|y62Z1pd0~Kd0i~{7vKn6j{M=1$PqS)9hQgSQ5Q<#h~Ypp z?#661*MDFyvLkw$0kXSBF_-YBauCnumw$kO2T=t9(fbsA zL1%<6gf1-k2^xXl{s)>fH1ebLb${a3{Un}$m4OZ at dVILssD$#w*il$x*C9Yvzuf> zHkm~N1PBr&DjKSh01`LBg|JCb0vp%t5;0&~r0a^6!c2flAn9Z=lVR1i`c_+QrP#Oj z at 2&NfAAf*^Xc7eZwHkriXw!Pvr5ZFQ3t2MXIcH`!n?T#w=lQoeqD&_chF5ljc&3;xaC{ zykd_5=i-LTDo_%I)3QmgKr|;gTG_36LSfAt zE~|khn)A_-IiEK~#{%Tsc6rW|*XlXTN9KIN5FIp-bMfUlpN{4ngE<#M&cnGKrt+{X zy=aJzuL>u->hhc`uGLSt7 at dN2GNZ8acbI zZQU24n{2nNpS~pEHu_Hr%0 at tb2QvV!E`%+zMM79>&Cq;e!q#>z{KmKTAdp7B|#`Y$L4A;ORL5-XMk at 5VN< za=rmQ4*HU+a$EQYbf8gICd?|sJHEXCG;O5g>K(+rdtfXy(7!d3C-299iO+T+D^R9} z#>Zl}>#+@(rGq$0e)|UaD8iFzXg|f*qLaVlSak9;EBXg*C;06sMcIRIAc;)UK+Pw- z+k)+A^Si_he11tr(UZU?Y)&rPImKYuVqshIklhbvQ6pDDBT=9*OU+{*Y+hwL7^;!N z4{3*@e8XgF at jaSOg2a+Fv%6({!^`*(?ky8$P`CXJYfzJ=VIB=M)(>hmf0<;Rj6jLe zX9{I0H5O^m$Zy|-9QoiB{_(YB{}IbixCb~FWq{7stAdh-#(dn!ce(M1cs?HKacmvQ z$C)tm)(3$kuz*>2muLFlAXZCGVe&d#1&n(0+aRY at Px`XX`|5P|OXc z8)L&}b0Q3xEmPR?n}@T-pIoD}Yr%5{Z8T-P9DL6Z8<3mdL5LmD%;3$~HnvvtJ`5-m z?k^Kc%7p96#1?kLjp*kPn0w_o8feK at 4g-IvbSfD?1qvTT1$F2xtsfCZfETTUl!L)D zgXEVz4kO7vV{i;^IS11ai_x)U$MVB4?r+r~^fEIeOZlWZ`oHaRm~tL4hB)r!-)dI7wB z3~v^A{sW#IJQ+OAs};j)U>sce%^rAuMgp?B8&w44@?J>vsd at s~4O^?WUjkfk5t^>p zI)=USPe8z%wpJml-EiaxRByDCm7=+O2uf);AZHAz at i44axJMOxlunlip@X1F;ML0B zG9aE)6){sO&yeOBYQ`y}p{OQPV}c5;>nT>#A;H$aqnUK6m%Q)V1NXlh^KajAT2&9V zHYGPS3x8LtGeP{4YzE;pQtYsDZ2p3|M&Tl~f#2UDU0B6G{sWqQOK=EZxSnr7d+^eQ z`FsOeIJ!_KY>_UM3rnR7-{cz_X at +qX?8W{1Vb)~HW~|8!lp5>i0uZFAP2-jH#?fk$ znyQ4GcqOTkQdeLSKxACQ0ok5E@@v z8$1JfO&9wP8u;Tx(UsPKBh0j+}-26&l$S8U*`#^DWAlA8Fq28#b1 z%m6^8!F0We(7q{ULOKxZx1gk#<_9YQz)Rl at BDSN=SrxP+QD~8vmv5Ltv at cN~z(DRA z{zBC6S`75p4HDQgfiDA)>kwpB5HF{^v?(}1bIB at gY)qgK0GU+Yuq|34Igs#FYt_ z;4gt3N0H(R-4qLNiVH6fjf;h^iwj=_lL3f}DrPB1T}YDO=_g^9#MIi}VC^NOFu^|q zZxkgkAg)46pelj#E>se9^sw`%>FSrQRm^2?-Y|T}%}Iu&x$ zO)!`Ja732LSImNIA&@g`VbI6WwVjjxME+L?7VhYa_M+e%mh)eMz^q3Y!YA z73M=l0oTA2-tfAP?5pz+%`YgA)Qp4GU at q`CP3cM{*EmXbaA<$BrwPv&8;$T;0^gyV zmC6j;DPcoNeskTtX<~xC#HotCs9K2hrzt5=&atQZqIg?SQcxY)P!B&flK?4=nYkd5 zwPR!MRmz$4&9#?8E;M-O=xNL>s1A$Sn0yl3J{@--P}3)L9p?S3-bJDJ*!QLn$Iqon zSHKUsG}8AT$-PC~4#j-hp~#GB at QjGQW<+$nekjH#MB`C42e(mzE6G4fH6E$ea)9us zn$ceh>$pC;gQ96#-aScQl0%!cGwm-arSM*U^W3Yo*Tbyr0QMXXo;3C-0YJMhp||Dg z$lNJnHd`M9>KjB?M_ydu*d5Iz#)Nj_Hlo|Z3f>@g{|cx4^(*zGuQUIM3D7>f-n1KO z-_a7?nWT;BKHH!;iAAoXGk at 9&lIJpcV)V>EM{@$EY0rMDx!aJF at vI2inatjVd}M#S&yWM-C%?M2g|% z&wumZmVeENXbXBHXWN>w#UlcLJ3P?p)Io^akhwhKsbLY)IV>|!-oqxohh(is+N&uz zj-%0M($sL+{fo2#c$HE|X58^sp1JH=jIOJVpnzE(#>pP#%rwn7F$1rir-dWv7{@%H zlEb_rh+F8!?Paxi^3TI+F^1fI5u^QanN|hsuqsGh#(!6VtAoU%B|PS1O*k z_iz7;;uF43 at d^K-`2TwM3dNf-LwD(wi#LCr;?4h|`0?*vVF+mRpJU%Dz2XqS=&vyZ zF!_HN0zW);1tf5o;jblEMgsSBkih*1BwTf+;;oqBzJF1?_3IRG{SU?e_~aG(AX%S= zA3Cns2gzS=8YcheX_$7UT6pwYEW2_oJYTOCp8s5nM^9X#7UT6=oLqRtT8#gCwHW`O zYhgTbg#nR`8I~@*@_ at +xIs+p6iUXp)mcywssky&1PCcS)Yju?CAzEH=QB%JYIjNRg zDFAr^DKD0UV-H`{lvS at 7O%S$R`qvQn-40;=U%sTnsEbb!yDz1>l`m{9!g#!k;8N74 z2~EJWE@>QXpYQJz&o5swTz%q*wm}E{r$-6fF4lZkDYpd7qtG3XJ7mIpZ(>9_ZR_7~ zjedvI}C8wNM+HHRoruh#EQbc-G0V85 z(Q1bZ^k_+QFW4?_cwxozmCD~o=yPbuCbQ>caRT@@{~7UmXw5YC$z*gx9Q~)WG2b0c zOEZYk017xLt6!~2!kgt{4%>aD3`JUom0AvIFkxNq68?|;uJ^3)>FgBMSqIdfGWev+sa_>;oPw8!sc9C+xoFed9U0M zK*PrJD*-epk2WoBr`H!KfZtjxAUgOIG#f%F>9bnWCx?=@txs2~BbZbS2Yo0;*IM!Z z05gKH#WxmU$di7|r8JPmdbDof2rH+Ro}dkN39a5IP-58QBF$tNNa at HnKYRjr5RYiq zJz!8;TrBZ82JJyPUeosH{XaJ93bCZJ-UMH$|6i=Bp1N4kLejYJLOUR621VD)U*vW< z*_1`mQ;tLsQ$n-dY>89T&$qP;*DJ-5GF#ia1f>nR>~8j(R&<2+&teorx*+!$qGFi^ zwcTQwtzS&a?<BEQFX+l at NVi^tnLQF_CBjt2F4m at 9H;alTH_;ATmqENGPF)^> zx`tHtU%=~0VW8up1&{`fo;jbi_G-KRD(}Z5`+_3UrJvzuAG)3?XStcE6(mf7-l%!U&F;r< z_U8#hy7_F}T_9?)gAf!%KhuzZ9D8L#{N0LG6X`t*R0T5( zk05>ui9OPQd7T(|Bm(ppR~0~VlT~UqOD*PxlfqrMRYb({Cg&x1FTAbdl6Y&Aa}eII zyRBkSoZ946(NpYg6{?tur-}u&k#z?{xAVL0D!+S?8Y+ReL3kSs6~fykc)Jvu32za2 zi-e|YrG at w=D?rJ(ZM0~$&sQChg6hb+bEva_sFe)NrR27RzM%Sh4xn2>k2?1E6}tcC z7vZJ89YgEY`#v=oHlSk4hb#4kn7LdU&-48X)Vw^>3j^umZ2j5_S^v=!de6R!e$QUi zT&j-s9(gt9Bc5EWLQ%)#*n%WAjJ_M$9^-9l!-a^KSeRkS+~*?N>!5ZQWccd zX10mkx}JFTru^m*4-A4;Nr$C4K|MifEbGq26g$f~cYdGks5qHDId1qpkZiIGnc*9^ zER?q6Y(lZY)&`^5ICS$RF7L7tdAn2M@^)S!uT<1Px3wpD at yWiqSDVtKsKppm#h!){ z>Fq%Oa4(_r%o|jl8(QG4d~m*jjf3dDFG5VaIp_D7AcX62Q6qw_5+-@^g{A0lEwJb( zpsQI7&2I*_F4KD)=lqN1K+8E+UZh{t$UjqDFqzSPl(&!pnA{ETO%CfXQNdQKwHSE+ zbJ(%7HzWAbv(PbhSg!5#tHMTg_C^eh;LRxoDCt>PFl4by`pgXPw*GY<)(KGsNw9?W zue(E?!%pU- at -#b`kE96w^bycEC{zdbM^Zzz-~y0X;OG+45oRsgPNWi)+Ro4~yl0{L zdygOvP_wl=AenJ3yO#cLql)XC>$*`NMEmueI7e0lWJ z*dHSr*S@#>9)n?ZL88H6H;8j~6vCr^FMc>dS`x2)6)!ZcE@;fe=<(8C0iNkK>G_8W z8X3IuPqip5WEO0hw+F|JaHponAJJ|V?1lO18(ayTz_4=Wjx6W;VdYGSmScr-Uee2v z%ezA+ydZF<*u@^1tLd?EzAQEx2S594Hr+ktd{$O1ZTqm>fz9;E|VMHUDrD{4KGum_w)J5M+qwb5wr*V;*p0$o-~j$E5_b~68bNVE(*u)hd!ZVr{Z?&J zTJfH|gUf$A_igDT9v{yr;rxra7o|^ld?+VU-xu!y7C|{GeY90BXSVagnB4QoCtk1Z z|7x}%fmUyTB~+=jm`ylhHbUL5LwNC-W=j|`Sl5XRFvYVD8*4xiUXw- zM?fi#fKnU*rE8;oe>}e9t#s*(8{WUbXBHAtrH{9w--EY>t8(A2aI*D;dJfTB+3P5=gZ$>x7^hKSE(HU_t0sEQr?5XJ!ov9(rW6+J${$ZP(eE(`asdD zql?MYfkD}6Fc%x-w1^3Q$Ab+usGmqCL at RLJ!eK!w!txX*QwP=rE9*6tkhZ zJu#A?`Hv=L0NLLOS#~tg>sfeJ$95o{Dl?(;TQ(Ecf+}33-$W1Qy~Hjx)3snsU;w&j zWa*g3i?D%Ba1sag1|%6Wg0M3ysn{?KDMNY)(yy?5gUh!#K*jq&4*2z}=pYTlW&d=% z7v|5qq at ASrXCO86cj0dU4YkTob>i=H at 8a(+v at jy?!z-Puw?7r8N8lVip6j58|4n-Q zs+k^tcmp2KKJM>9!z2!KpxoR}B_Zl$Kchl=F>X;r4s;_?q)LrPEK+3=i?Y8vhBco- z>C{japo%*+WWoA?yCj at 1fqi@caW#Gt&+6bagZfdd9%;_icr8=4+6ASr!qTgQ>j&}NR#SUBs$D*a0yv=R z0N8<4+M$!9ipcDhkpaIM3h>SF&PAexQZkhpl zNzwtJfUFkySybWBjjx>6uK5QXXPvAkWmwdKXjG?@r4P^bf)>T{IuP&?dGZlxx^zsH zi at Ja(k&E7iUvC74F1xN-X9M4~eJO07d$q7}$8kstpr$(AtnPqz0L(Wmf{u;Gz_R-& zV5Q2!DHT52Ud4Mn}wVCSXeM98h9UWLg ziJK{?F!4aMHJxreHYFA23S42{=COqZTSu3KKF>d+h;PDJH00r&shfA3I2SUxF%w|O z=;#h5LdxV4$e36A6~<>m{2YuQ8Cg)>fd)0Y`Ta?<<18S18dX@`U}oQcBU;@It-22 zglnHwRnjqaWIWiMoO{sZ$h1{vZcPdZNf$y1rXHy_1GQ^N!09y%tL)^2WU~5fc)`N!%P3772oAbaS+%+(j zPnT*rqnIJj?nD}qb~Z*SLJy+uhCI8Q!Wr%z{5(;&M-e5OGcQnwDvrnl%?Qqzi0L+6 zRZmaDz1JnGX_!AWVK06ZQ1E8U4fIqK2{aL>c;!5c8w$?vbAk}VzBKDbskF-`2gxT{ zMu8Zi{hMXDHR?fIT*bDrSZC2<8;juhhDUT05Sr$JqVr1s4m%(hks z{9PUJDg-c5=we5KAM5PrCM%a#T?z5fP`i1TI7S48}7Bx4RQpy2^FqN9| zH(Bd-+X*o(|Bx*a#}5BoODGjTu!s3)K{^e+;^Vx_a8c|mqt#42*NT_*2F1Sc1w?lQY+hQ2+*wuWQknwIbPdcFy{ z`c?O*F<*t2uP;~6hnDK=k;l1QE9OBRKmTi9<*x?Q)>8)))v z)YgC2UpRK%{2y=lyUXLP%m2s-QtNlo_eY1+QWB^q`lV0%z$Tzya&1@!uDnxeM>Aru zI{g@$l-sE|!Z89CSZMkjgoD8R*Ob%G+~s6jfgQ+gpLEJ+c)hN|XmCN$8VCY$&J-S9 zNluftmTxxu)%B$SroJ6(AyxK573x1iiX=O at O^J)7Ly`Gn8jz%_{tG~o at W3>Yh|;T6 zI}Dp|8o+#^nJ6LXnWH&J{o9<$&^1Qt70!oiZLeIC;bE&0SE^i+^^CXfe+E^k_bb4= z=#`EbUPIz3CccK`R4K_qb+!fO+BBteenD2#=8M$WMe-7BuDQu)kW0{5u?tpoHIJns z;AE-UT=h)O3gbMaB9GF%^3!flQOZB*_iS zE3)Nz at ph!#tT=I)8Md8QG{c5g)AIXlZQ^A1lyUeL=2Y at 5M_ZVql(b$Xqg>qH=TOFb zM`UEZ at fpMaI^(nv8UHveW6xz7EocxCR{z at ys;xD*!AnA8riawt&<1n{1lXmpQLr(z zG9PE{(9^5WmQW?+6x!HthsWOJvd z7P6{ybe*%g+8H}tTiuHoYTX;A-yZr!NU=r(y)wVk2qD6l`O<}NtUDhl`=@ka^oDd_ z+A?UN`JL at w;f4Ohh3NYO^~30X(0eOubc|ahj)y*J0}CfPJ~W;aN^SwovCNUUWo7M zUzL-kbU;jI|36G8)}`AZ-3D%5GWvX|F)qnJskAK>llxEicS@%X%U7&CXfbyKz_16Om*x~*gLl-!O5 at W{;V*lX~AY{d7(1-Tue81Ze9-5JjuK(g5n3^TIOC0P$N zBk47D6jVpV!~;=MdvZZRskwHP(z&1@>nEEp=AXGkb_1RL31!wutzrNU+n2o3R|pgm zNGsEB&4VL|@GyN3=$D1Dfjl%cI`zSU1GxiT zu*Aki at WdG!7l&Y6d`Sa2lLm4|Y#>|pfo#zS@(LUU-#|B8!Zi{z3*#l0CRoa7-*T at R zR{YkzSJAJT!{5hT&$2Ov87?W(NA`0Xl}C*Wrn zac8H-td4yb1m**n4>t`4r~?`s5|Nj(+uGOlHu*n;q-}l-$ZlvBZVEj2`9*Z>(!uXG z**Z3i%Wbhc15c)5yf6DM_Q(Gwak#k2RNT-kcKQrzjV0iZKo%&?2_<7fC!OBBwhuR2 zTo4YSFxow_Xb)s^v7fz;%fLcCK_otb7cJ;eq8dt+gIL?{z+(DZj6!aX4fL)&g};G at bc{9~ z58RV24NTZzsau>5rJSfcm>uG!ixW1aV?Z_pe45>84Vl^uhWWN*>kcaAk(IbJw&>Tm zGX|{eUSwsr-2zMVpC;m&+zzsfTDn%4ENxw55XLJTyf7&^Up71c5w10D?B};2Gn>XP zWk(s`4PII7w#_Evs&il>OmwSb&uaU0eElE}6d~Eoe)tE-zXKD=rCx$YwhpobCAI|TSfjJoz z)0I}XCqmaZo21v7KmEbpdYVK4O;FTM8-}zb#A(v7hO; zV*=vmP3aAXw7oBWcL_|ELqT-Y5eKGmC$8t+0Or9%d9v6Q_>*1ho6wC-C1 at 09I=_1! zzq>gEDC=sfn*ovBLfd43W-PUZYd!_`tfZuFoH+%kW)oHyTYzeD^|`I5a4NrHP|DAX-BO*Y$YEj4`r zdy8t|{j=!m_tmfBrK38Ivo8`aD8*)W732VrvWp9uk9q$x zJfiJTaSo90kA*M9wufPW`3$80`fHMTrH!0HxC-?sVT=fwF;z-kvr-!)`OPqeGQ6EQ zg^JNaNqLvbeB*H%$+c(M&ry6{>4nk4ZY8;pvlW~922?!tW&_P&TW`bd(@wmBUjl)z z;yomoOv=EQzmldI=!Veub#sbcsC0x!LW+1+t?|a@*J!20Tcph}C%gH#xbwNf>r#q3 zY3s4CWNiZP{}i(ICE~m`@_xLj1#`x>uTBJI19n{5TlqP96q&aO^Y+L8XL1OEP#lh7J+lA7U*3j(x=A8=@&8XA1clF zShdFx9f(!D<~Ouui(xMH{U|L!ALpSwsO*kONC-mLqTWt+{eYIs#q5}iwe;d at jlxC9 zjIK*zjIsfc0!Q at g8N{UhQi{a`43!;9F-%C=@L<3h-2SGK(gU*EvN?qqIAplmw=?{rL;+wNq=6m(qwnoYnk zKfCcox*HYPkC(KRZdJ=UvE9w~;-}_yOh at Ew9DXRadDQomN3pqh zX5z$;z40Hf#D6poeFRp*c+Hu~L4^#B0a;6wxop+nWdYM|{M zRK~-q;RyWyty(LVEA6CJ_)Q z+Fr62_`)r)wr8>Z7`%3kzQ9{gYYY6o8^{zh%bK9mh(O62r3me+vj@~+`&%?aTOg at A z9x0jF9lhDbRw3lFwZQH84EOL)9$cVYM5p2xRpGY$KHGbOO}c0lu9q$*2$PxGqpI&k4kjF8!!;*te;lP^E1Qnz~3Y(mD{B?twS} z*P%$2*7Jwg?e*CIR$P>T z)8*LGSwy9JV0k8Kr~dOHX(zOty at d)Z-CqH5DP1EcDWzU08o*n}>j;3_kBh`r@@5S| zJ>%jUh^%}(Q-^+kVO-sRJ=MG$z#SW_)g0NpR(cOECOfb?3Bhw3a!NPD9T2T(MQDzG zVc at y_QC(yG?5eMeM$1z1gB2@>ND$6??-NAJ(LcgZp*^CdDG73dB#^9YwHDqa&eHCr ze#6H*1CJtY^;w-P<(DJQ$9|-h(fEtUX~28SUSD8v%heVZ*pC#OOai0gT%a(oX^J>W z3fp<XBy(9W_##rGzB2uCxxx+mp7ad z66*$Lh<9o6R*BWY;Mj4Qk(CR7rHVmPz5%ss8i18R!k{`Vfel8jo{a573RYDG43J6; z&@fspTHQKo%Womn=ARjA_%j;(K#3iYG|uUD0zkZvM(HaCwa9IVx4D at smSc*=@hNT| z9A>Yc+?^DAD@}O*(8KC(A$8ny$l2nRb5CHSxh>fsXUf&#zzS=ixJ=EH9lhRV08*X3 z{WSn=@>ZbcDtqse#-*W4?_L;Y80ozm(&_OV-nh)}&QbDLnxU>=hQ at yK*vHT7*OP&3 z=mGvbj7*&)Vrl6z2eR^_g)5GTR(@Wr?0e{tHM71p@&=T;xe?t7i;K{?^JI-C2v(^LW_zS|(JUW|?^3aa0$B1UIhmeB}4X;FyqLS z_o23t?7t6Z?GB&`iFhqPP&Qo-+>P9K*^I!l>_oIyCkK{MN-t_B0i8tcC21dm0m0*U zMokHmZ`gsiq2?8fp1LhYgIM9c7f~r%)m at m9oxMpLaD783bJPDqy<{5{($FY$@@ly> z0shPi)d`l$1UXNk>IO at 3YneTg2TT#J?NzehiAmbm&v2`|uwG34c~k)b*Ln!WI>7FLfuK zj#)q;0)9ZR)4Ei}kLB#osRVY|>GtS#`Neb5DLp#BPs6}OE8{i%CQ?e-e|3 z>d(Dt9KKVde82*uH0_yi!0*MqkAUAvTObnQY9ryQzWq34WZSf9;@8OSb7YsC(-YY(gQN=gl2TlT`_F#7TohRNm_=$y zdhk$^>|ZlTJIy5L1lmJG^PvKQ5#c7tyV8AV;VmWCaCP|c^!W5g| z3SFa69;k0-z}&7_c=t)9Bwfhp}$c=Bc;F*s`%8;$#CHb^YBe6Q0ty7bDkG&P97VvE?IkI|+lb z`4$>b+QwMklW{ZP=@BH8bGh at +C|`JFnqg=?$97n-IN4$3h=Qk#=%3xJEX*qlw$t7n z9;Hwb&k30RFyDY?uj&dG^Zq=1*<>u{{nyc3!b;wcMmLlT-uqrh>oDK?6bp@^c@<3csByR=+wJ_VujHvWs}-0 z^@F&IZ8=m-%cqOIz6&|U{JyFx+n|_&#rV+>i?k2ZCvL6qxU at -1QywJ5r(>*=Mq9q~ zzP8Nn!t at H^Ntt^>*nh%tuS5Zh{ zE$69*c;{yvtJLqtPJq-rM$BP(pJS$LpQfG<&4ekgB&lo7?3R%3DPtN0vBak- at tGca zL_Whj=YK*Q2l;)WQ8L7NHFT?9ax#F%#nrdPf;-Y2>EBISgl9($$rQ?x zHA*{s6Y7g9kGO%UBjJ7KjF83OE>sRgOIvs&ZL$}s1D at Xw{FgoqMzxcxC8Gx0uERzN zHn3ui(#jqK*dBHWZ589TnK)D5G81o5Y~k6nIv~g%@(IOjGBpOnh4YEq4S!- zOh!9V-%x7LDtN~MiuxNDm31uaeR>b2d)R%SV{t$DC-%zlOJ`lIaH1wCNvqd>9=k0S zy;dbARR`z1t*X(ZS9Nw4in_DU;f~*X(9o$nGO>nXRT%HoBGvcQ<78u~4vpM|uHP at 9 zTo418>SljGq|M1p at 2c11uWWI2Wec6+Ik**gQJg)h4q4p)T17|xMbW-k(NFxlqSdiI z5Pr~Xh~YznKb8tVj?USraNJvokD at cZNf43@o#oJu%VP<8F+tmk_#5f4ykW{om=eKq zhFF`%L7Q?ga&V9$r8JCDcVy}D=}`GF>T;(M^x%(^aHx5o$JvsT2?Tn0+mqewyB(Ub zYT(1$OYWV15EdG>RNj&S&Ck(#LYYjSpijx$uld4c)jE zx0iTvF9M|MmB~?o9e0c4rSW;%449W3^C}~ktU@r`cJ zs%WTW`hcrPLu6G|>evXPbBS4%lR`i)m;M;-$n`-<=w^GR)^l#QRX>2GOG9_I(sN(|p11=tRogxCu(dym!?{Q6rKc0)XyBGL zkawDguOEQS4!v2$y{Vy@=C?x^Jm at Xy>TdJao)f zL|r1>iQY at a>o1?+W1^iFo!c-!SNIIWy0VLIXB|iRA9=*s^hojH?CvF>7V5Q;im20Z z96Og!4cA+U$}sNSu0XbEHqHZY^Xs&E>wN{EJ2Ub6^n2bH=_5<~c%DA8=>wXBzSfl4 zSm;iiy23cA2ooBFG^r??UU0R|*?}!25Ib-Nw}RZR}gm(b`4 zH&$P0b6iBfEBS{StHW)M3x at ds31pGA8Ni*OhA=q`4Pcm)&G at -4h=|s?j^3D+a^L|o z_&tuuG=~KZn4^W09z2#?{%=j3Kx)mz32jLsVW(T1bcG9Z0o#Ylfc%rqUbNE>W7KdL z^fTVgM}IVwawi%|sBVqAM)aVSvB_od?oo=+vEi0{w=#P%I__(;deLJH>Ka7Uu^c*w zpEKm1Pio63wo%5-ohwwzF%-FSdDJ3+8L~;&lB2-Z9rz#uo8NaJ58kE1uV!3A#^maN z`K#$jvgdlA=V2`7N$r{Jf4Awlx0FbOIh#+C#nM(Ohf?Ae?|DUaDU&Twf_p!Pd6aoT zRmMnL%tj&2qn`3G7624o2lT3qs~;>ITwvIImQt>y9qSZKDVm(>siF9PtXLjXf>UR` zHJuh$&3lb1fvwh7t{pQ3R4Mn{_qArf+=#iOFcJ4nuEzub}iUgQ}GSw|z7zDohBM_+cy&?U4 z=eUvmzwF3b>cqqfv5gLuw zah#U=iv~!yE=6k2u(hlU#S{yrb5 at ku=cBH)#iI=7Zn8*ik(SSS<=6v<%(!E;-MA1L zq4FLjeUV%q>1#3a{!cl$lc zoo3seoVWl`ulUO9Z~v;Oy{ z3Q*t0CbKvdD|Jg~V&Kj$3V%hbEk;p&zh@>WoU+J_K9dQevWSzHaDe2H34L1P1ryG8 zns30ZeKg;1IiXZRYEE8ZmLc^L_~qc&wuBS!YXYP+mh*!xjqrjFKJhX zD<+i~lpmF}dtpE+vys|*4R(W}Ru?NHpTrKGk*Oj~1?9^x`+cF;V+tDYDx7hx4i at p}i(C|GM~?a5bd zJ>o2>+4^8}hErQjJn=?lZ0)4hyiwBTp_Yqg?}L3ACQ9#pb3Ph}7-nLp#A<67+I?oP z0oV#JPE24|Gw#9|3xK>zt+9IITO0bBw1iX9E1+3T#3GautHh~FTa=%usGv#Ax!lV4 zte*TcA(N at O*xy`xL1}%UnPzcA9?oJI|BmoIvYnIdW~rIGL+tgLl>u6nTR!1Un=G`n z>XjjzVI67^O;rSbLcYK&Beshhij}u>kF^9Xfl}*ysVuBYjpuN23_KBmhiru>9(dX# zJ^1M~x7RUv!H+~NXOVbVsf2+RPDFVtu+$=#ndSLh;0}1< zK$G#stZe1vO?b6F_o%TPU7Q&B$9{zq5yZ)ION(k=8d!WwL{f>|tyHRe16c!dwG{{? z=C8KORh)dM87a!09Q at jWVXtF#14jPinryl`eXScodG&B3{-eiyhI z at mOuS0U$3i%6CQr_vS~Sr&+Bc at DesiMkC%m za`ib_`(?4iXGgnQT~&d79eBEdH at g{3 at h^YJZ^!f0g6c5ekVVcq!u1D{d`YiaaK|?A zvK1b at --_-zZiAO(Oq8x%Kz-w at 7S&%sBmey4e>ai`ozQsnGHfoB!nbdM5wk4N;K$-r zgLJ{lZ^xUyeJwoiKY+ at p7myJ0kN+>yKJzUF8za1bC(el;+ZXG8&ij9YX$~TtES3g1 zemm{)J0eQ$*@9%=j~-6)`$%DEC8rcef?Cv`eouGBDU?juw-E?P#Ieb{{z%{ zt#84h0bi0E3+kx<2wn6^EtbF!u`af^`G#8{!qy?AD-)!@4Vn%s0P}6}GmJs&nF at zw z4`?1XuF7_l_a_oHe7B$scm=%QprRR$cNM!CJ(q|m|Dh7+RG18?^;HK{_~BAT2j2PJf{kY0|JJbD^Zs49$!y~Nzkw$RS$1WB-=2h+5IdC0Bl%|(N2jf% zj`#nNqy}b7;{E8!qTUh4rq(;oBAGvNf0yd$mDd6 z7Cq9z4As#Ml824fRTypj_NOjsqB{D~84S(wMM5)u7ehDs!l4^|7ed$h213{P`a at Uy zz6wqB^@hgzz6 at RE>kFm(&WA?%z6d4xdO``l&zFVvYg at QO@&gdTr*O(??&nS7O|YaD z;hn^qiLCnYaM2;SUpu2dywgeSzCBb;m$U|j1?ahcLA{C at H>7&l-Y+#_Xd;_10>-a& z7};`>CM%F=O`@AUl*T at NJ9?a;ou5QCNOll|QO*I&V at f26yJfueQ4a_JFbrHU4zk^z z+EnSNdg?Q&JgkP&U|Eyi1_|oarzi%b5nuHI$Q>@TVw+YOo;H~JzBo#1&5)}(Tjx4v z>lC*tlM(R0Nb>=t`9NGAvPh3`hPa$PknC`*Tx*!sUayaGtW_gnt3RJ$2 zjEAO{H?;EI!O4)I0u#s;oL;XL+RB$Y*a8zB7r)wRb+xGmF_o4!nDU>e*y0w!NXq8M zg(#FjlC+@(Fy#@H=>l&w>I)zVU8g=vxfMtlx?+?^$%{uLQvtk|*kd|@d;ye7vQ zfWO=>m)k=}(YH7v`ENPp`x!cua76Si3SgWAj-FNM>;jgr@}5zkRzznpWVEg_m3m$Yzau(P!~+6B0E{@%l6`v{jV4K0#x?o zl}gTMyh|O6;b`Hg+`^XMM?QfHmRW?Wyc$MMDIIKu77T+yF0+iR(tGQNSE+41(R-zg zgVvp2X)wHo9a-SA at C|q20lNnFFiQcT!K~;ZY()jx3HIdoX*b8SF5wQGkWvaCk~)6f zXYj*I=qk%+Vl$4B2~H#5FiQ)VbWF3imL?S)@5TE74U=#U9>ALgnole5+Li@|*E4_+ zyACwM0QImrDI?T}8uk$7_M#=0{X01HC2nX-{8dUZUa)!6Nut?x-emyCJCJ|}5WU=G z+IV&ihMT=U3h&@b;li4^ZuUQDj`1^_sm*74_1RS5AnyhsxgEf!)sREJjCe(x(T2E3L8D>E{Hjn=kSwIYI%by&3}V0Aj=t$1OV$oM$bqPs=}Tdr->GUS z-N_n`qLE4DsoKp|N-~rdnwkWCzhcO at b(Xdv3VF#3ZNtIgOo?@ORP~%3T)UJ^53uUc z_4oUVT{1JVZAL;t_Rh0(RfCI80P&ygJ}eiCP5e9 ziRZ05JEG=B^9ra3#4!++M^Rd-!T~vtss!W}zW$Uua6)y-wdct2HV)>h&6P?mE4Woy z5-9wIdMo=<#H$`+Se%4zI+M{xa9)rUa7s~`%fX5Rg-;jUD)!V5K-+F#@AH{mDwWNC zlB5}DY7;6$OQ^noL5}^y+Jycyf#L)ZiniYbd5SO}FHJ-39G_XwyF8kgZy1Fn4%YOn zr{z>s?^|z{Z=u!z>iC9-k$@$rVlNpnuvgig%%7-rhg{oj8{`|xjbvH at ldRK|c-WyM zBPM(M%Q{6k7sx6_6;o4ju~cMGak>G^8`gK at Tk+c6TJ1D)ymqoJg*S?vJR6gStWtSI zEueSaj~5FNwomnFHlN&X@&kTOeIK2#LDNu!3eUApnMuQkx at 0ZdROxa0V3u~nE1G<& zM*Pp!K)EoCvI`}c^=UopIS7~?&Fa!Jie{`1NHwZ(^-vQW=U`GYb!?WlSw?A4xi|%N zn?%NpxFptgS5;v~F_mpRfMf4Q10It6eZ4jsgmgsb`?OMVRdOCorr`Z#Y^s;F#6r=< z)Fpj=f{@h;XSc5gwx=)G!JP<~4G{|*wxOvSvG{I`SfnXQP3GjnB4Khv9HICC2}8#S zLecSc2*v%Tk%Z!=Uu%TI@}CI>8V_-yep4?<{*&2qkXGWo34QXX*d3Mcx|KW+5|l3m zm#@gp%45UwoNYj`+xmsV{N}kUjXIs6shfC2qZ8Vg{s{-=#(q1~1cqX(_RhjONtpXfn$LW~}?3axUchJRV?fttROi=7@} z-$HT_whdHmzN_GBparw`!;1FF_ptY?i55iUB%}qI8Z9U><7ZE4VAkG(tAQ4%QCi?p z2{=;{bVF at K3$UIaLq6L8(1O1PN)yl@Opb|SoX at JaZ3xx z!31g~;%K8HMtnv$t4q)c!DgdQmj{Gx`a{xNEtB#%t1i{{1&q0`EVrliJ%1tqt&3Z|vv zm$m`X+Bkuod>yi0QzdiC`A`e(1H{?jaBC*L>)Xhj((D&t5w9_UEUdJ}*|Xk(!E)LQ zajXMylQ<JP>EnmRbR#dKWiQS%Q1!TOECXsj2QGCu-2XEt;T zIlqBr%pi=x-6d5>2)z at SuVN{=EvOZfv0$oTv4`OP5#hFEXG3QoKYQ0Zh-zlpqPXg??rw;Sf^NO(@(QKJ4~vUT#aHI=FDZHBmVqDD+bWlA$tC2U8mez(!#}n#SVX{d5FO8iKLDZD1m`wSfy)ZnB?kiwS0ebdKsxuiProxP!A|&{a at mhGcIpxV4)H7 zYU(MzOm7}Gqv11XUwOBRLiJf+Dy#lW)N>Jt0^h==HkDbZ`n3_cwo_8=d;pJ*lv(=_ zENU0xVTLSrDP{^uG=R`+>*1xJKyY6P;Pzf=3uh1upoXmoJpW8Fpn}4(hH%mQt*ED1 zx%zC#1lS;@;_29twPy|D_`nK_OKUg+6(+f~mPl>(&<~W_PDSj30 at j`- at 9LQ0A8n9K zN>_8Wina_U0XDl5O{j`3)po1mrqUoT!#=w&o8 at 1OSsM_(8L&_e*(lMd$yP?!AEZVd zTtB|eZZ=4q+GbB2CEdpvq-Hy03jL+!lSE*~wXtwa^Yo#2SldF*Z1k`;U18mfxE`rp zecUbUj3EmIaL0}!eSV>3v3GLW> zT+{{1p;z##dWXswfN7P&31VX1VS9+f9d5|Pu>oXU(IpJJbI)MwU%`2UJ~7!N at G8#@ z9h8w%;@oUI>CV+1HY#nO(xFo^)8+4MNX1psk%*@JGDdnq=orE{}1`%caEZRp8d z8Z7YuYe}}oBOq)gpu6$KbOv-y0-b0Eid89`%0D^=S*+TO@%*DH^pz^4mjn0Q4MLVJeF#hTImL!%C)2YaL442=k$BG4r8g0^7*mp7K}x_ zg2t}`@X7q+j~U4cu&G0bB$so;fobOZ_$aVr^vMB~Ehg2$1-6l`!hSWdMD?v&?lX8F zBK{9;I}POGW5_;X^5 at SeoytMnN^E;ZVkOdP!(C4H{=)`?sT26vF%;wAp3%SZRgW*z z>0-MdCb#pB4CVAQ9#e;}aLj2}1$$l(%^Vim^e`3f$bwK)c+6>535zH05V0*U>DwpK zO|Ls&&}}aFI at wQ0M&1;Sj5yiuk&&Zci0)%S8RWl*DGtk+(`8a^wo!JRg{tBamm^bl z9EYj^8Im1GgozNVidndcE{qE}jyRe94;o+&_*SZ|(yp8eS=r`4#mN|{$Fp$})I87tiE(pNY!@SG3TQFjv2n2jVO(1`RRlov-Wc?nU;0dbHjU(t+-F-QA(JD#z%{4^pG}`o@ z?clnTs-vr*2=i}#E|jFu8(JFit6Lrdx}|W^1yw+8J)xq>^rBI?^F>Zfth-o7w1x at TO$8t%p>gcxI$;JAB^CI3 z=K3X;gwb?TXNH at g+kTEE(&BFC{h(*VtqR&$0b$kR99 zVi%I6O^_)^U1Z*v3ad(jYDCjZ7R{&jM^_qkJIDM1+eofRGrILb**QwVYFqv0CcUd8#;utw8}`?u{a^ z9DC_ at GIfPb+4|>U45z`Y7!-RXK7>;^Wqw$xh>S?KdMI7}IlSq6xkat~X1t1y;z{5I zaz5}1IUgXW1pdAB+e5!c=$E_+_{l+mznOl~BLRE28t4XYqk>h z;T2N4oBeydq6}gN@^~GikWI7LMIdPB at N(E|=x{8~eHnT#Q+iqk6UlwqF7is2puA1K z%YGQ|yG-LZ<9wGTCA$b=fGgt%Jpd5*1 z3wKD&B+QW*CtO=rCX9tI-tWPKp#Y}mf_KK=&B5Da at 5W$0yw}q^?xzQHVo?dfOn9%m zc%wK&YBy{BtZa?g1~q>ZeBc5XgV_HZ1_eLi at D4S;KG-~p-~TqSM#r_`5Illb-*;il zf-Rf|_PUW^8G-#Jfh8OS|BC>!5daCwBLroUP+51;D=e(LxJJmVySRb(f18W82dPu= zZcJudBaSQ91FZ(Vw}J(+`dfqFh`nbAr^0)asc?=sx$Y6;EOC5sG;3Wf>maZ_h53|V zCMEb4CQ!GcV-8C27fi5AlAK)9_!RNz#!&~?i`G$S?+{icV!sjx+;Sb4(o+rum z2Tm?0zx$w5>tyx=8yz||`Ele`3D+nAoOppJ&{{TQhDHBTlTdLx2c z&Dd7J`e~>Wv~^Q%i)Ne!+x&Bkyu1h at kKa=o(M(AO{Mck?fV{Fe*_4>GhAHht>4?`E z(^ML1q=fC1j?UrfTdP%YHr}^Qj?DpEn_yGQ%(kP#EUj#8JAc5S`C$<QR} zc5A;|o7=WqTkW=$XuGK(Eoil+_RrEbEYmxU6)N&ai1$0^-1p`W47%UX at Au>LVcvW9 zoOkcJ=iYnnx#!(`j=SeBX^Ok&Zo%^`z`CgTT28hV4QID#tpRlpEK#lw(#-zw5AF$c zI=a%N*U}_grQ*SkSLuxnSoy6tHpCeJpDg-N%jHF&b9;pnx at oJKQ1>D#m2pa$#ocE0 ze~b#isM<3>k#FbSiP&47P4_jiTpVm7;enegYOYbJUv6rxAonA0eG3DGx-E!Xl;G&+ zg)_>#1$(M;AdtW_#@92uuuZI9Pd$Pb^m{$O2n|Y=WHO8+m5Sg at fYfIR1>Y!fs%&PoknU#p3U!VB)V=Gx*ycDlG?M=V#JI#TsLkyp z5$*uY212kDw|X$#(2RP|$JC#39>R0ke#ZbcnjHu9b(nLTrK>qjO5vR8Y6fLV*twuT zV8Oxj6sSN8`Z3Y`6zE|4LrCMrPaZgbqeX1JcU1QQ_kKh7=b_4JgW*x=5uYnPvMKYR zo7&n?Z42uTw=eZeZ at hN=T2*%@yC5J2R*g?&}FmA%W!_B(MT;3v06sQVimr=D55d_jVjh zz;X2Xt`HS395KGw}0{VQIDa$#nzicg+#`8Oid|p|JYX-+-ot at m-%61f4 z2F`D(($iFPtFk3*+SnSa`tZi-ip5p9&+{Za6gUgmn_D$0D^JO$L at 7<(@??mPqE5CI zi`b5D8_MM^fmAnXZz^;GMx9m(X-(5G3UyjhUKpg&>K43V_mrY@ z7)mQwXu^fXAodc|2(RH7mJxZvA}{Z39K0;o&s$c8lM(1~4cv z?yH!(S=YY#SNCnf9Q^N*N}es-30L~aTWu?2vsa=3mHTmxBCjuFF5H;%{~>m8DtqkN zNXjN?locIOG0NklGWMqvXb}V-+=DN~nNy^bSgrR-AjYM(mTZ29m3SlFVg3AQ4% zfreh?Uo5KrotkH0??kvli-36TPd)XDRVP=JZjCI!(#U1>3RW0xx};U83CDH&hNa5rXoV0tOr$d7hP zF*p<^;+h_<&`G82AN{Bp?fn?=x(}3(Z_Iql*s zWT at an$2PDf!H at +c>}Rv$1E zfa!s;+0|A#30;jtdra3rvN_&y2ufu*dlv-iGF3%x*Bav0QdUWYwCD|Ro`HLAf<}?FE9sjs-5Zy4wf5BQa(`fz93igL}6L?(sZhMgNOr2Aawa-J}_f zBpcg%lWs6d#KFD%uY7M_Tq&#i1e>|QhJCI~J0e+NRp$B%joy*U;*^Y at g<_v~v8Cn$ z-05OtM>44Uc^&6WUeM*rH4Ts~=a5zS32APHDJ-OlFi3q`ENt2RXrjn9k z_R&WM!{l8sQDIYG1f at 0V7F+;}gb@MlTEP@^jd^lPvCk^J;c{9(ODx6tidBHSbc=$KJSo7t_wb z;8!<;Qj6Q7v=pHcXk+c`Q7001IIQJzth at b7H;b!iQLnXZh*uIQNP9xd4QyX_$Qwnq zRh42Z{COV-Gb&M*Sk+jDJ{FV%xEph%(AeT+$_D;f>2PTDZaUr{;l55OO5!sd9=r4U zQqe7(ZzDN?BM)i58%euOhhOwJ;oUL=Q at 5nhFZ!_nEh>%O_}j>tvE3J(*Jj~ql~(Bx zjN051`F

    PFA>{i?$gmxy36j^$|Yv43G$2O%7QW z2#s-0b^%9~PxxOH^uVqf`1ciM5spK7QbyI?Ge#&0%2GEa( zcHDi7g-6`9+-Ri7%cM2#z5=0++|u99nuZ8y?0ARwY?jp!rI=Y z^4LJ$097uK?e43BMR4DpQlh(Wy)NcMr(u999k31f=*fpqwcCj; zLfrs85Uae~3*jPEyM*kJDxDi1E z$u`Ap}0biWa37}E>^jbdj8WazX za4uvOLxZ87M$~MMNv=yH>4MfV49fb!Gdh{PfCkFqT*S8Y28lh4=HcPkz&YID+Yn-d z&3x9J?+E4m^Y}rue$pGkhF{;KvBAB4DeqV-$p0)N+>YH1ZybVWp>Zf5W>Fe7zr}p} zStmZ8e_lElZ@29Y8G}ZN<5VLu4kW6_jgkm zcb=k$TY2ZLfrolen$Gbl={#8J=pccgc0rSRE<`TUxOej5-{wK}O6E~7V2Ic;HJBu=?QP0Ase2Q2~&fp36%Fh z>JIo&j|kQP<2Wfa at 9;^-KO$ym`z)xvX1UTWC-~MI`JAu1(tM6X7?k|HIhvc~3OW9@ zih@?hv9v&C!xN}61eO=%TrTI=?U&{@jI8agkghJ6z3*O2Lvz5=u&ZI;?7izJUAAkW zNoYJHH15TXMsZ5p>&E?GH#4(ue#{|j%7SZUcIE!S`9kCFhP|L#AC7z72*CYcb8tg! zPKEqCRDveNpsGic6?IGhOF!xpNQQg~?=G+k+#^|DHx3$?^G at rX#x-Mk_7={k4aPx( z>4G3u&IV~|&Qj?{-f1?p(Ky9EEltvUX at XXuX`rQzCds?$n;D*K2pfA&_McAD(y2^; z%-|yb(ixnsc*)Xv?pH8h6Q72S)xrEXVE%Zru|Bqds|)^jF!;I$hme0~e{g6ynTyKI zrokoD9W{sb<@0DP;TYFOjZmkCy0>KKZj14(h0%W$_ak{o0zlCROa@)U)2HTmZN?6X z$+I`ZTc<)Z^b|gvt_6-`$KH-KCd+qks z1haVO2F#V-xm*VxpvBh$uCNDI=3E4_5LNz*WRudP$@foKcL%O#LEbL#K238Np^Gi@ zowVFJe*&KnE)2fVivAxO1ub83x4eK?m2+E_N7r6+kvw1VAhdRa at h&+_>1l`qiRX!j zz7V)fV-IJ{BOSDnJGrzZaH`bFYB3y33A?X at rVaOYR3nVA_}_waIeYgSGH>%@E>nm( z=*TsTDk|fC`P%JC#EFX(pB-t!ZQWz_#014diDazCmv82tx0kcVte|`4p at xa4J~)SA zq9ikDn26gujA4SCAy5f;va9H%M4+uieiQ^n9gE`!1+4D3_(ho*M}Xm zjndVUmy-P}$;?6e zaV#1t-a|u0fl;X2f`$rBvg(Ek5&&KjcwU+-z1wFJSTjjzR*QQE!VMIf at nY>jn7Lv* z1_A(rCQ!dPwrY^M0t@(mVy;-MnJWr(a|M>Gba1iYCDEyyD+)AoMaMbJ6+Y at 6)6jaMsGG zsFBeEVVcnbZ;e9ZT=xfQ-tDM&x>Ynvkq5}| zaUL2zP+f|_O$+KOp^kQCJglJEL;XojzFS4Jhk6$%mN7vZc&rDZ?p0VM`#(=WlgWyp z&BIAH5A3H#f6-u at 2TGN5+dNL3329Wh1OF?V2gPw1-sVB^I>?g8l0!C++eZviVAn+2 zJYKvdX!Af35^nRrVfnwZc_g3F$<%EgxBeHzR)s7R+Y-)d^T3zRxegD at d1NT(<%3N> zcSPDe{;=}@*5*OYAJyg&M$yKQwc@?OR+vwF)JU6$mg7*H$5o+R9*Y0p+dS_2Z)_g_ zTVDSmWb-&V*yizLcLcAmS~0xMgLOyPJpODA4otzbC{E|IZu7t%dp4WL>(2&l9ztBC z%>&0Cw|S6g#5FZeHAW?jrc%x3 at ifYPR>W-{AfaMa-^|be9%}x`51BtcVTMTa$N6TG zO41^Cq}fB&%pNn{X!1BgCJ$QTMKyVRppbM%!$+$rj75LNTxeE>9(-w-!Km&bvVx at R zZ7^wcq!r{7wv?$qqu_iAe7I7sL#0vx3^W%Vlc;S0q9< zkdae|+CbK7HV_xuKnm;jOY^x6WX at n4$dq&2KzJKmxj%3LzdM^f%DfQ zR$eUEK3sPPRz?|*OUW?NMj7IXLBDx$foYw=k)Rnw#tbru=p}4eL5f&C?sz3@$QH7O z;NbGV8nlMM8tLm(WDTKVC)7P>3G3j6A!`Uu?b#tqNu(tt%^YqCK^w|YO9;*5A>sL7 zG{DR-bBJ>w7>!NW$~@@q2bp}28`kc323O*ao3yq2SJVi1%hQ5(ki9gohQ8+re{424 zx0}6`gpg<14g>^>Y zis0Mr{B7x0&E)btqFC4$9XfybOXW(~#Hz8D?~Xrtw`6r;_ zxbHl|xbh|j6e=fgLcvLa+|C5dt!4u=->>_g4+=N_-liY8ShH)AF_6bTy)S5f=dVbK ziqEMFlt7w7f(oQbAi1n0;3;#m91Jp4!e;$2*p!1R3NuXmFHAW$YLG&OzTS{2C&#^= zh?2)K$9;nj*?e%PcF2amm%u+%M6velzBp*@p)i!CEVEhL!sOhH)&=)~QI7AbMMs84 zd4zkwB&T-e&NoV9Tqb4(RF_fdVQLdUdMKrqvQv2PRFmg(uRRI;2(Z!v%S*MCUEhQU zZt;9AKUd2S z7p&4ab)A*O*S6W5a`feY71nucC+1x-Uc02M?1a_<2??O z7|a0Jf>BIiOyI4%o&h3yxFP5 zsx#xfzBG7LlUGuA6Y5q1KHyQRWW_+dP7^xBTZNtQY2p at TklEz*{tis86p2ZKrwYrVOidb{(xtA%rA{xw*_a4qk?6=GI*=O0Vb7-Wga^^NpZ^k6 z3r9AL<~a2?3Nw|F-uXh7f20}v7j^;Y%FsV|(w8*qSJV*rg$BQ5X}zlmdKapgfmq&? z6dxwLpU0vM8Pqp?oO=(zY2GvA_G4UYA$@Qn1^np=} z&I8bpLscp=g;!}lRVgQ0l?s$62+G at 1*m_=GUZoqVHO5WVGPx3OuJoql=DMkPlXj`} z+H-R^QJ)#W`fd5|>vyYhX#H+7>Rmgme%E0AFscewhh&?aZS)+&fnMIOcc0A8@*d_M@!%etrL;F&y at r|mTI%c(Sh-Fb_czmitpdEMtA!Y zuqi}H26dtpsLh}<({}+XGoUc!qQa2%LYTrZi@(dptqE5co*t?&*w&E3aPsa*g`wuQ z|5{mY8to4q2e%xJrXQ}{pM~gG at Aaf?a!M2 at cOopJDnwTQo9V)YhU5c z0(bA&^=5Zdn$VcwyKiT{TgAs_3?FO}o2AcJWHc`y>Ub(M4Nn$iS6Jm~EcWh5w^NVZ zst$HL1%;~*(DBVOa-JqoHrUubeYWp=pFh1JF|J zWLLa`?%}OUhtL?uQzpJbdcgwm6x5S{~B5lv}XBofSM(YO#nbHB~HW at 2@qD)p?I}uYk3#p at x@y7 zU9Zy;<{Qh(-lPf!k9gRs%;XT$%6wEM-D6fT*?>FR!|+{3^5GhR%+o%3We}zbQ?H7| zq_md at V_GoP7Kuq|4-Uet!W9zn)sc2Z?{b|nG^V89uJzIXz)i>J{=V4?G zJm>-I3Ji%+(c`V?2%xnzO*+#Mn{$hlowHV&nzLS-$UbvL4*T1et6F^FHFy-5;xP$Syr{Uq{9Zhsp{SWl% z6^$rvmd1C1xY-D)v`|{$W+~EiH%pKvxtT at qY}TT4cs`@mm(AYh=%LfcAHh%j5*rvGs~1}EGg%iL_FE&ivsl415)ZRFY=$O-K`w}|wgnbtS9Hobn{Mw{cY?U* zp4tOfW8x+8)%|+H#riwvZ7Q;%dWbO&XVJbWT`+$2MJj9k=(ZMwYy`5a< z(kja?nD_QKYW;#o#&Nfrb(Gqc7hwi z;Z}m141o(>aaE}VZ+}CFk8!sWod#o&rmP9lIQHkN$R3lqj8CN#s%njVPlBU^3t}f* z at S5&l9B2PD#gW8a#GrfrLK}!-?^265#kdrE(c4rrBK zg7RHI|3!zxY|c{lS4u7j{1U at w9|=@7A2qqMSo+Io#7m at ub(WE#b9xKOtB+#9qj>D+ zNqmG7SRRe%@s5uVJC7F_A3U^&4(E8$Ik9+-Z3WE5(wI#@p+4hXVezi8dMA2Uq`I%S z2UUp?*tgr*UB5 at iKg62@KGY>jO3RcR)9uRq^dx0bddiX;oW;det8NR%J>a&6x4rYz zt*g8jVG5wmP?lN&durxbWsS`}Fd&JL$4vK`0hp#wuAAnYxz4xjb-OYGTFd=2i$Q*` ziegmEvoaTSq&Mk6GCXXAhrp|=9wFD9?zdA`VB|{l;hASaKN8z$LuMwFXH^QVnY-DA zNh*k|suT?Nw#KfmNn&$VnzJhi2dd#UZ9{LLElVI9t8%G&PpW!Pih9o!maHM}vKW?> zmX#>qW;Q`D*^iF<)qOXU1Icfd6G}7irR at z|S_5T69F|*Z|5^dwoiP at Jd)2hOWjy%ep!g zcBqv7l&WqI%K9|am1LxA^zD&4((jiB>AD2y at gXI4jS9$2Bg9GmwA*bvp3nqo z2p)iaETYIkhi~OUK0Jvg at r4^nkxyJ5W%MNskSMerfM^J4b>1+hMs2r zZXgOK at x~5yopxJfUH?%Utn1CVfB@=apqs8wWR}}>19D(SctNH7*z!ZX7_p_=R6l{Q zr}p2fpYr6sla~kc4*I5wtQuRXhM#>d4z^(Zt&vnF1#|L$!duW@MsJY6jufoRA{L7)m#j(h z?X3S6 at -?|kF_dvcnEzQl$Hm4&{8V=}RB0UBdkcSSI%~a!&iZ?;fyuz4Nt{I~>~FV3 zvPfK_S1i2wQ;#ob}UJvE4?v<%f3TOWA?n;_>Vl1^u(B>r&Kp)>3xq zPTC)M16Lxv1sMCQ4wsQ+%0%^~tHAc4e0?cXcW9p-rj at c&{C+^1RLYLQeREGtspiF( zeG1R+_KD at V|1qvyJDb~(Ye|1F=RrAc(_)(;&0yG6lY;v_dZs976u=Iz15+Yi>@ z2EX!hv0Hc$O_<7mGQRZ9v$%UKYuA^t6#j( z_fuIt1JMtRrvqXO`_BS$BuIVF%C at Tb^$=G+2*LPBN|AM2(M`Ap zGfI4Sa$b(Pc~h3tfnLBf_rHlJ5h}9_Q-sHNDZ3(khzAc$7v`9E3tRJ&N=k*T_rzxI zFZ0c}rg*y6jmIdVg*LHwZ9Hf|=Fh~wwF&v|rYYhlYnkT$eMr0}*Fe>?z*rtjYBOp& zPWN$ZD1cN?=D(c5Xi;AB(uj9e23Qrb%Sc>e;G-o#*X5Yzl7(z`AIq6{F?(zoi5ttZs3jEMAF$UyE$s#VeIU zi at Vn=*{_-S=I5U$iLbFaz<4RQ{FFFVOvd4 at xU8w7pDIc<~0c{D40SgtUm3(EGgu082*b3f4WQ8&ZIkZ}} znQNB8?CwTuPxexabl9)b_Y1ZR8I5CI{8Ea6>d155bKV9n8RS_mV^!(hc?LDvhW={z zZ-i484Eg5anS~s&uiEb7z6}nlhG`UcIK;u1I$7e0E zTe`E9t$-)$a)ISqf7u;^FDhl%ARN;JbJbbcE7=Pn_|#H15#g8~n4tB=`Via(Y74As zsB at R=9S!}exvSe at A+IbsqU;LfLkj~JR at G2<>oZEz+e>1~L*=vuW)0ecWTZ?eI@ya5ymCFr(~rChRzkX*t6aazTeP=r!Kz>I?k`W{ zauuWeCX#4P#z*rz*+qw{$0|jKP{fuk^Ufb-RUL-{2icoaxNu0;a+#>EUsa+mX)h0q z#Q>Pq2S7X+By7ItHZOb{Je(Gc`H)_ at ZubDkTFQ;Jg%QxZ& zx@*hWI1EFjbg(+OmR2G8 at LsYNef+mb@u0S<$xEI22Ku5vfv}R;Yd7i}s at R`z#7~tt zg@&e#O~)TMM4ZQRU{rcJCG()W+GZ^CdN4SacMAqK7Cd-FvV^`s__m|#C*^};T#G-w z0e82_b|-x-f$j?{)Kjucj}mr2H-Ey)OIsLi!93Ya`UsNZ^{i3x4=ME;#TNO(Y@$nwD`S^f`A(*w zAGn*1_DtA}@>6J&I~kkzRLDyM;118b^a6umhL9jU_J2&i8=#8bwal^%trN zWboVi2 at TvOi+KiDuJ$y<{ym|~Z)%x3W5I$=>PPTieeA~11Ahf5I3c6^qtpfe;d#U{A at i0+{t zR}J4cgpCQsuqlh;eO~6?U^mO at N^a7ew3uIwm6GRNh?kLbCgCM+jv at Ccqa4HTIE|_* z+VH9h*W-loHaR%g76;jLYSD5U!yc`GvSzK(7CAf8m%!36HYaVpwXR8;=24~eoJn$g z<{l4jA5wa0fBR2g;Tv^~1qFc*0X41ww-L&xS17HpLZXZ@=c^#+Qf1b06YxJ1U0Y+| z7yq-+!E)wE#s#J9epnQh`=nSSz5cDsvY?Eu{x$DZ-Z>aE3(9|&=TH*JFJ%jHPt$>U zwR7i`OINszC2Y>G^|O`I;?fc)b3CD+pA5zy_~kr4CA3-0r)uXKmcz+S&0tlfmQTMZluwY at 1Mpp+teNoG^2H%>XJEU~qr^%mr` zRf at -{#$mO1N5gQfojXakV~nHz*Cz>&Hx-~ytsFJZvtP1Ouq^KqTLYcBD`1H)>*ojJ z&<{H3&_%X}Sk+;xHx at tvP+Z+X=}HU*F27jYmxkNQ;^p5%PL|eu)qs5vDk{|Bwoz3i4{_E|YqZ+KX|I+C+*tZlhhR zljsayBAR=l8Wa?+f1ls8M>=mI6>eIV4;9)YpTN36lS)g7Mk|nTT~55Tz;jTVBkX8$ z0`g=wk;P~zW&i+aiLJn2id%j5OL46x19A*su+!ObsLAr1 z5!an&P>sP at cs2@PmVJTN*`K>fReA8&b{M;*CG{5^vCY#$zi!4c;GK1V2c3(9x at D!v zX0P0j(cBz8&XN*ebtg-}eYXw_!Zk<50CLwVMV;!4XA#8awO2XWieHhf z14Q1X+Uw?lvQo at o&yRWrh0nc(LG5NWnJ^G}z#L)a+RT73q#s65Cs0?0pJ_l=PE$X@ zpm&n3Ee0{@OW5R4l*a^@Y3Xwa2*mIldW?bx7dm2}Ebv!pA@&Y^;Hb==D2>d`t;|l5 zd->(0G7C4;fN0HVE7{kR>ntlN at j5!yPrQyE;L3C-^E^hnTt7Tri1S2`QueR$?u at KtEaS#T?k4xFi-IzS1mEX8(FlO at bU?$4Ba)MN&vWr70TU(Bz^>DlM#0K5() z+tHcn=*a94yXCkY*F(;M5uQ_WoYLCdZXeO%r4ZBIpLl0s0n2f}h5MqJljmVzYqD-6 z at cj<28q}~rU})6W0J{v~M*9kXtEz?KtMKpBZ*|=15g*sXGRY%=o(T`PbFd68$Km#1 zvcH7v!Q)xxqKL?TP1mSeWWSH`RZIPZz&pwkyZ9m9?sHcssYQX;W+VvCIo7aT`13nnC2i=%% z!4Fg2yC@`Gj$)c^l&2*$Nf*z)#VB8ta74PGnb~LOndGsMIBNDSX4&p;wzzj$5{}6G z6`1>49v$Dbuif2bZ0X)bU&m4!OzvGq$mW>4*$6Kk>fVKmW9g5T3IH(w_aU_v^Zys* zzunzz3e at v{H3#PhgBA#s_F3Il22i8EVY_cakKgjO9K+Kk<&ub?uW=G~hXvOiY z?pkUtYAo*zHfpZkTtC4eI}=cZ;fIPiY(AU37oMRNpfEebm{~Nmr0g=*1uLW6a&Ig~ zr at Tyb*w)3kCM^w2D$`8soj!d+)fBG$9BuDHD1uut>J#FZKvTy;qKVAoKvVS`ou>6j zlL!OQ)Z$A) z%78MsG(;QUaP}vWm*=ojNi&d0`qo{G`q{Egs1K3HPwwkCmE|ss^r-uuUb(>Bo$3Py z1MR+A at d)3jkA_<5Jy#stxhCWw^vfTk+k0nj!qsOS+kCg?a`agw;WJp)Lt+hPfIe#b z(f6=b>_d85fSy+iBZlA{PL5YT5?Jq at 2vei@t`whLVP79FzAGo-2ObP+jjIG`-CY1Q z)sMyfgV+8 at YY!OQb4pn|a-2f5 zdNV;Jh^@TEg5H(i!LC}{PwZ`n=cP_|tq(iy0++Fjwfsr%BCYcIY{P>{Xl zU#80KWlnab!YkLRhf%K0)_MsqGYi-|xR&c4;I;hvr)ns0*`lz(FSPZ?TIQ|z2zcbJ zX!lke at Kzl1%5Qipwq-9*66(g7F#wSTX4EvNu(e=DmBkJ#dY|JBP*SInGv*}RY|>_; zNVr!hxNUYP?(Hb^IzD2R_zX)rAmwKLww*cYmNo}?9S2w*RV>}>IFw!Skx;kML?H)- zx_dF=c8gHAniATDx?AbyfKXSCdzNA8oq`tZL-iJG?i^GgHlFl3m{VP6QIkK?P6SM+ z5Nj+(`1wV6Saz#}fg<5`?5(*xtKxfUiqG*wgB654te-ZhLgSvm2*|J1BBTk8)&*j3 z&57LHtfi`a5O at iS!8%I}7UQfk(B73pUPlw^?j{VV@^%^)*Mz3BqISh`2(fpf5v*)e zGpa4cWx3jW>yk>?UJALLj<5JAyw(BA9TCf%@HQcvH00+($SVo?h*I6|tH+gb=6-ke zUSp+ql(OW2x9Dx(Be?3VU-3ZwO%K$M^%lM5Yrq6=(eC=OH6>W%#lE5+yhTSEM$P_E z$`=|JLZ$bM?|6&aAGpN#i$bI?U{;FWQyuO9z+EMfb6%de=sl(Ah|n0HUDRIl72IOd zk*so6-d2S~`0A0=Vkay4Za{TC;QKi-sf^8sN2nR3)ME-DT!|?UHPN<@bQq=AfiiN4 z9~H_~9zrKrmk*G^$lrsAxPxmaRv at Fz$v&Z^z1q`m{65u)IkD|Ms6*MIKX7j}UMfIw zG6^5=ahPTC~Mr5-Lof)74BOe?azySt*h= z7v`fb_a5lBNl>upNUApGdL2odkJAdoB-FiZBApCSFc08PH_N}s8mh`^eElNSJpu_e^IYwj`8_RYV>ItM>k zuOH1GHv;S5hVGTxW_S;}QDBslUD6G`6b)}}hA+MV5}K^As0o<86`k1?okHDQBhB at l z+)9KyhtqI5Bh-D3U3C`nq@;u+kZtD^Ww*De2RC8vGVr~NP_%Suc15aC_bM*7ic*C~ z{!AkT_fv$w>3cdIop&dF}?8e9Wd zikmXK05OjiMWHhEHk?#a0u;%Xl9E8IzOkdHv;-?hCnjK-Rm%Q=_A+>vJrzgm(sF+} zHBG0tq64?OQ|lyo9oC4ZLe;1C_pmzmI*y}%c3e_kh;8gh6Y36<3DH-Sgoh)r-Pkj~ z=LSSaC)D60W!4d5C~(`UvxSzIkWH5#cb(SEard;Z&w@(oT-m9D80!a>^^3MR;z}EF z<@(b at xI%{}0r3r}Y)Kib4A4>$9=Hv#GqOZWW>?@M+O-6=NO6`SbL8XfyJyg5>6OuJ z+5MmKU6bK;wmueZyW at g;WP&?K)Z`;6vuCyK^wo!ppD-Y=oE3(DN;h? zHw_!tPUF`W8ow#}_r4DNQ%@)HvLkoMQ;w&@HU#`U|aCdMDgaU=Fh55o(=X`Hb zzjsLw+J4=;fgbnmorV%nH#x+<7xgTzwT)$j};N;z|sqop}r zmj%(jIU39}-Ra5*rvF<*p5k;(4JK~W5~n&{mj at G{(-LPmUDJYz4~Mdy>2ysGrmxeG zQ=P6E!Ngm%#4M+4elT&7mYCyoIf98-hqBFex(b5n6E)=dPS=89VuF at f=yVkZ6HkA` z6BjvM3xkR6-vqODI$hTW(|2pgH#%L{1ruM_5|=t%i-L*IXo<_5uA*R~HZ at mD6>7FmaidSmktO1rrx&iFZ0(*}=psL)orzx at HH{$7#rt(DL6)U(nL)DLog`OVG^69 at Wx+LFsux z{0*TZ9wktI5LBVP@;If>3#L1?^d~8ON-+I$E&X?terYg0IaI{61eyrbme&8j=CAyb z($j+JUuo&+XU|z>CWnO at s7(XCN}zb$#8=USbwu|)fB9M~N at -i+#lt>^o5Nfh;1-BY zwCJ+1Ct#MsOGn$Ak;I)yE!>r_ at i*BNXs zU1zeZ=$gu=(KU-*OxGMX;W$e5Tyn*wvbC at 5=pIqongoN*jzhGd9|DvLCQbol$Sh z%NiwrxBTXo98vC6ntf}G4HN29l-4Y}d`kN|#ygNSONkX at Y%n#U_Txknlmd$wW7ksV zQp!53I4g-#O4(FQ37scQDN!oO+o-pKdFA8T_om9{XWyG5pXZhPy>d^R!-|>vXXDnN z8Ni7v at 7F#YR$IjZjLDnpUysZF*U{&m%U15PoO+(^z7PE^l%wv~Dvv-dwh^?4^1wdt z3 at AXT`=^2IF`MtxER(HrDrilJ_pl!)<{tJC;)5dRABSr445+KH^=ETST_ekU4(2jK zRoijXMkh_5f}SWsVmv0o>}jXjm8VapKr}fc9G$o^W;+^0-S4Y`he3B#41x0+thK!} zHlA18oBcpyt$#+nH5XQSvOjQjZLcVwQaXG!#s;B&q|%KaHctk=QWB9TXlu19iO6Yh zp+!kV1|!o7t)Tg2?#Tn7qaXJh!i}4JMbF~a1j+0K70rzT17mhN>61>1`ueNX{~1t6 z%w!KT;(?>z%U^f&cnQ(CLfJ|78!VQ3`BgOp4ZF5*c+NyBL$IrSu)6lq4}G zO-u3floT;0T}%0tr=*H8Q?!(S at su<%W~!F*I;E^j7iZ1Ty5i#1Ayh;4Fw3CqDk z0`1-`$V{liV?Ka#$$H%;E{`f#}_FK-)?#ML`Zd=?FZB6l9_TbFdh){>D(G5HJ?(xi4fL#HJ*`qp z12t=0sWz|N5X$mWr)zAf%RrN=sG(lwbls?gLS znV!rJanxx}*A05wM_Sr+r>jIyYdXY-Seuky!k)&cjcnI9oUQ+$Yd?GK8#0CYi}Bm; zywu^x-Q;1$9f+45H1hgRJ&!vzWNQq0`m`$X-VyM-(Bi$0B92=@YxmB>J^`J{h(WGm z at Dzkmc?jjX*cLR2DKu?E!sL*xFGX#n;b%s&8);DX9MMN2Wq>1*Ui3Z_HViYHTG%6K zm at 2$eOw`r}iL^E-#I?c0b5(V74z3||>ll4ANBf-qX)t9*#CM73C+pvJauoWeXsJ&L ze6H-x8Yfxuub1)j^!E)T>l5+|X1^<$ua{4WeX_kih3%Uj`p&my$PREim(DkBz at M_j z=38iJFeNle@$Owl;U!CY-~=$%y+?&~ceAk}mO!mW;W_sH zY#R$o%RrRPRU9^R%TpP@wIkNVNTVnlrT<9kW*Y%bO+-ap{|E@<6gctpYD at 8OWE6p@mmh})o}eG zTrqN7`k)YoPRrC!0aEoct}jkVT)OD%d=$PF-^EgQqwf_e-yUXNOf^692l(uN+Q50b78K1ZDs zhKdc{J9;;pjyfy)^*=rcnNG!0)7vhVlN~yJLmr+hCW8NQmtHitCF?vg_ zfU7LFZZkj$lXr`|g}P_XMWRrbf`0gT*?HUPvndif9SB8BG_-N{a=Vm}h-$63z#3SP zz1${=fILB`X`0IzNChN$CW5AGd7XYstMY`BGUa_1_)#000%nZ6v6tiCpCO%yzB%kZ zFl;ZP2A#YpqCsEi5AWSWs~Oq5Z`KIBQ714yyTC4kQW2QouCW{B8SWbBb(d*a({!w{ zPOL_{UJY#+q#(zK4ud$Y0 at z==?j~2U6#CO;%&jv2E)N))q$a-yR6!T8$QJBoEl}9I zfC{e=_V}h;Z-Jd{)88K7Erq8sUmMRCXyQSc zN4$uwC|O>J3l*~}lxHqvWe;Wb7|-hPGhtbUk*Kef*dNf^Rbf>+cnf$A@{SD!`nThU zw|Tj~8jE)VZ5vF+??yht3e=L#` z7~NJ7G3}(l%tPhZ{eTnyyY4`3_h;kxOnz4xV0ZQM9qd+*$~XIMQrVB_AmVMh_tQP< z3&PemP%oJF(f3cZq{L&0$-A9A=~tvwV0A`UDvMJpy;iuSR(cCfmEH{&rNZtxDE(BK zgFX1oBrBd2v&t7$ZG*YRm0QBLuGX0`N#BiW9>=%Aj{mErz*Q(0Hq3z1xBH9p%GrTN4|`EW at F*)yN7?fl)qhUj0VgG zpb3Dc;mS2bx#sBQsvuH&{L9hLoKZAM8-&IVq0yAlA&t&#@^lHmZ}QDIpj&JYI^-7` z?*St6jZwg-;s^|6}t1E-ud|=G$~qY*8}1hi8 at u;KV548#s6*fJa6FXL7IrVBsvJ*oYLn zm~Yofu}8`5XbfcrojHG06mS~{p9kRcqJUrE;L!jceHKzSp+D}tBr!ipCnYILW;gT9 zk^!6?1)RgdV*orR3itvJJ|Dp6pM{hz96os|Vt$HFN=lT>_F5>ju>c+$1^jmo9tYrY zQNWLJ at OS`^KMN_ViIh|^KUF6sHA-d~ zY)*6UN^}2^=2p`L_fs&xnm;gq>Q*NTKi`So9 at Dok-I@mk9})A9NcTgAM`zJ_`664*mhaKb(b> z6e6WV%4=iqNh4);0>CGtfIsBmlK?&$1^fmFp91iyvyeiYvhq5`{7#*e&M2Av zglBddz^9{t3puz8z+F+mmvV47fV|AS7-57Fd5&uqA{d@%nT}9A+&44+jr7mN#;+K9+|gWeJheE#`OYq;yBgY&y at ZXPB{U=iuSS@`-)| z>tlI1QZR_9lGi8Z_vxhcMak at sJhOgnJP!tYI9MOkgTa*?tdHyANV$g4^f4~fO^4@* zaqho>i2X{;|4JwJt0={xhjb|JYi;-s1|Q&HT?7mUzsbS67#NONT$?L-N5%Z3G~SP* zc!-kQYMz at u(+>tO>N~4AxV$ey91KTGEYb35LHq$TRnf)+~IJoM}S;fKmXClPGaHMpgRUq%An150yCE85? zPA_G4Y8Y|wQtw&C!7q9v#KCZ++)ku)iTPbRDbZ&7Yj|ee!-#{l-m{7WV{e2w7><k8$Fa+-!S6fiJr5HgLOR-;$S#Zt_QSAC2yco%pVZyu7M~2cck$i z7V{6&s5%U}9F9^zGB4n(VFW-|_gMwNr`-_(U^wz#?M6<0Bj$gjb1Isq- at r2)PSaoA zefII+9WnlgBjq9@#V_XjbyA{f2WnS at b}(f8cb$FwcSVf<;Yj&y7n1UwnE#zlN;K_2 z>Wa_~hK&ENvycC-i19xhDFTslLd-v*lM+ok at Sl#*4u*{X(`O(5rz6JyaHQ0oMp90T z`KNVKqG<=qPe*76L&pElR at AEA*Jor+c!SS~|!>rfy3}aw*9uLp|_-mfw zFR#H$y)n=5;9v3#)8Tm{JR9J-`^7xNA79BcJpT7QgS;ira3?&Eh39y9{`QSL!{Hb5 z3=hAYXQ+8K&#(fXOX1lB&nKabkD!cq{+ws{Ih64ecrJuzzC{B)L}DB|gHZQPvcXU& z)cu=Zp5&K>{PJcJp6s#VM`c&qP5!lL{+Ja0y2+1A-Y4Mnxdtu6aZArN zXJk-V69Wh_Q4zLrgjhg`jf(Iajt~b3al_KH7G?b!t9Xx<=&=H_HEM1Pd2aE55FZs` z3P(r)goLOFaU5X;AdDE6p0CiZu*N3dV;yrexr`!%N*rVolDbH;bAdQNOVC4ws0m6Av5ss0KVa;ej7(FaK zc%)calO*1gMEpqt~**bBpJ>jRl101CWtjW6d}~7#9_xjU$W)gz>}DgPy{bHL2n~snS|NP6g!DA;_LC zxf*~M0Puonz?A@;0Kf^+fb#%25r7kip+TNx-erC#CsQ|9u>I&Ld*+5$PVG5hljsBN->@OHG&lrRF4L_A!(OtDxd z13=JtijNHe>bzQqJ0P4)EM`(QCxHQO@}P_a&tfuotbqkku|F!pC2%rEJcSS{5&JjQbD()VZo@}D0M=b8q+0zp>vr#-VSP>QX zMn&i#gToq7f{M>XMfiXtfErZXH!L}SL8FATUo7s&FQ!ONKi~>sxSsv;RgewnLB&4~ z1%Xsq13FOg0DwkEfFz5uD*&P*SH&Z^XEA%;>@P{gG5xhz{I$-LucOxJN3tlaIid~v zp$LaKfVX7(jn7SkG9UE3yoPR?Q?r%NpEB3aOd!Xs*K7g26! z5f&DX(1QXaD#F)fjVSI#fiWySJJ7h|JR=sL(b*GSarkv-gyJw1LGC<<6b|I|4ohlcT at 0uM|O}rfR`GhBD}{D zOn_jDitrLgFbj=~&8WSgYw}3#1tWh9B4o%W(yA~bh5)bQ1S~cMo;g=OX*{3BM*kY_ zQd23i at h!Ff6%_aY9n#&`lxJA|cAjDV?mWYj at 8uc#cjg%mwd5ICTb>~vo_`9 at i{N=F zJm3Frp5cofd4}z~@(g=g^9py8sS*iP&;65sd1It&)*5xZI{7?D^)b2KN zPng{7H at UwuyL+u`FFWh at dK+T87C^KLcWGv$LkgPQJ3M>t$x zfX7F(;Aa*5*TetheGReoaSa8=`US>@0u$t0zrf^fHM`p=_xFOiLw$p|gk^NMn%r$B z#QIZ+295*uM+)1F2(1s#V+34!pxh4lXYk(+{|DfIFZ}O at e`Wr|N4)bNIRaM(R|ePP za6Jy!4!Cx}wG*zLaP5I>4_y1<+V8XYpy~#5hq*^9Oi{7YQ{g`g{ug121NgY7qAxc38b at 3pY3kv0t{)K=dECbdF+80Mp4 zcz_gYv+vFBACP3>L3C~#nfEHV+zI~@{BMN+I{5zu{67x=f8IxJlM1{}g=-32Q{b8e z*Ce>w;cADg4X!r0TH$Jis|Bu>$hP4;YJ%V0 at P7dQkM9d>n*uXX9o81~9N7-xX%TIw zyP(2j8TXCh4zk^IdTcPDlmnm-0TER*KGdDFD?NB(;W9L2&qCkpRp|gKb?Dxy_4NZ z=@v-ej6Y(Fbba;(h$by?vUe~X-Yk4lI at tDPa$er!>5`^;RA~x%ni=aW>M3^Fd_~8L zT}CIJU5M>+bQLPWomkwg5ZZ_~jM>|=C2DGA! zc!aC7u$s)FrQ5 at N%m6}I2qW$ZtTeMre1GEvcdx0&=I%AiNt-)O^9+G0bnzzA!+5r! zYak+)-G}5uheDBs`8VI&nQy3Q*^HOaQD`114IMsRN})up at +8)CdLSYm8F$IU!w36u zC#Dtwc at len5avzcn4jWFnjLtXE!)>!z%~y;zMLcb|A#zlC858Z-~S1n<#i~9cJW<# z5ynT}YN&MgwlR zoUtpAr>?P5kWG6TaokF$Rf?VL7d0)#xMhOL-!DvvVLKq?m(+m=d at HW;XFt>GMt1c6?sHPuOaXRzuUE#Ch}b^F#If zfY+}jSikeiLh;km$ghxn#m(W- at T_#=aegWJKs_{*J7+bOvV|oWrwcu5_DTPTy>}0b zs_Guc&kO?$FmOgiB}E$*%tQ at EO&l!{1~ElP5D*m+We^a7;2e<>#dl_k;W*h%UwzB6 zyLR!l3@>@(Vj$+5cquh4vB=IezDh}eip+Pdea>7!?eqCP&+qyE_4RS at Iqdso?X}lh zd+oJ{LL4mYM=87UTG4*!ple;iYYL95I^rYT_>xnY4Z7pWr7F}{iU;$DZ*>V*iv<&| z&-^CjtP^svN;I?_R+VXzTF-GO=zSiUCP`#uOiZS_o^hMW-UzFL5j+dgJc9*^my7p^ z_OKE}d%eWgD(8WBnzh{2Kw{uJ$EHn4u$>p|T1VzcwS3Ey#F#uWZ5 at h+t#fR)iI at gD zHqxx=MC&)9!UelEeTkJ`0D`^Z`a|pRZQ(HGZFr-6$wzo$-^!u=`xb}&`vGYG9&N3_ zBncMq4PnFrevA}*1_ao(1Y!g~^GU&efN2mK7dBoZwwbJqP!`MyKP!w_Le10*mhh#? ze3;O9H)yLiDOt;NUH4hSf3aCu;w^Peisly zoHFbZ;DJ7_s}T^@K}tYWV~80pSB!E=7?S&+Z7(NT6wH4Fe5C$%)d0SCkIZignXONA zn%407ax~M0Chy3S@?A)7t63-73S<~I*N#DK1qxyj;bR9HQT|W3W1-7i>Gmaiugld? zxXXf#6c+5G6Ul;2;zuKb6dvgiSL=}RJxn_1|NOw!ipwXgEt#8&Gmd8PJ=JxLjvIug z199ts1(cLzJ4A&1#!X>dJskx zx0qN|T2Z at eA+Y$#92wuxPk3kxM|WgUcdO57$fKn;tFNHVIXM7&ivY}ko6?hVC}SbvxRm(VBfeHAbb;8s53_Oj96g_iBtR`> z_a*5V4A_ zs}}@}Q4IOJw?{ z2%t(}@~KNO`I~}!nDHLOm;AS at n;CESt9EL}n#R|D0{en$p92fg-ib5^Ifg=yF~2i5uwluR{Y<1ScbPBlHtW};hZntN{1a+-yjLA3ink2g-O3& z)&9f4Gs8}s`r at BJ+L5Ocj!VKC!rg at gqKF+Xi)jRSvAHTfhbB=H~rlK>gN)r#{w5~1ZK_~a;8^hhuTBYQOuF z9lz6t5}WYw24GnWzVck|A++8 at uzyU_1iPep1T7E5Ddr|5C*?@cnrVV5RRQQ+FrEq- z{b7Tkjf=?(l5(IR51S;`11?V~MdNEpw`jw1{Jl%RfFcy^*4fRZTb4PF7ah7kXS=4$ z_0?Zso*+se*9nce&j0(3E}L0%9btjfT(|8;Y69>oc|#z&OSCJ_x^tRN@}5XpX$LVC z+3IR06w4y-UGv92wAr+1c~aA<<=wkwC)l^a)kJX;zIyIc#g0HD#qg~_v at 04W{)21b zYTGj){5V&Kziy|k)8Ts&gv<+4V4BmG)0a;Fe)@t>1KZkui)%q+#*iX9NZEeP?R24^ z8qyWZ3u!f^UF9`91R at 5`3-S-U1YdIaQndfjenI~O#hu{Jau>0l#WhN*Em9G|c<4*y z6cc2dAzSUk^(vRzB=p`YtAajK1 at wCMEb&!o*3HYK*5+Zia at S(*1N1_LMsAB!@RfL* z|0x at kRH~rX{bpx^+NLWa at W}=4A~R0EPEN6-0AwT{){qJ}Tb!IbMc&h~ zNh4XBJGJ|1J_8FZl~e1!bKuAI*H=qj-|tEQ5}3TrQ3Wdu=h$rCeGi||LbVao;mhb7 z-zRE-h_4A5_v7=-0OLrH z+Pukw!V&D^Bz{*6jMZ28IxxN}JP at A~?gvQu>Z4psb(eefRS!2sC1Pf)lsnND8MKal z1=Br(>HO`;8y^{#nZ;B!Z4p6bv~f8R9;z?UhE({f=wmWoAT4hqeiiXQ1;2dLP4Eq8 zU<-s+MFHLt5^g(&sw*4%Kw!m*GK;G0_WWXB`bZ7Ew at d|0zrKm)%vj2bDldAkK^_5N zIr3^=wpb`!T}K;$Rya=-dNU3v)c?B6h at NyA;}*vlTNua) zwd#2lzM$yFj1Q?}f?{JCfB1toCPA!MB__AbMAP`LVeq}4e526_OOPW< zY6*bvvO6Q$QD}pROg^`+({vbHVzklb+j2*V?b|TW@*9M3q@^pWyy+t+%+c~jq2-p7 znD_(i7iFoE3*`>)UM??|`wl6W41r}6DUt6{BK~c8j+8QkNi4gQ#YC6g$z=k{?iAC; zrE+_R at V#bB0wz=Evi+jOKp=R9$+JvybUpf43ni575j3Ws?zy!8+cEGS)#snF(0j(HJ$)*h_ at i(6~9K&ChHXOp=)wJPD{GCr5 zKE+q$K0wHTADmgrY{aFfrT5lo`BBA$BC9YWET%9+IWsOub0tC|zu_*xuUnK*v7w4K zY(Q-%*AzLB!t#u#04W_A^v2&&-O_+6uKJDydgCpmLJjz2fu4_KlmI>{;N-Efv~i<5 z3}20^p1>mRNy2&%hAKi&CXF(0YlWZvXg9^Qt(gGlo47j68VIQ;)8&D{g*TMj3G{}d zX$T{lpmdokJXUZEJ_ at SKC$h+Wp23BJHb z3<&RoCJO7xf+Z#``&3NtEGG%;NjeM^G77D-j75EKPscKV>{GZ{nX!SHAk>Y0r;k!5 zGp1(zw}#Z5?r`bEb-XSwK#K*h&cCB|bXd#p9s!_YX}}~M1 at y+h$dq3t#_o0WhJ7S_ zIsMW&++sVjnU(sEJSIrrkxv`nfVehNf0?Ng+s&klQvn^fCUQ?Y8qCjb!&cLVNAB2c zLKYRH$m9r$%rtpe<-(`Q!#OIJ4`lYG79k9aH&SgRpuHN`7;X3n61sJ9(>u82P7B at x zXM2_1Smi_n^#l^}3GTHKTqOyqONE31y0=xUm;hl|+NyyJ zqK{7Rw90VZYz5+GdM5_DZ3V9Wj5Es)9osniU7RsmpWzQ^6VFn6cGPZYeLQbfVj(sBrCg=Uma)&nX2uU~jt80)G#g)rKVq~oeC90?!?Gj7Ng$)LRle+OM_em^ zxfKTob5kj7r8Q7*#uyvG9hm~H*pkXtG--Pnzo|9$wldgOm6&2>tJqdV7ZlUSR*4_{ z;8%fY{eXm}aAdcwa4RQUvZ0Fc4HGvdn;AVNpLu)=%LGqZ%?z0`pBXgy2j-EoyV;C?+1-4GF1yPz-eq at JM!_8qi}MHc z0&vZ$!!-UoRP1=p4`}u{1^s%Jb%Odd8^q04aEbo=agQE$oERHxY`=&Ch4vrRCj|4; zzEG-HSi|I6B1u5j=YM9PNwaTUQVX%_N4!hOxtV!JEkog#THj+Lpo_FVbZo0kZxQch!K4W>laRz zB5lw>lfnR7p_fYEF7KPf@@Z3B3Q$8*g$;3@*YM6RlW(a8!~^*Xsf=(>QO;L zV!~|ULiLrne(4RfA-bYwlxoWSV!9g>i1KTWU^Ev-FzgaAf>8p-Q`geQi!i!nPX*J4 zS|q_q<85qwj<=cYzuF|ekGV^bkFO2oNLbmVAT~Ih^q1|M72$z&WoWz2maOIFMv~UF z4U4h*3k?=F+i()bE^#UOz=kf^q3{oU{nb2IB69PauwP;YBh>Zu2E2w+79Kk at dQ0DXM%yq?@LIZ3O_sj zDYvZkb8^Ln at a?sYFw4vRx-rG`{hUnkEI-1$(#E5B97Ed4_SKU`CgaEt7tu-H5Of*k z1g_^OyN>TH9N(8Z#qmW$9RiI5W4yYv=NMNv$;=zvajwI|X#*Zl+X#c7Gcv(47T^Hl zIfMInROqJE^(I0-(&o*+F1$JhSqyj^g~YmY)+8$17dajrZ_8p|v9}e at -uCX3{FB|DXw>z_h`A3jAgHMnQ?>gKNV{ zYj-OiEE3qF=+0+ivZr#{elad00kV)Sc?zdUV5!0>5=c^zcdJn(uoguEF)=P80U>Lc zLKF$CMUem`aEb(k1idjq22%pNBMZCZv#>j^gxxV4c1N9nfXqh3+l1v85p&pbk at 3f6 zmBKv6nF+~5XbXNk-oh|q*%g$H{37?S!J8|t$$W34AjQWq1hAi4Uhr`W19s!pQ^R&Q zQ5f(uA^$gt!hk+G(#0Wl%(LL+A$7nvcoBJkX9KEdTaOtJEz=IsU zWj#$}Eq&$oMQf|X0Zg)(&_<%LB86W at 6L&6*E!RB^8T0ag4#IjX=#&OFJ*%G9Tr&`jQq at qY8&{Gs?tRR~W3f&NhJMx$(h*$#+ zZ#o#=FA at DycB8XS@rGsRLlIp;r*(#-(^uN=pXQ-1h&jZg`yA)ES>Bg9ha{Bu|5cEj zY;Nl=Il(0>N=^uY;UUbn7%Ce4;`b7lH!xrzK` ziIDYZmwYZ?ZD*}$gS-v#KbiNY9^fE|_ej;qdt)>T^{l>Z5XxqtolOMKlc7r$#ta`d zBp=q?aFPReG5kGxnSR6USW;?6}<(1Up1NiquU%nLSlE!4CFQ5bPlTT|p9{U5b*pvtL(5p?C}Yz7Wv~-m zccVuvFG{+PY{FcA_e}>vX#WFXkeHRQR~&Xm0ICRPp!z(@?bP-EOSv5aF=fXc50cxt zVhFq34q=kW?FeN^ws}{%9m2IBw`;lTl-uD}W|!L`q(4M%x8OerF*s3z5;(cfjCYYUwu3T}a>9N6F>vfUIU_j=KHCxH*L2A{8Xk zyVlqlnce^1Q!YGE6ToT13vDpC%hCT81#66 zG!YSmLz;+xIHZaAhsr6}=LlaBLdHI18;0&6fU8VBocD=*&Cv84o41JjP-RFBz}2M6eQw at Ly(AeA5oAv=!%OV5d%?>xW?IzxK at 5V zR&f|}+Xaaj<0?oL2g?h_=E6kq>WY%A_#M39Id{CA}&NF-q?9AOSBJjw}) z4+Ok%>rK?J3MU)^<0}X>J%LQV;he%0aVgIYYYQhr$~DuuP1i{u2>8Wz&R_=5U#43_W88ZG0TcFe&vla;rQ3$YS(WN;MH~nn?DwU)zjMNs6 at 8Gt6fB@CJ%0 z?-Th5%F5stH_D*E;mG2JoXC2?XuH{Ragt$42gW^=)_a6e1^!Yda(f`W`m(~QqAH;1P- zGmr4!)T8odvq{eHs&_OmuG!X8+3F`-m#r2Hy at -X{)f71m5yzP{9h^p)oMh5;^6%0x zaHni3_>306z)>bw&z-kELo`M^=c0O|t*=se2pJOg5n6`Nm1y}{^{8=pimR*caOY%3 z?6c5gb9AVzOm&Zg$`WBZ8ftU=vm$Vm?{&dAeQPtZmrZPwINX8!A9WC_qWJIY9BruM zzPI3`3}HZQImUemUk at ovlladZ2?h1V at UMj7KQ0V^VE5tof#DyE!_N-qUl0n&?NLC- z0YMq=gpI4QF4Xc}eu5q&=hg;YkuZVXbdPoldZi}KWm964bpSuuQ5rv-l&_DwY}3az zIi`kaAZjjiiA{V&mpD6W+A%ve_b;VUR2I at C{7i51l#$#NiHCx|`WXs&ePjSeS$n}B zGIOLqL_rXeMO>s at pDv?Jl2pgDlnRu1CbK0;yhqT(M4lbhHbLZhxSPmx`2R-a$vnzG z at pTuV16Mihf&C6$!e{VBLj7GEGnI=`?2xc>LsiMR9a44-Adt0k)-#Fs!dHkm4|R;3 zm4~mDvHlSz51Su0oAY4kNdb&61VB*>@g7}y02E`3k?EUm>W at oIF$%6W7}emcS926u zOAw?!h9MSI9Tj#}$Cr+ES9KiVY+eXzbbYE9RB6TOtnLyta+`auq}MyiTq*b)n4zc2 zpZXTlH#}9zC?^eOdkb1}?qLm?CV5yDYTJn_*TY!5A|LyxkjOKW-s=a+y6ay at SWlqJ zGriYC%b!XVU#Ka?TN~w{l8ac9wZY+W$~CI6GvTRndQ(k2G<|MTju%n33nXh2QnN}f zPN^nY3RRO9OPGON*{62JJsr`)BMO0*6zr(3)~++?+8D%nlZi4Csi_K;-#C2Du6u2? z5ffRzx=-!;TsO6A7%-Q&e_);_Xz>BTIr^yuk|?T+b?5a at 09TEFkVn$@qd>@7kOYG_ z7gY-7a{&SE7x3b8{Zz~>Wq)u!#eK>|3QS7MaVO7%Nz59#Hp$la5MKJZ;K}3%j9u9pH|p~PX!&p5mEnCG>?np^#>5DBy0W68Xm?xfq(B; z+?{y5oZ!o?$49j3eX{xbCJA1y;MNOwd}RR^WV6dkTT$Us(?YiGTFaZHXS{yDQ07=u zs=T^XF2|zDTVoVnYWpf)Tok=4H1Zs2xu&x`^Vq8nN z%LRIJCy8QF#n&8rRDb)C;$CFP1m)sdf=I*xByg<1?w=X1k+U8+C05;j96<~y8bI#@ znDfO~$ul`wWaco9f=pDWH3F3!(qf)`Z&- zO{b{As%gamg_1kzeQ}Cm)plK0(iGATSy)v=t+N&VoUMS_inQmlcQe>FA-Z!KQJtMI z9zMh-!Ar at m)bPSvZQ3L#gy7qp4wHf zX~bR8lzNWwGNoRq)7X?&?|RJzqS2LVGi#c({1am-D#dvP9Ne1SY|lC;RvkM0KK1$&p*;l`MUFS z;ldmRY`rP5!}>^DwVaXTF)x&Sqh8Yi#Y6xdRtl7pe~vOGq?&mW+(>YP at I4|uAHlv8 zUfMyw4)fPy9bB(zLDtFI7d~*4wkqI*;1ZzaT7dfc3JRu%)f~Xb^VHQxaW>YenNZjo zMyczWN2gLmiii&*PsLZ at Xk!FkbsO%d5JVd&P^SU z_sVQ+tDsMAW3QVvjj+MA0HKLsbRKXO7PAueDU^d&;Tw2t2*8en30|-3Kv6nohg^{N z0U5`06CXy8b_tt?mVf;a;5C at P|X`5 z`UDcdLBOyY2m)}V4KLv+yWyq-QCH<;;79~Z)EuSE3IGt=_!-LlOZl4zk5X(3 z_S|xra^dFDxZ{m5hE7FF%R(2iohW4N(v(w82vdgl0fh*IJx)p{8n=Yax zXm&`w)*L;Rbo%R9LF9n>QP}O)5ng(I-6a6>5Os?We1(d>_BEYnUAeB{)MJ%F~ z95=)&>wiN`lZ=?9?|4FK0&212k9ojPJhUFb5)=7q)QYrhK`SW}xo=%ML9mHQ=Ev2N zD>=XyS0VNG>rL2$fS2z{U=HGI_I0N$XMf_LEDH$>qs)mA_FvpG%|O|ih~}?9aHn>n zuQ$#~>1A~nGlehQhYYIqC^Ae#MAeF#ozrb$AR-}u;mbuvXy+nl{)z7J;u zfjHFo2d~5PReZ~msUe+mGTYE2EmzNf*)Ddf$=<2H0yzxDxIw8re*+p8)&}heXPcQ3 z*tvn6CjlSN<1&(V|oS2hRbE8g}YxX_i+??Wh>03bo!$weP>}EXO+ZC>Eq1uG(kTICQ9)YTa12ujM5txI z#C}0{S7rA*wv%^?7r30I3m0^aPOAcA_|-jf$sU$#HlBLn1IYAVFI$|_hU`fLz4vrm zv~-Zn6xYFIV`l>Cy>wf&1VU0fXrm9}&3z4-+%3yBoR~y;MeoUHS$BxEE~vhWWu3|N zIU$sl$^8MvWU334g$nR{7kgy775G~x!gs&IQ1AnaM?%N|YY at FJvBRv8wnYw7GQLoT zX^>El)s5bF0?Xjo4hW`&22K}S*vZ6V3!(B(>*9+3(1*!qnLnMafYj3=Ri-+YG$58V zAeJ;BmNX!iG$2-JK*#Z4FQB202f^K at _bBuaBq3c3yuQB|uIH&+O?A z1Jp+kzS?bFi82l#YeM+Q9$EhL;X|^7<8^d;FJ%Xr;Zb_8M_7Xp zkk(!HAsBwp$SbJHwJhpoDuubK%JexdLJVXE{)pb&7}FL#8A?!Lk*J>8zoMTozqfF5 zfp^RFsfmH4$UZC4WX0=bQkI~o!epO=PG*BRHdg(8bFkhnz7QVDP0XQksH`vhPa`Z| z>|+#_3aFd=73OGGkgPpYhG)*WHYsKtUjE}^JHw9i4QX9aZkCeMj)>>9LGipl?%~Je zsd&qen-`=sNzouag}3_gdS9Y8rz`6aRFYwv0KuXz0oH>@m#>QkY^D`ZarieCnSiLEI6&N6ycn#1FiIZQX~> z&M+aJ3JnT?zSM?QWpL#0^(8WF1Ms(V633uxo%2qR=2>`;PJU2>b356m9UosM}ar8 zZ>^E5ClFEZWBlda$VTuryB*+11gx{)x9 at +Jxu`UPq3fZwZPho#`tE-5WwN*=4 ze}1!2${I&?)|~Zsh=~v_Fk|Yov_bBURJ4>f+GK(?gC{E at f}~ZA9p#!X`bbr5jx2=< zjAi|}n)b#W66O*8&t0ZOpl5-$ZnfYIB_V(57g=5yrs8j*ft}A#$H}(SGjUlTy2w*&JOl%P$xc zMq$FI>ZOOL>ZUS~#bPW&F!Z zZQjg*IyYa=6IiwKSsw1zV0CIM at Oc=qJx7vb%dz1cRa_$ogapeVeH6-nHA?y)(-8^v z>%PXTq7O%x&+`k8LUz^u*YK#23)bH47q;d|;!z09 at BWqa3<$xH)Yj8HUa&^0 z8So=Mmn{f}p#v~@4qAD{XDE=2yAHfZt6HOAJhgmQIs^gTqwnaVjU1tYS}c0um+K$a z04&d at YBv<7m}d10wblVt_yJU8>i- at rY=X1{jiBgn4-hm_;menyGfh5GQ4tX^`NDxY zY`@iA>guAw=2$5y)mL97gV-EzBBwwwGT_<+mRbZ9saezUP(WEo04325C?hiUr5)bP z7dgK3Gfi#?EFB0e_;DLPf;rE+XpiCE){zK2oKyP)L*mga#rA z1#q;P at sqWAAPD(Mt at 2EcBB@|j0IOMEK?0eyF2{W_P~`pjHJ><6sL)n}Db$ip*w2-; zF$M2urCzrz>LRua7vgE1GK;zl^!=P)y6k771Nm8>2$*~9C$5}f+*pF$Hp-+N8DD+6i<}=O at V}lRD85Nu&-idfo%$PI zz%NiB}oF{@#c5 at f}*Y?bI4Urc}_o`MlrgO1d#3t%5htaXwREA30KL9hCaDk zCETvg+_0&G{1BbJ%njR)lOLi;mbro463*Q48R`wZxshlcaIDO%k(tD+rlCY5LqZAn z0J(_H9Ic=rVm4mrv;pU(<$syiCH{r8XBu(s*22uCF)B?~rwE!E&|Y1AQ}%Mtvbsc2VMxc z5M&en1*z9+M8h^vPGPt?+Dkqah0VqN_&0$WrWyXKgLXd{G`E z_&RIv?qk;oP;J&-N9q|5+xQRW2^Yz_4f(BP9P&V7RnD1N%WoFg>j#a!GxJ`^Oz+hw zV7I79^f%0t3}OfCOO+JU8*n~n5>KTfhXEBpp21-7a at T{31awRh24BH%wYjonVnhzb zukRl2=E#uspa{sI?H(?5WO(vH5s=~09yMoqqGFto$L%3;kd5!^5#{F0cJd){knQvC zQEplNo!K@$Bo4AY*E1^FnQiey;vid8SC2j`#XKV)6ag7}cMq32M(_5$2Sh-ItKGxp zjts{i6ag7__vF3F>1PX{o`}0(E84ePzgqS_;97Qw%XF9A6RACbq5uaJi9luNa9xa( z$@w>JF2{uW>yr|a3HTo8+vj0TO0E>O3($hlB=uc(G=KEH?i~2ce~KLVIjo^ks3Gi( z1y!uWQ~eo*zSLj3<~aC4>uP`nI}S8~DYdo2bGrTrIbki=*wzM^HOIBER%|(PEq at JF zi`e5R%I$?=+)MVQqHmG|b8-x5+0mxb4%R~-7a+AF#Tx=tqUUr7gTiu at DNrvP48fs* zLNxw(%50rb;W=eB<2z+O2|{MZI at A>BA0FqA2Mo4Q)}JJhO_|SnPlvLgAmNN{YdqJH zjKs7l at iPC(ek4ztxwnoJ%B;zx;Z2FxfdHrXRzm}$cE}hxedG`QjZkaAPK0J=ZbkK| z^eK40u ztk_-6Hmw>3sbz>fST&~!u*G%kkh76tRX~L?9F;O-|*Dd;ztTS^rbCSaW8z) zJe+MU3@^q2+p4kr;di=hZJGc{Jv9{N4Bq;<7Mnh<)n at Gnp;E?6uWO-ThOM3$VPc_H zaqTFX&HG?H93az-E=6qZ|-~@rkVt3!Gu7^&xJK;qJr|rzbh} zwMw*n)IC?*OD?h#z}NinZjs_qGKx#ZH1=`;&GC0SyA>qqR?v^#BIn`>dXgZaC4`>; z=V-hS53JhQfN)JG(}&- at y$i`4Z{EBel at U5ka;|Q%W0O!gcW6NaGfSo<=%`L}hZ1%t zH0y-4oHs`Ec?m=n3%9B}aV}fcc-M=rN-i$Iq`81MUQL=tj!H6VF2f!T+rBC8q^Y#Y zRC*5B9@>yb?Dd{Qk_Gr>t?hemkf27xEC%*L!pkE7?s#&z8#HicXE?nQ$f`W_$bM!=Ue}95Mlm_v~fY_W=PvQP<9i0r=G#9hNqSmo_sO%(98vWIO?go=HTDNqAb~S{yWX9hZ7i zeT5l>6$PTsNV9Nka#HBt5>slEb)jGpF}(B~>yL!9BNb^6GbJfU!f*bCXvPpyIRuhu zor!?@@w2f_{FnqnRySFF^re?=2;Yq+2{uoXNm$Azv#!cPUc}6DB`*@fE+r+SDA4d7 z{)Gf?^Lh$|6 z1FlAniJ}!*w&CHh<{ssr+t%HfvBxVe=5rqlXBEt4yYbw!i&HIlyEw_oRqYjaU;B-6 zv>E#c%Iny{{E%(kv?+GIESj<-_m*J9<;8>fdvA72Q{hNsAR0R`E#-rO=Z_4JlNWpO zr!e(UYa?J;;M4WDhZY|}ec5kO1Vz_*j5g1f0Plp$qWuDQJM2t5tI*%^TIF6=lWcV> zs|hXd6=~CS;ug9}4%B~mVrStGoTgK)kr&F!2V37Re`H2Q{|ZTYuNmc@)77^N{}cwU zMj at CifPK>&=79A!R+V}Hz2|Lpx7(hB7V&psC{pc664SCC;Tn0VBmyGw^a!$|Xz!de zneeo$y$t>jrR zmT3S!bsp4g*e@%T6 at KOYW|zw&Oqu|7UEy`26j|d>IR-Ako2A1wign&=+))(?DRDHS zsI`;*1n$0vu}TvM3uAE*U8487M00U+tCwKT#8WV5G6P0Eq&n828{1+$vleDT8P9)1 zR8Sj at ZTPo;5`U2V4e`tXV;j>C0N+2}g*W^Zwg#(z$oH%}uxVBw;2h4-+wi$z$zmt9 zm?ZKb<7Of)6~HB`9K|oP7mt4j#`Cl6)kAe>n0`=IV3G@;Bv$vQv${61I;1KW_vBTu z`rv?DK$xh0V>_1jRG`zHc$4L_acPr}M zF`6hZ^>yJ^gucp4mUhe2}HYezJ*1xaU;EPB@(|HML(M?vFUe`qFOPeU#umg%sfc=pG z&}H121BK at RUWJju<14agnjNh%USghKJI$s3iDLcz_%&F6r_shN=q4Xf+}8v_J^%^F zBKty$x7W+`$DnhhLCysPL{c)JvY4n%HSyZT$m(23u~gy?fal|-auzi{BK%DnxiIe@ zf|vsrdN^KgZAk$#h&Fr$1g4q|WVF~b!Q|^@lt1vPnCJqY*I%LyuM^P`CJ2B8%_PAT zOwfS|P;kvRJ%dUbcsCcX3zq*eINrtX|7}7i z2zLMFoBp?U|9h&}dZb#OY`5854`qM0v;R5DtOyj(?m5|I;}r==4eRSvLI8x>b zdmNfN&2fYOS*Qh-^(J{y1eKfK%aue?-J>J2-gic$_IxeT&`;tfL<`zb3?2(GZotUA zlPjq1J3|(W(}@UQhUTrii&`&eA0TSI3rh&7DUzY5;1DxBc%=m3c6LcT92LYIyw5kN zYtIuEJX7LzY*`A?l>;!kc>*xN at nI)WJMXrQiNu$UN|hlk1Mkq~b%#qL7p6Fxu95ual{7 z70S3;tCXwL;&UXBVBG+_N*ptBE7rc+W8GO}Tk$DQ)Mu6RA*2jQ4>M_R!s at wbsfQc{ z@`sUrpXAQ^@Y`Rp>z$IDRjt;;>bvWnT?5q?tw?aLpw>?M>-iIMZ z1+4Z9v0F`=mSHuf#8%XKdz_DS6wl9i1(%z6H_ZduI*e^4D7j78fB^7#EY#Gks*B`c z$$~$yc$eVfZ9DEbSW@!0UM2 at iIbQQE2dEx5zJmGhUM3f|4#H24m*WMDSc9E9#=-de zTVKpU*!|Z90-0H=DC)}_gaUK0z<$C at 7@uf)--}({E_}J1D7|veaiZkQhuPa~X!*L0SO8=g`0$H(^>~*GZ?fR%uda7F)?+sc$9fA~>n0jQJ+9u(+DOK2 z+{W%V=Z^g2LC1RcPr^|xzw`V<$M|}e%cB}%rI^9^ zE2G${Wiw=DoVR(_*r1ADWk0VkI|2No^|9`u|0p{lwen@@vUOHpXH40UGNTO;1nWtz zEu_{W2n17A6y=UpJMF4XB`p~}l{93ypeX$)Uv2Jbs(R*nGUPe^=BL(bvjXweroM7S z4OPyv$b$l~4eHI^*?!uQ*XqsrVqS7zjR41X1dfGYBXB5$wmc=YC}p at M$)*r+-<(${ZJP{!C>{a0#Uc%`}Y-%R`_ z;$J5I1>&D0ek1Wu68|{yj}gC$_=kwUpZH%Af0Qt`ps4lEQ5Ko>KsB5n6utw_UO at D>&qs#(Zn|8 zNcoMs342BxQh`;?`V=U)ByxdjeI!AvT!*@g8KAfIV|@i(jCY?WjZ}9DhBd?4CfZO% z5s6=4d%0ZoHKi&kOan znAi)(Hel6&o3HagtyQ3xYv+^5um*KC<2x7s at dJc*B=eiFP;>MoAl%MXP*WDM1v!h7 zc at NT(aLqZv6nFwDW{p at 3o{$v?Xy@#6!XA{)mCB)~y?}cESt at qI@D!}aB+`Wh{-hYn zdUAIyBO&7Gtb@}iiweG`Ji(}h3I+-lxIPM1C{%#DxC%x^a1JE=GnpiWc8C|$W(vuY z_`3ffQ{mPHQ?u{iM5+xaOLIBgT?GiY$h+R%AQ7Z0?_t0 at _!o4X|NceD7GNW>BrrsC zZYpwWtNQX^y@<+%Nqoo at 1P7S?3)X}jZ`8!9cdOGT+a_RoeuI_J`mSTVw}do`FL_ZQ zv#2EgYl$!n%Lq znI?qFp-1snIIz(<624}au+x+44C)En$4616OW)ZL6h)b3yTd0jQ#qRj^LAD=*|lNQX=xv9ge$|z?(b^IG`nb zv7CJbU##MvkHxAnO|tlch;?>yMK5}94ZXLcE&9npGG<6*MX$+cnZESiJ9xLWK3t;! zraIDww>^EsQ#-A07~*D%>x`UymaR>5t&r1nc6-{2>~`Y>QZm&k>SyI_5dX1}s7k$T z?7rm(mN>Tj#CDD1HWL142_2~wFShivE9*UPL~WrtMr3KMBX%g+p*tkZ;5Lmy$^`H; zjkvGk-9LV`(Q(!7G@%~sY$vu3-?2z(zmS4-F7^NZ{r$fSze=e>aAn|laIb at _1NSAk z_rWdsRZ7w=ZIV*jCgFQLgav^M0H*-g*({~5gZly8G%@|RSEbZtaM!_gf|CP68~|<% zxTnCygIfx&5Znvk{snFqxEgTh!2J%c3tYcnq|^;7lm+etxGE^?Q}}%o+za4Vfm;eL z9^4dgBfU9iz}KL{#uSgY~0cDEe-2%n18F|^vIM;}= zW5$gMgFK7Ct<)72r7zc|EzMs|W!PJqwv5z@5=~aXfZxgtBsDF z7umhOIL++D2h>M`sae at e7ZqhQy3qyc%T~bP6~RD?MNkRL3bP9s41w>c_!(O0Z>%OV zS`(i at X=g>wn>Aw^ff;RLyavB#xrGNV-kc(h#~2Rw at mk-;);rj)_}_3 z&|sldQhF|{6F#Z5w54ozE|Z;?mPTnyX65HCPm3wcUzwDjouOqQURweQ(_-=qSEe(h z%n}&lG;Mlek!~JafHRI^Y15#P3{o!nJ1Ry5kF?pkV)%Q`(j1u6GytVYhAB*73Spip zXLv%- at EI!$08-L~pSb)CmQ)na=H(&w64t?(F=NQsvAG!p2=fbcd8&f^BIpYlh0(%n ztAdNXg*L`y=aC_XZzw4(A$ujX-&touNl}^rL92xH&Pjp4M~)n+a at LibpPr!-hF=9S zlzp7EP#A-G5tIt^mlvk5oSnWB^UndO&(Bn?)U5=_9^&i^lciG?6zWE2yRKEStkM-07Xnri5;(^}T-S^aCn_DbAw=oa+6)$O&ng(Y4ArvC^$rMH05z>9yGW}6`#K{JrCC+Tc9Ff>r!8# zZaHLv5+GYfez9sF?(R;Pl|j>5&9i=n#J*$kOFp_xM2 z1h*#SXEMdU4&H#jgDEhuOARZCn4F_B-ilS!c+u^QT>5lf|VA$I{ zMx5;4&8jdkxM;K;CUf(bqY5ciyp*DPB&R~h zhpOUr%T>|SR0Qo!RxKo%Q-h19c3&e!I+!0_iE0(Wj?vjg1-a=Z1S{D4g=3DO9y-oZ z=1g4)DKYhd>rEh!piQF-O2iop4-bcx14&3uVSOh6U at sHbEaI)b!Eon(gKC8;e7dxw4iDRCXz6!Q`HZwDOSvG9Ps`O>c zfEZL2W-rfTio9`NaOPH~FU!i#(_setk|g0pBEUm^u`@L(X;F#s at tWE5(h?Ii@%FG; zbD|<=rNu=?#m<jEq%VwiZH;hfTzX%%sJnSTnN30r at 7 z^{{>bF&B!vNWpzQ!QF92QDTvk0rmVQ at 15Nn$XL^JGUTtRn(b zW0oQ%;e;bdt#iWkec{5g0s6H2wocu*Cqv6r586eA{dsgDS-nm?AWo|;V+aMXf%{gG zDm at Q7sj~Ab**Ziwn2n&s|4lk?M;e%E*Z5_Qb}rSq77FQIL4a&{7}gE7K&UfJT;M{w z`?qJ8aQl`n*5kVUlm7hwv2Gpn(qrXfdtJ~`clt+Mf02bc+{9J z8VQMnF)IpQhQHZ_3{@2X?+R5zacYYhbL}XE%Fiz- z68PUd!ndTeOg{bsC9wAA5rr(nVd%PjA0%6MyB z`6a*i_g^j{-o`OTH_7cKN%fo86{NKPQ`c&**z*MWy!#cXm`x$ldbAwC@`ZUW&MV=+j?v zFN|XsUD2HK{r+;w)YG4Q8hUZ~Wa_86WpmFT at 0Z?qw6gWfA;XUCN!q&Ut5fs`hxfm= zUphiw?wqK1TmlcX78)YuVTP_x(q>HRT67uMGNe z>5S1o^u4v_>;~Peb9d*be-ZcX+{(!eb?CjHLl2&d{NTzn=QmxLy7JiR_wTlTe>TUG z9o2a;Z+uMo^3NLgFZrQpv at H79L2hAbv%EiUSmXQSlxN+wA4f_bQ!0Iqyr5Dv1XpGy z?=j}9yv}7Fc)L0MTff^sE#A^_@$sQs8h3xW<9vPpse4k^`+hk_z3A}1&vL)2Qt9{q zckiB~|5E(C*X>_tK4-$GfA{;pi_dK9JN%MN-|uo!Z=Yqq7}OcBKb5o6cgKR9=X_52 zHE*+dz4q8H%KP)TJWHcrqg&3rCx0>PPs!k}8jtMM-#k|2tr~c) zt10BHX~A ze(?123 at 4uA3Lf-gg4IeQj; zWIJCo_Ecjf_twQxgLeJ2aCc3{8^ixxcKyxwa#-)zR!Vnzc)j`bL_e!>xo2UYWXk;? z&m7(4|J?qccZGcZ{G@?<6>q$B=2hP#-~GDp=H)d*u3YjtcjoL1(|$hpN5`HYv-0#m zJo=x0N7gSKexU7Y@$UTM>H7k%Es&QN`7IhEUQ z_0QhhZ=CTxKTj{4U9-n6Jbn1`kJ|e!X^fkmJ>ybw-c!%yoZfYL!S@$4eXc~bs4qO3 zun&7sZ^)Pvh3^s(fj*{;gAiTV9;o zyXG0?u!{+23tCsd8hJB4@%*ka{?{s>JYTsbaI-=0p0Z`&KLU1AZ(O=FdiTG+nYc4G zwfI_KZm#Xh(~;-i@>}qqcY_R at e(C%6235=#AEg)XJo4dH{*T`pZ}CC;pK5hqeEq}6 zyHZoFZ^uNBIJqJ}`(DAST`R_h-&`PxIa9 zl(a;zU21u8^qiWyz6 at 6ciIOu2A^TR%@xj5;l at 7LQW&1yY3WaCGhy}#XT?&C$B zTogO at yoOtPC+|eU)#7=n2fyl at yZycIpEj5O({J-D+AZgQ>b3J^{h2#gufO)qoxc{H zUs^cmTFHu^D(6MKZJ3iXzqen%M~3yKe<+v~^hV^csUNMlr at OY`+L~amZ;~@6HO_u- z*DI2r->wK4a`L0FCHD at E{P)$M&u%n6{pDzV at 3(Wm at Ot5spxB1r`zAC#9<%mtR9EM(s|#|g%OZ;}Og}&IpB~pnzw~t_^?|`K at X&yY$Y&QGT#&VeFOIr+F?Ye> zIivfgt(~ZNbM(N+ehj3Z>P>AqkT6!i{pF>*xYG%hulD=8^~dDao5x=NsOIK(n=iIm z4teg{VGi84;-|51j=VY2_}`KhCq9iWIGaB(wPVc4n5$PO{*<}h^XqlX=JE4}>TbpT zdg}}6`!zcUE`P-kI(+-vkMH00b at T1Ff4VpMb^z$1rZOfeHZae3#t-4c^xc-}^ zvmX6=()z`%!?tYu$ZyZ(&3!)}NX`3o!Pq&STbC|9e<7jd+x~N|&PZB&N4shC`RC6C zo?P0e!aO?u;O6nK at CP4lytv)t`mME#KdaGA&wC{{_lfNZEI+aLg!*b>Y$wPEc z_i8TrX!8fLhc;#oeC7SeMphhdI`qw- at 0c5{OMkjoHSFfKi-)fs^6zZ?$oFY|#qhOX zyz=ycpvHoZzTaf4W3EkmuK3=<$`!iHtqazE{iIjIja8Fk+dtpswZG-<-tUB+e7d6W zUJz=ZQBUU7Nb=4Z+)|FjNH6d3^0d}`kS7r7i z$N!wr+qR{>&xgZ5 at Ab;8BBlR=DSd~9cKJW|(*AyN&Cm63iiw+ae$>YBmtJj9AL#Iz zJmp68(>{h5o{FDbHASbDPMzO>@x=VnH=mqX`@;mu&VccTqse3Ue77m|_Z4Ty{V3 at b z_VTYQf~>PgI%zRnY$1{AYKi3 at +LlcDXPx__gAYIdfMP{?VV& zyzw2o`m$;5oV_#G^^^OS4q19?&HGGQ$!mkBtv<0`_T0S_b&bM1zw~!pRiMOAzMfQ!WvE(tKwGZiQ_!8wWKcV;Bt z`AtofUCo_^D=!4^KR(;&zA^K0ux4(u&~x6j_SB-|+pdHl*AUc?yeO3V z6`doWu#a{P3N{lD$fw^<_T6?)5>gOIVdGm)y&+qaUT$EW@#*d1tG&T9X`2t)at14d zveWlU-N^Iby2&blbmu}Bs}BYbKYtlw(4QJ^Riqbjl9eTj*5g at Z?$BImMhmiJfYhe! zn at d4?px?VH4MzUkj1{hxNA6cvu!gJ^3%?UD@;U2WfRbx0yvM(p`&sd1UfGYp{F at ma zw}w3L)xTjQuj?q5Z at BU#w2|h;lRGjs^tG1s=$fNknrNN%o+ znQ9B0;b?zuZqoTdA`?D31;X04HN`%pD*Jf5p3x}7GEr=G>cq&(+1p~d=N~4p*4xVL z8G at qj*h}dO(_DC;F}G?Q5tZ@!^l(%pwr=L+D-)f>K{-Bg-$;gqxAVT|&d^SLkhkm9 z+sxY(SiP5%p>|Z{u!)XQ_S{!j^yO5_FApvi%Rgi7+IH3+$~i93$Q9qqnx2z;`6w@& z>W`K{B#JmCah+jfNv-7cxqa8q$(3+5BpnbP-N?J*FzB<7zT|PmEXC!HaErU-BW}6o zjVv6C#!aQ`r>2=SBi{53&jbhA(+T%obX4=bdyAg7?}1&7C;tOdjAm}r1ZXdP at BTq}A%o$~WalaPun%XI@{H{SQHYOC&3!kUjng1@~u z`$pO7My{OWw+CUPEOwIJ9`rH(eJ9Kos&r>f<$oDyAIV($>KPqd#k_KYc~d@=^d_%t z8~34QPL$u-Yq!T|VjowVipw+ at e=r|@eYQGCSM?d&`(I9+GL}>-QP1Bji#-fYNN{_a z{eiFMn_kid!-de3qUTPAQ6&~Hx`-d5?2e>$E;?CXFe~5Q9l1>=%#UVK*Zy+*v(I6% zbVPQHUxz^EfyoS{#-nvVp(?emE}|bJg*GS$4)gR4f9az-8R9xe}aK1z~X1spvUz` zo{tZ&6&R_ev#yj%SN`ZXM<|nj)bg>qvNjOUqx5nKwP~&AFZ at m7U@Gc)4Uc~3Sk}Ac z``>Eg@|3A9=~me&>^1W`^sb+JA;}wl{8~!7?oT11Yt05c+fz%~jP7P}zRa@{145Fe z<>(lM@}e9GG9;|kCwXRm?^o0FKa7{rnX+fsILSkulrXYS%LZca50;(?l0sb`Gvm4I zQhUWGaO~sbd#+;#jQ7;!%`P0=_c_GBL}T2(Z|@yC-*VHuo at VL$K}5knOK-fs#>7o6 znJej{$B|IXY!lhz{#^Fhl_iUCzB>f{D=GZkVy%q}Rdu(nF>xs)&g~zk4ujbRe zh!*pI*;Fv|Z24fu$YeBCgQh at GOrrqheoM`IOj-{i$6oaU9MO}$@^ z(GHdmpEl;16sgdgf=)gh*9-0(!Z35zt=AjY-s2i@*SGm;>bvHiD;pUZRqSUbvHIjv(7so-rJCuZg%q-cWxir*oljsp+Y> zAH}0v^w2knbgGhsS-MQt%MP at yl+LFGldYXH7OhN)93A!6Ih-(-5m=FlPnM9j6ZzE- z`-uuKhElF~f1$r;gsq;u&)B%E8{5(JcDp$`(DK!RX{P6b=(y3q&)=VFVzusI&Yi5+ z8^~{iyq>m-%&AWoqE1g-9WNNZ=R7*L{$0_2*+If(a=X$tTIIP#(~uIWpr<&=f!Aew zG%viO4Sb|a=6;Ho7**Cm&A{-81{rB&SAPWQ8d2M9^OR};vyfvx^^J~y@=<2>Q0CzW z<0W;*wWnEx>S#k6+f8Me<^P` zHArfr=bp~=r!&K?wrfRgMz(VGs_E`!3c9RM9l-mr5B)xc>TC2W{ZXl}73p)0~l`BTv_!&MDZvs@**FJj^Ae zgZatVW}fq|)xNW=jjF!UlqQS6=pEc_$YmZQh^S2yvDv>iEvxJ?j=x5kod%V2_ssc? z(~f-9CJi%?CaLWyw&lSLSuk&)?Nzm8U3_0u4Lhh$j+wlapQg4sF(I>B+E%4M)tcR_ zdS~#mNd2$n_V!O4k6U_T^lMW^xa;zZT81Rao{W>H8cZ4Sb4}WI*4hLJ-NUFinc3|p zKI$rvR!7}&;x0`>o(b9XenH}uc-a2g_KTv#BrQV)1oiJ)JN1%Y@?BRpG%1eML8U)< zI2l7Z+|!EQT3L#jU!Ux&sMn#XuL{!24iij>%H$YS?_t!_pX6fjTX!49te{eas>aWr zs9)U2ky$@Z78af!x&&TbDy|k!f74oRb3N;1Q zF-8t4=V=wm&-cwJ?tE}Fa9?-CinJd6ym3pkr{M}mvUd_it^`X?+jqL~_?9E3Q~sy! ztVnr&_W$Luq}GAz-GAxa)X`I`{yJpKmO)BAI)YIz3^?wmF~tzY)3wSMaV>>)N=^1i z<@VBYwytaLNiR;^8=pR4+7D4FkBh3gY+1(o&gwsIX*Dy*&vjyoj+YxtPN&P58qd^y z&|ivpKf5*ZWvegM!*blz(SPxPyg~hxu}*jnGachOdL}M5ZYj6tr at 2tqu|FJ(0~bve zjrypLXb(wQ6D3#Wv&Q7ii5K^C9&P(!QOP}fyH0NCV-91OU?kNYr$=hsRZ@&kr z at Xuj=?S$q0ze;keH6Eba??uXZ^tgt8+ov;X at wNWgDL0Ft711|~pMU=R(bM^CC^@jd zFZXm^U at I?h at NRF!}2riNrLiN3E`@_TCQ8DaxCavcceU~y#oF*rk1a%J5 zNCsWt-7k1U7UFo-oCz`JhKcIOR#_&c)awtwTJL4Px3X at u(o>xFbu#@~6-C=}BS(D6 z4bdsbh@&e3-pr!%TI#B)*K%yoMh-io?H z!eyqyF6Bfa$|QG>kB%8OF5ddN!Y3Iem$;}XN-4Pw91wC?f%Ibkg~T?s!h+=eHtjJ-c|Y~F&Ac0m&+Gaz zWjVRH!nLn$ww<Rz5y?>j`h7kChH&dsZMOD zN%=HURn_D%=B&oZ^^2!+|A2oQgNS+ at PLPB@bs<*iFs7g?c}d>a^Nut=@D7;{a|GR9 zy(ao$nMB%*h%uV8E3;JW->fMoQuX&_3+|ydRXxqYlkaw5;gRa0TfPSmS{&ftFHBv* z{sD8HwS2mV&A$E%a$w0 zQOCF92%=Zqj<1uBlqMGQu898R5j_8h%Ti18a4zpfr7c~YjaTbX__>qXl1 at CRJoUxsYI!WDOg~sPs3x;?A5bYt;?hH>cMT^vq;Vdg(k;f7;mQ zL*%)Fs2a0($r7gg-$~3}l}#>G3Ommp-yb});odk`Gx%}dvv6|pRITZopOcQSn{34v z0%*xrc+{mnE+FaO-^w=pV6l!_5}sRF{t!L-u3R$at-WdckG)N++ruLder7mj|2j)v zy2Z|L?E6H({%_g$6gEw(ygx(BYM*+-F0Y24=2=rQLabAv(!TTw&c{_ znZ-oQ38UxRSLj~I&Pz|Ze`%Yp&53>Wg>&TP360m|jx-Zvr8X;1S0);s3El}AvMeAS z&K(dRU37C8;bu4MHUG(Q??xK${pUx69Supu_x_pxJwr`4nf>7!*A6t5n?2Qa-gYv6~ z-+oG)3GU5ld$5 at uR5^Gk=M&IYE56iNS4n0TL8GNvMG34d*;qcUcg9yDMt0)%MlabFn zXiMjYa!Zgc8D%!41LXxS->TmE1>WXo)Tnf=V63RTf24RVgtbWgop6EoS)am2IaKZ@ z|Gm7Eil6fXf0W(o$hcX5&vU4bob646d~ru(=#wjVp1h!`rLU2xLDO4S$70X6jvuyb zVN$!$r2mz?Ir)ZY+f+Ci+*<#D69>y}(-~O0rnPGHdYE|rr z-bhKQR>9Fw$E6P6GaiJk99VEa+r8EGwmyW&WgcMm(3_=sZeBViy>#9 zLdB;0^u?}+whxLcy*(%upA5M2T&=w9CWv5Vk}GKZ9>qG8%|5uqd&@IXq53|uf-*q$ zQLfl+S=NMy=l96i*58SOhJ@(h9pouVEojd(HBMKWCHT>%2Ox<9jj)|{0pWNF8 zhR8GLeCOpqOwexXb=s{8Z04zD$)7|w|bL^v~zvWqD_W(os zfPb!|lq?KrHYr38YL!eEtqr#POqqVKBGh!n;5v)#dtNtU z_f at slN1DP@FTMqfSSi0b>nN9dV>Il+w{A&07XKJ}j|H<6eWtUzRoVu>!b}<}zu6|sdy{kd5cjpSeyG@)@!R62)sH_IH^`iQJ#4P38&v)4J=-%&8BV9? zQ7Tjq#g^Z=B_xFMeaL>Ar1z~Rbiwe#$#bG7ixa8B4vD)g(nfYu)}JhLZkL}eAlr`Y zWE(erN;YPYSht5%Hf3uwQ zjMrRipR^p=$i9pRS-i0vPPj1D at UDj{;Y>jN@(DXgWpb#Evn_gB^sR`MVdCMjZMg zZ{uwdK*ZoNSoQO<=cDUJ1#5>_SkqO1R7#gBBh34Kv_6s#tX;8ssl*d+y@^`-ChV_= zN^UDg!4+iNKd(TTuA7rE{{R;wd|#- z?Km at cMu}Nw-%?4T0YnVCoJ4L>xiu^VIX{!^bKdmpUi7l at kF~S1nNFePoKIyjO7~+2 z%7RXm4vt+$Nx9tRF$?s$QhV?5$1&prW3ID#HG4kqJGh`x;vcfN&wjkzm+nq;Po61J z(0%C}r9XqYnXbJC%YW(w4n3Dh8|Gr!=k7hnT&IqujW(mHNJCa at nij9-)1oi#uMs+^ zI3la|-NjgN`Nh|}dbY_${ne$1yl4gjY??7?Q)J|8zjqlp*?VCLjM}>X(BD1!mX13Uxb$$@+h5G%k*&|V4|Ao~H50(b~QP#}P82Z#^g zYQRAOl+l3H0A2<8Nr7wtXdlExIS=v+0ND$W1c-kK^3wv at 8W1ia9?uv+>Hx2U{A55j1jG!b zzGp}O7(ko=-vXQnPzWFtz;iqLHwMH8aLSJU{Q*e>JhG#IdqDgE-vJzM?-f93fIsc% z|12OTh=G!r2(N!{K*vG+;~o8j*-Uu^;4;AB at rnSX4Dj0>{hI+g0C3ih{x1PK4e;|F z{W}8^1h at roxID0&rqlv>Ye)ZZp1q*|cX#yf2?*$c>i&-Y;V}i_R7HTp>B9g4JyR|2 z=>I$*FwRuzJNmx}2#f>O*pB{zwNZk8Q8fS#mlq321K_Va`Zof^vP=KIfKGt;fgSzZ z0^$X at 3UIi-C_t(Jf85dk1wcS=RM|WFzYItY;He$`y8;phxC3ywyhK1c0RQ|C_TNol z|9Q~g_CHHt|H%aQKTKf%HPGMozxE&O{}F-xmqLHr|1yF7Un8*pNdo(ChW at tyZ~wvm zdkO5n5c=ExUlZ8>RRa5eMqvN-(BJm|p}*~ap1}T73G9EA!2WBYzwQ6?f3W{P0{btA{U~<`@aqSZT~9-_Mbyw|I-Ba z-wFL~|GyvxG9rkDjEHD283Ni*M#O+1BZJt;h)9{pP|yJ~B6$Wf5{Q+Ih>j?pLala;%uBSw*R!_&shA<`Fo7;W$(O@LA%DM6jC)xaw at n?l!5k?nEqz>2Ohn{3QVZkZh(uXCfr=oYEmEL4a-c;@pvOHx zhqOR%2xu?F0_}$mL0pgkBo4_yijY2J1$jbYP(E}Qnumyq at bxheT!@{Eap&5*bM4!? zn077(=n(`TC`<(A3cd~SJfa0T*&t3x6hc85CHVr0j>k!k_Q(&_Rek?FMCTTEb^aS z#_&F38yhe{*qzt);JwO!cJA-&w8zcdofMv49$1X?pY-r%aKbnjpd%M77M|R=7dSDX z47+3n$P^IwSp`TJaCtxyfRKO~0Bt7WH5n&&p+()zz(Md-Qx_09(gJOf- zct&Rk`Szqe!>tKQNI*p7X0Sd-RIUQRZ}C`u^@4SX?tX?GN~jDHzN(ExzURcHf3=hT z7Vlvkp2FjnL|Ww|l|zWk5=uyNKY~PCgA`gstY}pAv at l%?{%T=!HVS%K8K!ot)3S9$ zWSXL)XdQYpcSfbL_ed0e(+_KN8>-0=!Cq*9h<@0{oc(uM^-e z1o$ff-XOr61o#^P-Xg%?3Gg-n{z-r#CW85JXdsr8YCl8GFX$B!O}|=j_I$M8 at j*nD zJ($lzjF!1yEh;AIhY;8Lpe~&;rHosKU#V`RXw;%NnEPp&RhSC27R<$*=T#!xC=6&n z49%=sU&v&5O03;+_&LR=`rg^$fvr7!OT&odsCu!rWh1j5VTq$W7l#mWrNI6KJC_2m zBdWZ+uv?7XrM>q-eb?do&dx##PBd3~0nWl>=BwfiX?!DyBx!&X-pL~8RgtBi1`t(P ze0xI<)mzy;1nF*;ppUhz1 at LpAQ^ zVMOLLkiH at 6dG5@18_WA4L_7m%4?Qni at J~i(g#RGoD!5(mI$uT2aCuc-bYuw8tN`Lk z7-xB^w9ZpB0efcx`6t;t9?~pbR_y`tC-L#QjdboGl!p*0>Jakwg9@#gAtT6h*Z6ip zNtC+PfRSKC*_Ly~v=}a&yG}q2jUmq&x3oht3Qk8rMPn;=+xpn(`5 at w&7ij- at hNZmviBk(LgNV*cAl_c(BUIHnSj6&YeqeZ8Azz0f zMB#C`{2|L~kv!iYX#gwXaW0BTHBxT`(b at o6WL#9y{2;Ub znN;X>PwvzRqGJ()Hpw0v{g80WEpswJSIA}D@?icJL#j)>q`(2IkBK44(h2Ln3QO8dp@=84A~kE#k7 at RpcFL+IO5tR4aYbsq>L7 z`!%}QCqa_k*VWSy+U+);{ddJRSg!w)A3 at v-g6AitJ7;XX7{Bkf##PNE0kNBg)e;2p z!3MmaLN}5X+SAq~Q}s^17dnw|cw=A$kwXW at _kQHp1-6Q+sw!w=z|%I8qGA^(~o9fFWsVF`)PihTst-7I`{ZSe>9KU1O02|;#w62qAXtyoQQ_< z?I(Y|0ro3{|9;}03z0VdGKxqz3CgoO@$3iz<{`km1h~BR9S1{T7P^2X*ueKhxh3L)Vcgdj->RXBNzclW;NJP%L;@p3HFOOXMD` z&_!f|x=wXAHskgK;c7OruW7n`+~_isVe|0FVCkIpt|smerpjT9&!lN|mhQ2vly%=#j$}Iau4M`b&Nm9w~Y%y?inAnituH5o%wAUyL at g*@|U0j+W8;e5p4kE6= ze=o>T{G6SpbQgw!{S)Esznb9tE%=v&lIF^vzYkq|^_?x_h7ot3!1f-8Kz7~u&`b&J zlMDa-{XT&=u3UB)5m$}Z_q*F~hK0cQNt_=J*R8jhGwV5n`A~_Ew=O#6^^O+gKZ4I+ z7t~#Z6&!)>6BqAw&OqAI-CU(H>}Xz;&PqsRy9P7uff=nVnMsdy)t)BCJvpY?SBDV! z1)x8aJdzA0scBN+`=d<-^v7xL3xiFw{NegxL~R|wE=t((RwN+_?nF&UoMIw8s3D%AxyKRkVL>FvFb)FUOPWauiH&LanNuj>bf zb?w<~J*pf*>pzrW6Ikr!m!n0aO^QyxC|^B7BdhUFy*RY4$`ssp4rP3laJCZE-u9^+ zV^c1&I?--O9ulz`Yon;$eFvTK$jdi;JiJi~#YsO}lce5S%G=k~E0v}E{inty33B2la#qxRR4ejQv%`9ZW($M4B&8yy zfv?%+VgaGMN=3KIi-^e7_3rAQw^S?d)^0hJw}MjHW((=ktr~e3qZoNMhDt~xGr)-? z>`E7}hI}F=gCN7pA6`RQqdyY4ZmU$*IYp?E*gwE*__9>m#b`yfi!>TPLu*!gN(T8XlI^q;KMZm(2_j5j9~nk$S{6_fR<JsbscO)O_1qi4jibhv_U- zvwpr6XK8Tv6bYFVKd9}a5 at wPqZ7OrObw%DJ at O$pIMwEKjr%yo(kULep2=E&?Ywe0M|q&v!mI7b at 9!EY>`$SxHgtN*R|9+NxAut{ zWn?O}Vp2+{%9MVcWQDjRFyGO)Ce)>mS_tHe(hSGEIGV0dva#UCDE7$1`~-AV^Y9e9 zX;_JNW99VAp}CgsX$A?!j#mMtyVoz_iMt-RM zr6(TOgCBIKOkEDM*U4{@zcE- zE;}SomUPdb%Ud&C!+LRR)7>$xGCLwds8X$%oyxw?u;@wB;E28WcB4)f&AaN=?YdL9 ze5R+5KD5$Gaxhe?Q1*J5`eJW3q}Z{CJM>)@J5MG0#QB`MZgki?rW5q-YN3)xI;TozjWru?p_C(4 z9o}N9bjT*OqEv$$sECpG8lhierkXcfs}<|(1U+7Bmld!d>wSE>{-t)xxT8=^cbWvz zOhmg7;-F%t%tfXOs$XlYbni1WkxE*TN;Vm(Ot(T*7Q{Y27Hv at v(J6d4^26DD=2>%R z>3vQ4J9ny_8*ZcR0_g`n6QTRnBh{Wg)gWC-96mw9_PB`?RV3}KD#)C1w5&_=7~{Dp zjm{y>q3N3I()D~gruLiR+6fkG2bu#-A7uIk8|lPZDz#dqXrXUZtLUovD!_ z<97B?^_7NEpH|JNjdNynG&61%lUJ6sf>(@xMR*Ow{g^WXIn>5V^n zzvJRDrH6aeleY%Ge!1}@k91~oEb57X(oG}tJ at 0f}J@!j`jZL1R&<@kKeH6*?`DUmr zXYh|U9nEN#R$dE6+tT-L0#h5;Q`Or~bIbXKJWa9NuGFZw$E=#0t7TT^NG~hE-G3x7 zOHU_wCV-#sXNSV|`}9xd++VAtC!K$iV^mgqH=@m%!puXn*!S{#KZ;}I%@Qjbk;UHf zEzvXrH?Nc?u7`w-U*TF%Ew!*{>-msM9bVsORJUBEnuokMEq;7zZvONA52$b|ROM$U zj at -s6RqBb*iLy5z(2o|?Skn`uVP;;*R at DUYu5KO=d~Y0aggAb0spM`2Z{d1#02pN2rw%FW+TAJf5CKr zVNQa0h at gHtf_P$rcpd`GK#-n>AfAc<(-Wlca?JU}sXKruV}c-iB7Qj{g7hLMJ!v?O z4j?LDgZnKd-_tY%`DqC-H6bP_Zx10RNKZl#PeyhBc-{ox+;350Jaqc}zhP^(6h^#fR{&w+L zKTXhHSpqCifRzaFdBXm$KE7s-8bn0z1MRK1|B`!dyp%;{5OH-IU_08nBrRt;DceCr zIwc+lJpC-9YCVidI0g4t%DL(*b(>!_SdTBm>*M=RB_6WH`|rYs3C2@}p#Bts@!(DGbJw6gPje`Ur480e(V&2MF*W0j7L#Gu_7&td}C;=OxufQ%U}5eElPc z+zlxBLPTOsH$i*42=ILZ{EPrUCBOp&_$;lIhd_M3V#Hnnm(TkomL&+r>+Y>H=R~l> zh=zR7KJSa)o>yh*N*e;4hsUc)j6d542NC%qKtJ6sSdnMSv>HA`h`h&myvIM2xo&O< zQC$Q2JMpsU;9z;+7rzliIt{@2?2%n1b?np*BZx{g9uLjvWz)NWcp^L&`M4d|E3 z8isPY%LQAT_KC6!6%8SZdVzhD-&XE2Zwou>3hKLuudi!LxBS2^j0}tmx*0fxNS4E6 zxd${w+cQIm3|)MF^F^+h9?>Dh6%Ks)vvME9Cc*l=SqzWo2(a6#Z~a`*pYkAEh`BNf zV0k=V>#OZ{i2j2=5#V`(@`5hL>6?S~afSlEJ^rg5f#GEuN^Nd-3yfiJ+gLRQ(nf2C z5zTe*_&ux6zUI+|-Wo>a-o}p)6z>;7VF$*C0snk;=3<}IZoE2qm)(?Q7;&`&thY1X z>P+jb4tV?o_ELy at eloaS;m^>{KZ;18#XnC`U}76G at TWw#k>8P|?oe)t-jaTQd$Si6 z&MDO~lBnWYedNuPNBwNd$w6Xf9$R$-wgsQrbvQE>k`lj~PrcBV zwlSD|aeQJZ?OAdBMdjMM0kf70>S&VcN@%(LzH$QpP)@4;Eam*63Bgk(rCRwSs at yjv z&gXTc8vdF&rlwWjD<5)+{YkUft4g)PQ{1TX`TF7`qIW2;Hq<{K&ora+`~*zv;!_Hr z|FDaBc?hW)_YP&FSYLFcc&(Z=DXmQ at eO4hopYhC`bFpkg#35JZyc=pv*;^5 at avh$R z{lA|=7d;4?)#g5j%DEKaot4arx;Fme4&}ps8!EN0S=Q%xG>ehl8*!8_^H-E>^1YHv z&{y)w^Qr`{7snDjPmJ6+KNX+~@J&3Xy)+YcfyN5e$!>ASi|n9$Ro$HO-5M~Th4H^9 zgz-N!MW+G#g`dy)SFU;>exYB!byiA=V6xUPQsfx&{N8=?{Vk1p#<&;BQ4Pa6!Tp0~ z{7VWs+X@=u_o5a(msVb7*xPA$@JKg^S9UOt6Y;#vCfioXy?OKpXT!4%PlEDH$tXP4 z?>MUE9ATC<4&Wz$=e3uRzKk^WK--n+HOlbZT%|6XIxcShwp z4vt z_j0WJV~xz!y3}DrWhS6!7?q!XLuSNFu>%?Dslk=}W&F0e#Co0b-ch5#RSG`W3b>PrQqPed| zR~F4D6vT0iPS99B?BGGyP;pZsy`~(RN3Y*0=DV%hUfdg{Y3g*Op7q-zy0tOC$Dk`` zI;6AuOMTpajWjenQ#Os~sSD)+X{LMjYSxWuY=pT!+T`=1ESi_`)T*TnBrTNhWZ%5X zKWRSbquy!!b~O7|bC3Y~K|sRY7{#a;cAkDpzubx^28`6 at jwz<gXcH at i)zv at n(0$Rh*&wGAH>pYBjy)%<8J0^39_zzCZ?>!k6*eU-uBw3l-Sto zNLDd7-cg01jG{Ks%=R#d`-&!VRHmK5{7SUYPSM7mXkcc1CHW~f?mhbjbY@!ev%ph! zuDl-gBV4DiYNU3d1)dt*HGD!EZ8+Zd=lST>LtUy7v&T^Ny*j+p=_YRvvz;krq*T(% zzI%Bz&cpTeUZxAWvW_Wgw>*qDqqDSRJqhL$;q&0tzC3I8lNhDsb0_TW?WJ{JFdWag zd`Uq0inmwEIlfT?Nxe;lpcgk3Bi0ru%=TV*$n~TxeComr&8mXi)=j7V%A-93pH)7! zQ|%zWnSNDl(t>^D$D$mwH~L0gQO^E+HwgtBgyi1w42|nyUg4!fq~d$1^|cX;zMAQ;-{;I at ttiG9o)HH_loNDH4j!P7Gs=VVHRG=jBVrHZzmHD%9Qr6V3+`wA z at pz_vVcSk4SR>(v7muikXLQi*;**lsX%tH4H!i7o6-0YX%*B>Ps%ka*i1ioHxUt44 zJ*kVlVWX5nBxK2OKB_8M^|g;z<-A(aRhiP<+iSD|i>HcfV%C)66-Tx^9XW;`%Ozd< zHpZY9CYI(z0~XtgMkv?aQ at DY^ZAQ8C5Rht$hz^RM5KD4z7LGv;af*r=9B zQR^2%uQr&^7)s3Bu&f$w*sXv)tF05^Kb|^K8?F?_YJ2QeF7dz^_Wrj|J#3nt;$er! zj|=NfF at ARcpqPXT_g&U^3_VVLu2 at F!qxdt0){7S;L?@j5?$=z6K2*n{S!hXXsGu9> zdOP6Z&u_;AlqwsMTuRCE>?%vP&Nt3CY29dhH7l%Ouoh at a(VXy9PQLuw*n*y}zhC9j at D!?c45M)EQuKW~jRWU~7UFV`Y?Uk3 z2R^8|%Qe%y$rD}T${K|(n|e#LlGwSV$C7S+oU%(X@#iz2NPRkM7ZG`-tnneW=*0q_ z6yEFKtGi^ShH-nfU~_?D z at Z<~kE%lI9xqCl86*ko at 7wfL<`u!6k+^?b``MDW8fGBOj|Nd%mEFQlKz{HKIK^`Zy{JVpDxB z>MOV(D22|2vG9~RH6|kJWPZF7(aKlLsUPcP|9Pfq{Os`8PYPw;QG9uKMy&4}@SO7S zbkwP3I6KCeh#o-%h99*oC$~-^ zgEIF{%PZf9=r!Jl-Dml=E7`sMm2cUMxt<~JZ{_N%LE70jYd1bEa)yQiKSo%6b02#(s+QYbMZQ#h z_B#iaxXb2e$Z_+m+_@ zS4U7MXGl{fS-e-qS8b#}>rT8M6&c8^Yx?#fcGG=K?t1!=E^C+ at vJdIiR&uG)Q8(LX1 z21TKl^-ft7i_%9GrcV!? z8SL2VKMyKhp+mU#We={f+ zr3Stxg_pa+su-j)u3e4R$kuXMj=Os1IXvm%B_?bI at UuNqKx%3yot;nO&zZLdpJPZZ z at Ik_YKlngeTEf=W!v44;Z*{dG2n9$9YlVf+nuWu(U48zMb*#KxVNoCJ=Jh)eeKE})2!y1DtL&d`$CmGmzdwA}I8DXtmusguO8!u_Oy5Iuzy>~dq z3(gDYgVV$5;52YNgb{XwFwVkm&JcVasfV(kJ?ta_K5i9)oFPxh3UY-!AS}3qAZy48 zg8R2gtO)6nC_)A%xH>>lphQqGC?8a#kJ~>B+77w^dICBG`UScNdI>rU`V6`bMgSfN z at X=JfV1U+AhPn1xE#)(4MO>Jcj<&J^>WncgD;gN=b}ghfQf#3hbPo{*A0DRb(y zteiYbK~YIrMO6*0uA!-=t)r`VM&ID9q0u>Glk=u#<`*n5mR8nS8(TYj2S+Do7gslT z4^J;|A74NJfQx~bf-XZBgpNV*fw>m|$pAVH>jUNhD7(PBkab;ghn9md4M-U}18IZ* zH6d|G4CGS+k|u5(z_9+6R>jFv#RH3lxjxnl?+paVs=H*Alanh>7alwQDez~aLlErc z!a!3;UmqWWb9$kV)>hpGAtfCx6k7XF$QelyaS7TzC>JEg&CSUk?-d4Vhk*~MwuX-w zMq<2R*A%!Dh;gnn-~)pdk-zJ9vbV%Jt at vkevy;Ejo<9dldtt2bM-1;Oo!1lT>FtI) z4%!ReFAF;%aCY^8&p@`p`A7k2glKmjG{fx^r`;onMEz-oHz-?6AFYYs?2S9r8h6Y! z#?up+ypuoD+8g#yfOG*x`QYES17+_xBEc2E2Y39hy^A&6B=|6Lq@}kl>^lK>mh!H) z3L(*6 at bSRTuAW|?uZ~zyI^Ms6r?(UCG;XV%Q=!2~!EF-UIic7Z$tP^(~zhxeo7B9)w+v at rJgzQg?%gZm91H;i?0^|rM`db(j?M>rrkm;e~3 zzXojgc!?5>m;E2lI5_2wrtbd${;rf%Q(jm=qlE z?E*VAB4~mg7UPC*Eu8Me|Dun+_O1ka`;$-d-{$l5vi at J>I}Yb_gAYshvG?%u#yI^^ z5UfdDLO7kozb*fQs|$Q^wlEkd-1*sX7yl_=RQm6J;|_|3b?pkUHP*-8YFFBwF~a(} z0lNV+1|FH+whE^?L6F87OgnooI}a?dMBJ+g1nK|%xa?$tH?xD}w0M;h8a?b81nUV` z1kaS;4sbw6z_*jLy$k%pfjz8mc)EMLczePF=!^M((BwfMM5O<1AFwV!YpyP^cPfw? zPAm0q(_((RvHGW6oITlqFEKB?zX$N0`%klednEepD at e=U%EJ{ti63cbkL#tPfWSZF zp^5*}gVXH+so}HWPyIei96rz-x%2jhEP)Rp&OLi}JQ|$@U)K;HSJ!Gj$BM+Cq3Ktc|Y6El!1D=U-1pW`ApA9fHQQcCw61toMsM8rs!0)mi8_{~3v z(!$OHe83-CH$U*9gkQg+fGBZq^}#Rkz=^D^JfX7&DuPl#hPkMuChqU`S#7kUjuK9U z-EMaM{%!C8kV$vs^j&g1kSTZMgk5stE;(tJoV-g;*(Im$lJ)(;>~sF@`btDx5`>|Y z3{kphaWNq!O-<J$LW*-hc4$(c`}UCj)~+!y}_l zpN)-AOg?|{^3~Mz%W_O%T*8r zyFzXrg0LSaT)Z3nM(>X75&*vg>MIz4#W-PHtRXvB7h6yz>?RY)PPi~z*b^Pn(!<^h zgYzwhb+N^TTLoZo&!c`9_B#c*v&1#U+Y=_xSI`zuUwhnxGf!WvwY{gEppCr?t_*M= z47=tM^ufAd1H7?La5=xjygj^ay)pj(V0?d&xc>YThV{VtcKQcnJTSOSe}#dYUCbZs z0vd-)wJVJ?SbTf9?80EtWQB402ZM0|t96_^w12`t3E&geC^?<=?|`1*i$f z(NGDFt3x+%+yn~8aec at R#|pLnTk}^=AT(HqeLS0N2(z1NrT6YaG{xGy&H&P=KW1^!oY` zAC4a=xwAv4IMd&GxD?#^gTm`Deab at TRj;lh^IIafy;kXuLhvV9i0gj^~ zB^*aVA~2jaHqXAH0(4K z43eZYl!Bxrq%;f+ln3AwjvyUHT?hq8`=9Sm?SH;gRk6Q+`@lOZ*7w3aNP@#*r=56D zf#^R^m{9mUnix+nlok9GR at c=HcIFAY)W%_aF_0E05o3#0aP>n$u)EaVPaepFgCm1O zf+2{3Br-TMGjpnFlIcPg`%!Z~piG|M%Yi{rKOnmpgAtIGr=E zwuIHzcyUVk^se(g^wkj;|3910 at 9`h9o&5N*uixhG8sG8rN18X^O3!zqQyLQS#s=|I ziFYR2A`Rit;s$y>N-7x&CmI@~tyn*T4e}Rk at 0>ht!njy)aYlz?W5Grn+k1;LU>W-Q z`}>I=kyH!s?kKmEPkO*werTn&ymFOMzS<<;@St`2XaB)kKI0*4`PlDU%Xe)u$`705 zOST*32Tbz6f7)8^-DQ-o(aGQVSvmVPK>o)-w at bgdoDV!x&K`Tln9ojgJMK5ikD27Y zm#yXBHObBG^q*Id_Z&9L51Qo48`kN!9J4OpEypu$^Y!Bcw-eFVb+X^+{O0oXo)P-U z?a}#vamKow551GgbA!%rF7Mp)8QHhb=PvIL-m}*CjhmeYx!JznD|DvIekc67 at _DPs zn9o|Be9v$v+dJGSH>clryHRc)CxgCWl$+c8p|P2AE*hJ=oWC7wt!J9gTHaA_EkCf> zx}G;JG0OG*`drw_4ux~eztrkvLtAspzYSTS)w+C#qSo at VxKX~}B!54VJN at 9LPUcu@ zoxifex_yqXuui{!rFHtM|F)K&J7JxFo#Hac&34vfcUk7YX^_h@|9kSS(|6=s>uG7FY+o0_+5~0QbEu(k(`QUYX}4 at JfJUU%RYcoo=>yq*MI z4?GC80gC}2PzKxq6aorx at g0SA1BZcUfhU0P0c}77-~sLc6yW^tp%-`x`ELT&0UbaD zXaKyx9^^Rn);1ys8upU?o96)}%fi9pAY1e at +2ZHF24&b}MBfwL@ z0pK*y1LU1i*a%<}Fde7^ntqqA!D4DW+3s&qagL(n zjGLZoss_Fn=P4(hY--%K)i_TD>DSON+5O@)Rw3S>*D6zbLUfTR8gEC6S8X_*O%H`t zXEGTNElwp>T4=s(uL;EFht#EWnn=c$%ajy=Bo>M^BbJA`!_kCViSrBMoFi=%p*Ga2 zve%g>n(!bAg=(W|{u$d0Lz&ujIXl^`ym^sUgXVpC;Y2bXR_Sm#N|7g0XD}G&H}ZNE z`Yn2ST>vpg+H2_khN~TVqYFYo)!h<^vlp004Xc`th at E~no at dU^Xk|`c5PL&w4?jKH zsD~~(Ush?G&X2|Ntc$WWQ0!W at HAcD54zv>Q zUXAAsBwG;vfV9^{gQ>7=Rq&QmocZF7iWN99KaBDxQfO3u-vl!-)xjGNMdP7lyE`19 zc6oyGai`*OHIlx*_-{I%mbQp$Bm!Cv?BR at kQ96|151CTw%D&1jez#q3O~s;zLTw^F zy}Yq10;BzEHs4QAF3E~!RrqFCq;2*?oBruQ3Ga<)BR&1R-o7*uLz-lhleH-*w?+v9k9*899RiBc{*jE&< zsxHyRVHJ^}HvrW*&r at FF5=D)QDm0>GH!_#n9E!*o55wA;#FGwgt2E8biv^)TKK@{P z6n{%}sTOLM?JdI8!{0>Nn?q0$=iP}MerY2+N9QG?*e4EBYNF|fDQpduNCbT72(+~~ zn$X$ZJd%3@)a`5`Zzb7q=_n(4`v at juF=|_(N_#rPduEb0dsMkXNeoi#0pz$64}uu` zCrU}(;f{uBZ2v@|z?>A#T1_N#Evcb5^HX1ikwQy1MVkYnWGg-y@<+p=pevrDXR$Lp zRk9dO)HZWdYP_A_*F?^D5Qk4hv($FhY?M=TvP$ArL{hDYK#Y0{&xxrK8D2_Z?KUV+ zF_GuViy`COO&n2OaGcDU3Cn_{Z_)79Dzsr<4u>n2sg0OZoy=cZQLP#I66TK1i)60s z(Jdr*RH&lD0vbQ=N(Q?AoPNs(~1vfY>JP7nfOw+O#OO z(M&?<)$zsLm7c$~c~JL!&(*HYbZ$G15Sj>r-cU?s$F$hB^y1#*7%ybJm`*~-)35To zMp%!OYBkWNX7R&(7KBzYWupDJbBp9AAvyobYvWTzeR|FF~ zpY_B;w(3v>Jy9lR?La)4ic#gzw|TYN?Ys0{?@FvhEj;UB#j-{+_kmMI!{tMjzQs5Y8jp;%O_cYQRXZ)dC(ywqOev6q!9YE8O~s0OPd zjd7K3-7)rpp6^l9d_Se7N4l(#@}E;tL;h}*YCgRM*-h7>X_}jsSF5}CTt*>z^Z8rk zPv4H7N+E7iPi3tjRair|@SYLY%h*;P@~Bv}qwOq^H(%TW<>~jy`NC`fLu}In$w1f{ zi&4*EF4t1Y^87Gw0aEa_haIEUt|D_yaeg2kqRXI8_Ujyy1?(b8gq^sfDQctD!YcT+ zQEHt>bYVV4u}AH`WO!bLUK!1{Q+h2nHX|adID1jw126*^1lsjkB{OPGHFZXUe(aq@ zA!hNtg|5J2MZ|Q!pGuQ0VAVNNEMPAVoC2d_p`A~LUNz3m3o{GXj?&*Rtgms2Y?Gg6 z?-|g&rT{L95?q7aRJ+JhQ7h!a=je+;lN24MZw?kW#fMZOc{7p=uG zWFIk_q{aLs1hn at 3PP1IWVlLbCFct-}1{Z(1G)C)MVIi`Qoa|9ue`5WKrINgt4Y3xm zpK at E}8$EW;SQ?aiKIY%n7}m{nUHwK5?F at v?1?6Uyjn;OkXgtb$z at z6E?$6lu!;P6I z-Zef#(n3jx01WuBR)jT2 at lVx?_(ZQ1-ydyCE`=F3q%To7i2YxpL5^Q}Txgib|EUzf zo`K%ma}fE^|D^VU4hMY_l-}307L?wblmw;sIW>UN&tg=A-U2!alun~1R5s9J(0t(V zE#=zln%G6Zi#)2J!?Y>_=<7Fm4xz3nKbMZaF_xfu;Q+s(mpDjK61KJ0m zGSQr;ja|E>G#}9%Hwd72wOt1cW{l5w^e(r2Ne4 at MgOvT1PBu)YCHiHVZ-L|u1#Xfc z{?{b`E*W;puv><`GL292{gN(_`7e~Z!;(+mOLYLWwHN`!Wm&J2 at jGRiS4g^2%2!GG zYMIaX0s1P;1{r=_mS>C9_b-zFGg-dZr2N06y!d+27FwJAaa=)8C*+Qt?vGZ)|5um$ zvbK=tzD)f2mit<|zjPar?oZtmKENEU4$-Lxoo{vD5V-&`ytbC2J9 z+`+zc{Qlz;v*Z8j*vamX7%S}%DG$Ev;{P*sOS#p)^Rqbm9{;rr+gNs4hcI{Af8al` zPdR`y!7p5V?=a!ASc8dDU-wH_V9HZZKPf+#{FBDdCI37ft+gNSck#9LASkWj8$oGJ z&)+Z3YbW-(_}cs=DD5}afZhz+uuq)hO7 at BK-Q}N)^WICKUjbbUN_&SO=vP5Kpd&%M zpLg-S#WqkHk306d7`>mg0CX7 at 3Y5N}aPc`8qgkdKlm_JqP}=+*e9o2ChScYsH?U9b z*1v%LF>sgT>OlKE+OJW0Z;<+_j`R+RdddGGunRZ>{0}e`g`NP+23l>IG*g(^e=TMF zd%0{U at GIbbY7@j857Yo*U8QLpyoxbS at 2<$l__#FW%6LFJ8c&oJrPZ<|J8%s8!L97i z%w6gGe2U50rPI=rhvv~f(|Kf|dFu0U;<<;N_um+7%jvvP4oc%PCbsFics52~GFX$v z&tr5Cdn5R?|K9^j`~SnB6#wi1`Pc->;*%@ZHH^lmGvAmT{CjfnD|7Jca`0QgU*@#) zpME_h9|(2Mva^l0OxRIlXL(8{Tr$Vb>UH7Hxpr2li@(kXxh{-0=508ZYZc6mgISg% zb2)S73_E%9Bs+TaD0}|-=h^DjtC`E?Vv{FNW~HU2?DpGlXT`_6Ghwl<3N z7e1Z)OG)=`f4?N~=sx?i`2B`-G?E1oLt6XH=JT+Y?p+bqR2ZC at uTR&%dmn}ScXxH| z>qlTWeUjhE?;@g4_pxsgW!39*y6W+{&{xm>i-_NM;a%=04iSC29>-`(w-u{)(e|wc zg$4A<*yvZl at 4LYHqxmNrZAjN!J`>44o?Gg4me$XOZPKUHS+C>Q^Us2rMtucED0+{h zsB3FM5!4mZrqF6t zD0gU7S^x1$-Qe^~!O`kbY8QeUO7PUtJZXMHb1!auWjZdUyY)nLJG1)_e#y1ID% zf~2+RVeo|?UN(?E-iA_ZrSuOi)%f&TYS!mqqUWfV=ri=E^cNOreEKXj)$e061z{ug zWFvs|FZ5}Ae7Y8x+EbWbpJtPNWS7#vyGyfG`ZVc-!C!`@r-vMcG!PLV)RRVi=@B7m zKOYbR+PEO}I7XY&3Cq{0tfQ`;>9BFUU(j+Av`4h5u3bf#>TXOYEWcmS3&K+M{V2lP z^rF+pEx*5yQ~uebS*x(2jBO62Pv)A at H$(f(*rrKe5$~g|Gy*hTQWI$%wl!^=CVfM> zO<=IsYx?9U;QD6FEzO~iW#$&CPaAbTat_F)kK6phxuuH+&^NR+ZJSy3quP+l(F4>^ z%mxGLtGfJ=Y`vKSwCB+JUQ2zv-^kb1W$3 at 6?L8LtlVjcIEEwvl8^B%$(8ou-u)`wq zv)c-??K3-_81cg9>)}UWfbno4E1g_y#8 at YP*FNL8?@NybL%Q at 5r(f*M{tMaZKB4=Q zNoQl3^FTSw#-0iA))W%aZYfAre)`Y2&iobLeK?`* zVmGpP&25sd??1A;QEoBtRx+u7~{j87cSoMk9U6k|3 zyqp(vmU9Dh>B?D^vpud{W^_ at x%XU4R2z?4KQzx6wTR6yVQ&=8Z=s5m2kPTeRG1>#W z)oj3O94%(_(;*?*>tb}|vI`oMRnVr5TN>p7J_ at zmsEyhXTZKd$k&VceVm0%;$=A+h znSA1wwwU1UAVzvKLSuQJnHsqen|$UO z;>fd^*ExYddgChnAJfP!HRWiN`3IPf~nwq?JDw)H^{+tS)p z*gdTZE!@IVy#Mqwi}j4WG*_Qo<=7YV_82~IpVy83vh<5vm$il?iK(Mf at yL`!V~g4v zNZi?~-LIiHt4;|dTF14Oj&igHBB3TVpI;wQsgi+JJbc4fDmW-zo{9FH5ncFu- zI;2dfjVbzyfeeF_ejO%#Hy{*No7F^Gs27WC)F?=`+NOpbVfvgpDv+p(v_+Sw at llRc z$k|Aj?xv1v3WO8tsA*;6b0p3vAD>%$*?2=)%f_cGjd0m`tv#oConEKMQ#E@=U7hs& EAFIfB4gdfE diff --git a/Lib/packaging/compat.py b/Lib/packaging/compat.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/compat.py @@ -0,0 +1,57 @@ +"""Compatibility helpers. + +This module provides classes, variables and imports which are used to +support packaging across Python 2.x and 3.x. +""" + +from packaging import logger + + +# XXX Having two classes with the same name is not a good thing. +# XXX 2to3-related code should move from util to this module + +# TODO Move common code here: PY3 (bool indicating if we're on 3.x), any, etc. + +try: + from packaging.util import Mixin2to3 as _Mixin2to3 + _CONVERT = True + _KLASS = _Mixin2to3 +except ImportError: + _CONVERT = False + _KLASS = object + +__all__ = ['Mixin2to3'] + + +class Mixin2to3(_KLASS): + """ The base class which can be used for refactoring. When run under + Python 3.0, the run_2to3 method provided by Mixin2to3 is overridden. + When run on Python 2.x, it merely creates a class which overrides run_2to3, + yet does nothing in particular with it. + """ + if _CONVERT: + + def _run_2to3(self, files, doctests=[], fixers=[]): + """ Takes a list of files and doctests, and performs conversion + on those. + - First, the files which contain the code(`files`) are converted. + - Second, the doctests in `files` are converted. + - Thirdly, the doctests in `doctests` are converted. + """ + if fixers: + self.fixer_names = fixers + + logger.info('converting Python code') + _KLASS.run_2to3(self, files) + + logger.info('converting doctests in Python files') + _KLASS.run_2to3(self, files, doctests_only=True) + + if doctests != []: + logger.info('converting doctest in text files') + _KLASS.run_2to3(self, doctests, doctests_only=True) + else: + # If run on Python 2.x, there is nothing to do. + + def _run_2to3(self, files, doctests=[], fixers=[]): + pass diff --git a/Lib/packaging/compiler/__init__.py b/Lib/packaging/compiler/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/compiler/__init__.py @@ -0,0 +1,282 @@ +"""Compiler abstraction model used by packaging. + +An abstract base class is defined in the ccompiler submodule, and +concrete implementations suitable for various platforms are defined in +the other submodules. The extension module is also placed in this +package. + +In general, code should not instantiate compiler classes directly but +use the new_compiler and customize_compiler functions provided in this +module. + +The compiler system has a registration API: get_default_compiler, +set_compiler, show_compilers. +""" + +import os +import sys +import re + +import sysconfig +from packaging.util import resolve_name +from packaging.errors import PackagingPlatformError + + +def customize_compiler(compiler): + """Do any platform-specific customization of a CCompiler instance. + + Mainly needed on Unix, so we can plug in the information that + varies across Unices and is stored in Python's Makefile. + """ + if compiler.name == "unix": + cc, cxx, opt, cflags, ccshared, ldshared, so_ext, ar, ar_flags = ( + sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS', + 'CCSHARED', 'LDSHARED', 'SO', 'AR', + 'ARFLAGS')) + + if 'CC' in os.environ: + cc = os.environ['CC'] + if 'CXX' in os.environ: + cxx = os.environ['CXX'] + if 'LDSHARED' in os.environ: + ldshared = os.environ['LDSHARED'] + if 'CPP' in os.environ: + cpp = os.environ['CPP'] + else: + cpp = cc + " -E" # not always + if 'LDFLAGS' in os.environ: + ldshared = ldshared + ' ' + os.environ['LDFLAGS'] + if 'CFLAGS' in os.environ: + cflags = opt + ' ' + os.environ['CFLAGS'] + ldshared = ldshared + ' ' + os.environ['CFLAGS'] + if 'CPPFLAGS' in os.environ: + cpp = cpp + ' ' + os.environ['CPPFLAGS'] + cflags = cflags + ' ' + os.environ['CPPFLAGS'] + ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] + if 'AR' in os.environ: + ar = os.environ['AR'] + if 'ARFLAGS' in os.environ: + archiver = ar + ' ' + os.environ['ARFLAGS'] + else: + if ar_flags is not None: + archiver = ar + ' ' + ar_flags + else: + # see if its the proper default value + # mmm I don't want to backport the makefile + archiver = ar + ' rc' + + cc_cmd = cc + ' ' + cflags + compiler.set_executables( + preprocessor=cpp, + compiler=cc_cmd, + compiler_so=cc_cmd + ' ' + ccshared, + compiler_cxx=cxx, + linker_so=ldshared, + linker_exe=cc, + archiver=archiver) + + compiler.shared_lib_extension = so_ext + + +# Map a sys.platform/os.name ('posix', 'nt') to the default compiler +# type for that platform. Keys are interpreted as re match +# patterns. Order is important; platform mappings are preferred over +# OS names. +_default_compilers = ( + + # Platform string mappings + + # on a cygwin built python we can use gcc like an ordinary UNIXish + # compiler + ('cygwin.*', 'unix'), + ('os2emx', 'emx'), + + # OS name mappings + ('posix', 'unix'), + ('nt', 'msvc'), + + ) + +def get_default_compiler(osname=None, platform=None): + """ Determine the default compiler to use for the given platform. + + osname should be one of the standard Python OS names (i.e. the + ones returned by os.name) and platform the common value + returned by sys.platform for the platform in question. + + The default values are os.name and sys.platform in case the + parameters are not given. + + """ + if osname is None: + osname = os.name + if platform is None: + platform = sys.platform + for pattern, compiler in _default_compilers: + if re.match(pattern, platform) is not None or \ + re.match(pattern, osname) is not None: + return compiler + # Defaults to Unix compiler + return 'unix' + + +# compiler mapping +# XXX useful to expose them? (i.e. get_compiler_names) +_COMPILERS = { + 'unix': 'packaging.compiler.unixccompiler.UnixCCompiler', + 'msvc': 'packaging.compiler.msvccompiler.MSVCCompiler', + 'cygwin': 'packaging.compiler.cygwinccompiler.CygwinCCompiler', + 'mingw32': 'packaging.compiler.cygwinccompiler.Mingw32CCompiler', + 'bcpp': 'packaging.compiler.bcppcompiler.BCPPCompiler', +} + +def set_compiler(location): + """Add or change a compiler""" + cls = resolve_name(location) + # XXX we want to check the class here + _COMPILERS[cls.name] = cls + + +def show_compilers(): + """Print list of available compilers (used by the "--help-compiler" + options to "build", "build_ext", "build_clib"). + """ + from packaging.fancy_getopt import FancyGetopt + compilers = [] + + for name, cls in _COMPILERS.items(): + if isinstance(cls, str): + cls = resolve_name(cls) + _COMPILERS[name] = cls + + compilers.append(("compiler=" + name, None, cls.description)) + + compilers.sort() + pretty_printer = FancyGetopt(compilers) + pretty_printer.print_help("List of available compilers:") + + +def new_compiler(plat=None, compiler=None, verbose=0, dry_run=False, + force=False): + """Generate an instance of some CCompiler subclass for the supplied + platform/compiler combination. 'plat' defaults to 'os.name' + (eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler + for that platform. Currently only 'posix' and 'nt' are supported, and + the default compilers are "traditional Unix interface" (UnixCCompiler + class) and Visual C++ (MSVCCompiler class). Note that it's perfectly + possible to ask for a Unix compiler object under Windows, and a + Microsoft compiler object under Unix -- if you supply a value for + 'compiler', 'plat' is ignored. + """ + if plat is None: + plat = os.name + + try: + if compiler is None: + compiler = get_default_compiler(plat) + + cls = _COMPILERS[compiler] + except KeyError: + msg = "don't know how to compile C/C++ code on platform '%s'" % plat + if compiler is not None: + msg = msg + " with '%s' compiler" % compiler + raise PackagingPlatformError(msg) + + if isinstance(cls, str): + cls = resolve_name(cls) + _COMPILERS[compiler] = cls + + + # XXX The None is necessary to preserve backwards compatibility + # with classes that expect verbose to be the first positional + # argument. + return cls(None, dry_run, force) + + +def gen_preprocess_options(macros, include_dirs): + """Generate C pre-processor options (-D, -U, -I) as used by at least + two types of compilers: the typical Unix compiler and Visual C++. + 'macros' is the usual thing, a list of 1- or 2-tuples, where (name,) + means undefine (-U) macro 'name', and (name,value) means define (-D) + macro 'name' to 'value'. 'include_dirs' is just a list of directory + names to be added to the header file search path (-I). Returns a list + of command-line options suitable for either Unix compilers or Visual + C++. + """ + # XXX it would be nice (mainly aesthetic, and so we don't generate + # stupid-looking command lines) to go over 'macros' and eliminate + # redundant definitions/undefinitions (ie. ensure that only the + # latest mention of a particular macro winds up on the command + # line). I don't think it's essential, though, since most (all?) + # Unix C compilers only pay attention to the latest -D or -U + # mention of a macro on their command line. Similar situation for + # 'include_dirs'. I'm punting on both for now. Anyways, weeding out + # redundancies like this should probably be the province of + # CCompiler, since the data structures used are inherited from it + # and therefore common to all CCompiler classes. + + pp_opts = [] + for macro in macros: + + if not isinstance(macro, tuple) and 1 <= len(macro) <= 2: + raise TypeError( + "bad macro definition '%s': each element of 'macros'" + "list must be a 1- or 2-tuple" % macro) + + if len(macro) == 1: # undefine this macro + pp_opts.append("-U%s" % macro[0]) + elif len(macro) == 2: + if macro[1] is None: # define with no explicit value + pp_opts.append("-D%s" % macro[0]) + else: + # XXX *don't* need to be clever about quoting the + # macro value here, because we're going to avoid the + # shell at all costs when we spawn the command! + pp_opts.append("-D%s=%s" % macro) + + for dir in include_dirs: + pp_opts.append("-I%s" % dir) + + return pp_opts + + +def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries): + """Generate linker options for searching library directories and + linking with specific libraries. + + 'libraries' and 'library_dirs' are, respectively, lists of library names + (not filenames!) and search directories. Returns a list of command-line + options suitable for use with some compiler (depending on the two format + strings passed in). + """ + lib_opts = [] + + for dir in library_dirs: + lib_opts.append(compiler.library_dir_option(dir)) + + for dir in runtime_library_dirs: + opt = compiler.runtime_library_dir_option(dir) + if isinstance(opt, list): + lib_opts.extend(opt) + else: + lib_opts.append(opt) + + # XXX it's important that we *not* remove redundant library mentions! + # sometimes you really do have to say "-lfoo -lbar -lfoo" in order to + # resolve all symbols. I just hope we never have to say "-lfoo obj.o + # -lbar" to get things to work -- that's certainly a possibility, but a + # pretty nasty way to arrange your C code. + + for lib in libraries: + lib_dir, lib_name = os.path.split(lib) + if lib_dir != '': + lib_file = compiler.find_library_file([lib_dir], lib_name) + if lib_file is not None: + lib_opts.append(lib_file) + else: + compiler.warn("no library file corresponding to " + "'%s' found (skipping)" % lib) + else: + lib_opts.append(compiler.library_option(lib)) + + return lib_opts diff --git a/Lib/packaging/compiler/bcppcompiler.py b/Lib/packaging/compiler/bcppcompiler.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/compiler/bcppcompiler.py @@ -0,0 +1,356 @@ +"""CCompiler implementation for the Borland C++ compiler.""" + +# This implementation by Lyle Johnson, based on the original msvccompiler.py +# module and using the directions originally published by Gordon Williams. + +# XXX looks like there's a LOT of overlap between these two classes: +# someone should sit down and factor out the common code as +# WindowsCCompiler! --GPW + +import os + +from packaging.errors import (PackagingExecError, CompileError, LibError, + LinkError, UnknownFileError) +from packaging.compiler.ccompiler import CCompiler +from packaging.compiler import gen_preprocess_options +from packaging.file_util import write_file +from packaging.dep_util import newer +from packaging import logger + + +class BCPPCompiler(CCompiler) : + """Concrete class that implements an interface to the Borland C/C++ + compiler, as defined by the CCompiler abstract class. + """ + + name = 'bcpp' + description = 'Borland C++ Compiler' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = _c_extensions + _cpp_extensions + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + + def __init__(self, verbose=0, dry_run=False, force=False): + CCompiler.__init__(self, verbose, dry_run, force) + + # These executables are assumed to all be in the path. + # Borland doesn't seem to use any special registry settings to + # indicate their installation locations. + + self.cc = "bcc32.exe" + self.linker = "ilink32.exe" + self.lib = "tlib.exe" + + self.preprocess_options = None + self.compile_options = ['/tWM', '/O2', '/q', '/g0'] + self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0'] + + self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x'] + self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x'] + self.ldflags_static = [] + self.ldflags_exe = ['/Gn', '/q', '/x'] + self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r'] + + + # -- Worker methods ------------------------------------------------ + + def compile(self, sources, + output_dir=None, macros=None, include_dirs=None, debug=False, + extra_preargs=None, extra_postargs=None, depends=None): + + macros, objects, extra_postargs, pp_opts, build = \ + self._setup_compile(output_dir, macros, include_dirs, sources, + depends, extra_postargs) + compile_opts = extra_preargs or [] + compile_opts.append('-c') + if debug: + compile_opts.extend(self.compile_options_debug) + else: + compile_opts.extend(self.compile_options) + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + # XXX why do the normpath here? + src = os.path.normpath(src) + obj = os.path.normpath(obj) + # XXX _setup_compile() did a mkpath() too but before the normpath. + # Is it possible to skip the normpath? + self.mkpath(os.path.dirname(obj)) + + if ext == '.res': + # This is already a binary file -- skip it. + continue # the 'for' loop + if ext == '.rc': + # This needs to be compiled to a .res file -- do it now. + try: + self.spawn(["brcc32", "-fo", obj, src]) + except PackagingExecError as msg: + raise CompileError(msg) + continue # the 'for' loop + + # The next two are both for the real compiler. + if ext in self._c_extensions: + input_opt = "" + elif ext in self._cpp_extensions: + input_opt = "-P" + else: + # Unknown file type -- no extra options. The compiler + # will probably fail, but let it just in case this is a + # file the compiler recognizes even if we don't. + input_opt = "" + + output_opt = "-o" + obj + + # Compiler command line syntax is: "bcc32 [options] file(s)". + # Note that the source file names must appear at the end of + # the command line. + try: + self.spawn([self.cc] + compile_opts + pp_opts + + [input_opt, output_opt] + + extra_postargs + [src]) + except PackagingExecError as msg: + raise CompileError(msg) + + return objects + + + def create_static_lib(self, objects, output_libname, output_dir=None, + debug=False, target_lang=None): + objects, output_dir = self._fix_object_args(objects, output_dir) + output_filename = \ + self.library_filename(output_libname, output_dir=output_dir) + + if self._need_link(objects, output_filename): + lib_args = [output_filename, '/u'] + objects + if debug: + pass # XXX what goes here? + try: + self.spawn([self.lib] + lib_args) + except PackagingExecError as msg: + raise LibError(msg) + else: + logger.debug("skipping %s (up-to-date)", output_filename) + + + def link(self, target_desc, objects, output_filename, output_dir=None, + libraries=None, library_dirs=None, runtime_library_dirs=None, + export_symbols=None, debug=False, extra_preargs=None, + extra_postargs=None, build_temp=None, target_lang=None): + + # XXX this ignores 'build_temp'! should follow the lead of + # msvccompiler.py + + objects, output_dir = self._fix_object_args(objects, output_dir) + libraries, library_dirs, runtime_library_dirs = \ + self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) + + if runtime_library_dirs: + logger.warning("don't know what to do with " + "'runtime_library_dirs': %r", runtime_library_dirs) + + if output_dir is not None: + output_filename = os.path.join(output_dir, output_filename) + + if self._need_link(objects, output_filename): + + # Figure out linker args based on type of target. + if target_desc == CCompiler.EXECUTABLE: + startup_obj = 'c0w32' + if debug: + ld_args = self.ldflags_exe_debug[:] + else: + ld_args = self.ldflags_exe[:] + else: + startup_obj = 'c0d32' + if debug: + ld_args = self.ldflags_shared_debug[:] + else: + ld_args = self.ldflags_shared[:] + + + # Create a temporary exports file for use by the linker + if export_symbols is None: + def_file = '' + else: + head, tail = os.path.split(output_filename) + modname, ext = os.path.splitext(tail) + temp_dir = os.path.dirname(objects[0]) # preserve tree structure + def_file = os.path.join(temp_dir, '%s.def' % modname) + contents = ['EXPORTS'] + for sym in (export_symbols or []): + contents.append(' %s=_%s' % (sym, sym)) + self.execute(write_file, (def_file, contents), + "writing %s" % def_file) + + # Borland C++ has problems with '/' in paths + objects2 = [os.path.normpath(o) for o in objects] + # split objects in .obj and .res files + # Borland C++ needs them at different positions in the command line + objects = [startup_obj] + resources = [] + for file in objects2: + base, ext = os.path.splitext(os.path.normcase(file)) + if ext == '.res': + resources.append(file) + else: + objects.append(file) + + + for l in library_dirs: + ld_args.append("/L%s" % os.path.normpath(l)) + ld_args.append("/L.") # we sometimes use relative paths + + # list of object files + ld_args.extend(objects) + + # XXX the command line syntax for Borland C++ is a bit wonky; + # certain filenames are jammed together in one big string, but + # comma-delimited. This doesn't mesh too well with the + # Unix-centric attitude (with a DOS/Windows quoting hack) of + # 'spawn()', so constructing the argument list is a bit + # awkward. Note that doing the obvious thing and jamming all + # the filenames and commas into one argument would be wrong, + # because 'spawn()' would quote any filenames with spaces in + # them. Arghghh!. Apparently it works fine as coded... + + # name of dll/exe file + ld_args.extend((',',output_filename)) + # no map file and start libraries + ld_args.append(',,') + + for lib in libraries: + # see if we find it and if there is a bcpp specific lib + # (xxx_bcpp.lib) + libfile = self.find_library_file(library_dirs, lib, debug) + if libfile is None: + ld_args.append(lib) + # probably a BCPP internal library -- don't warn + else: + # full name which prefers bcpp_xxx.lib over xxx.lib + ld_args.append(libfile) + + # some default libraries + ld_args.append('import32') + ld_args.append('cw32mt') + + # def file for export symbols + ld_args.extend((',',def_file)) + # add resource files + ld_args.append(',') + ld_args.extend(resources) + + + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + + self.mkpath(os.path.dirname(output_filename)) + try: + self.spawn([self.linker] + ld_args) + except PackagingExecError as msg: + raise LinkError(msg) + + else: + logger.debug("skipping %s (up-to-date)", output_filename) + + # -- Miscellaneous methods ----------------------------------------- + + + def find_library_file(self, dirs, lib, debug=False): + # List of effective library names to try, in order of preference: + # xxx_bcpp.lib is better than xxx.lib + # and xxx_d.lib is better than xxx.lib if debug is set + # + # The "_bcpp" suffix is to handle a Python installation for people + # with multiple compilers (primarily Packaging hackers, I suspect + # ;-). The idea is they'd have one static library for each + # compiler they care about, since (almost?) every Windows compiler + # seems to have a different format for static libraries. + if debug: + dlib = (lib + "_d") + try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib) + else: + try_names = (lib + "_bcpp", lib) + + for dir in dirs: + for name in try_names: + libfile = os.path.join(dir, self.library_filename(name)) + if os.path.exists(libfile): + return libfile + else: + # Oops, didn't find it in *any* of 'dirs' + return None + + # overwrite the one from CCompiler to support rc and res-files + def object_filenames(self, source_filenames, strip_dir=False, + output_dir=''): + if output_dir is None: + output_dir = '' + obj_names = [] + for src_name in source_filenames: + # use normcase to make sure '.rc' is really '.rc' and not '.RC' + base, ext = os.path.splitext(os.path.normcase(src_name)) + if ext not in (self.src_extensions + ['.rc','.res']): + raise UnknownFileError("unknown file type '%s' (from '%s')" % \ + (ext, src_name)) + if strip_dir: + base = os.path.basename(base) + if ext == '.res': + # these can go unchanged + obj_names.append(os.path.join(output_dir, base + ext)) + elif ext == '.rc': + # these need to be compiled to .res-files + obj_names.append(os.path.join(output_dir, base + '.res')) + else: + obj_names.append(os.path.join(output_dir, + base + self.obj_extension)) + return obj_names + + + def preprocess(self, source, output_file=None, macros=None, + include_dirs=None, extra_preargs=None, + extra_postargs=None): + _, macros, include_dirs = \ + self._fix_compile_args(None, macros, include_dirs) + pp_opts = gen_preprocess_options(macros, include_dirs) + pp_args = ['cpp32.exe'] + pp_opts + if output_file is not None: + pp_args.append('-o' + output_file) + if extra_preargs: + pp_args[:0] = extra_preargs + if extra_postargs: + pp_args.extend(extra_postargs) + pp_args.append(source) + + # We need to preprocess: either we're being forced to, or the + # source file is newer than the target (or the target doesn't + # exist). + if self.force or output_file is None or newer(source, output_file): + if output_file: + self.mkpath(os.path.dirname(output_file)) + try: + self.spawn(pp_args) + except PackagingExecError as msg: + print(msg) + raise CompileError(msg) diff --git a/Lib/packaging/compiler/ccompiler.py b/Lib/packaging/compiler/ccompiler.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/compiler/ccompiler.py @@ -0,0 +1,868 @@ +"""Abstract base class for compilers. + +This modules contains CCompiler, an abstract base class that defines the +interface for the compiler abstraction model used by packaging. +""" + +import os +import sys +from shutil import move +from packaging import logger +from packaging.util import split_quoted, execute, newer_group, spawn +from packaging.errors import (CompileError, LinkError, UnknownFileError) +from packaging.compiler import gen_preprocess_options + + +class CCompiler: + """Abstract base class to define the interface that must be implemented + by real compiler classes. Also has some utility methods used by + several compiler classes. + + The basic idea behind a compiler abstraction class is that each + instance can be used for all the compile/link steps in building a + single project. Thus, attributes common to all of those compile and + link steps -- include directories, macros to define, libraries to link + against, etc. -- are attributes of the compiler instance. To allow for + variability in how individual files are treated, most of those + attributes may be varied on a per-compilation or per-link basis. + """ + + # 'name' is a class attribute that identifies this class. It + # keeps code that wants to know what kind of compiler it's dealing with + # from having to import all possible compiler classes just to do an + # 'isinstance'. + name = None + description = None + + # XXX things not handled by this compiler abstraction model: + # * client can't provide additional options for a compiler, + # e.g. warning, optimization, debugging flags. Perhaps this + # should be the domain of concrete compiler abstraction classes + # (UnixCCompiler, MSVCCompiler, etc.) -- or perhaps the base + # class should have methods for the common ones. + # * can't completely override the include or library searchg + # path, ie. no "cc -I -Idir1 -Idir2" or "cc -L -Ldir1 -Ldir2". + # I'm not sure how widely supported this is even by Unix + # compilers, much less on other platforms. And I'm even less + # sure how useful it is; maybe for cross-compiling, but + # support for that is a ways off. (And anyways, cross + # compilers probably have a dedicated binary with the + # right paths compiled in. I hope.) + # * can't do really freaky things with the library list/library + # dirs, e.g. "-Ldir1 -lfoo -Ldir2 -lfoo" to link against + # different versions of libfoo.a in different locations. I + # think this is useless without the ability to null out the + # library search path anyways. + + + # Subclasses that rely on the standard filename generation methods + # implemented below should override these; see the comment near + # those methods ('object_filenames()' et. al.) for details: + src_extensions = None # list of strings + obj_extension = None # string + static_lib_extension = None + shared_lib_extension = None # string + static_lib_format = None # format string + shared_lib_format = None # prob. same as static_lib_format + exe_extension = None # string + + # Default language settings. language_map is used to detect a source + # file or Extension target language, checking source filenames. + # language_order is used to detect the language precedence, when deciding + # what language to use when mixing source types. For example, if some + # extension has two files with ".c" extension, and one with ".cpp", it + # is still linked as c++. + language_map = {".c": "c", + ".cc": "c++", + ".cpp": "c++", + ".cxx": "c++", + ".m": "objc", + } + language_order = ["c++", "objc", "c"] + + def __init__(self, verbose=0, dry_run=False, force=False): + self.dry_run = dry_run + self.force = force + self.verbose = verbose + + # 'output_dir': a common output directory for object, library, + # shared object, and shared library files + self.output_dir = None + + # 'macros': a list of macro definitions (or undefinitions). A + # macro definition is a 2-tuple (name, value), where the value is + # either a string or None (no explicit value). A macro + # undefinition is a 1-tuple (name,). + self.macros = [] + + # 'include_dirs': a list of directories to search for include files + self.include_dirs = [] + + # 'libraries': a list of libraries to include in any link + # (library names, not filenames: eg. "foo" not "libfoo.a") + self.libraries = [] + + # 'library_dirs': a list of directories to search for libraries + self.library_dirs = [] + + # 'runtime_library_dirs': a list of directories to search for + # shared libraries/objects at runtime + self.runtime_library_dirs = [] + + # 'objects': a list of object files (or similar, such as explicitly + # named library files) to include on any link + self.objects = [] + + for key, value in self.executables.items(): + self.set_executable(key, value) + + def set_executables(self, **args): + """Define the executables (and options for them) that will be run + to perform the various stages of compilation. The exact set of + executables that may be specified here depends on the compiler + class (via the 'executables' class attribute), but most will have: + compiler the C/C++ compiler + linker_so linker used to create shared objects and libraries + linker_exe linker used to create binary executables + archiver static library creator + + On platforms with a command line (Unix, DOS/Windows), each of these + is a string that will be split into executable name and (optional) + list of arguments. (Splitting the string is done similarly to how + Unix shells operate: words are delimited by spaces, but quotes and + backslashes can override this. See + 'distutils.util.split_quoted()'.) + """ + + # Note that some CCompiler implementation classes will define class + # attributes 'cpp', 'cc', etc. with hard-coded executable names; + # this is appropriate when a compiler class is for exactly one + # compiler/OS combination (eg. MSVCCompiler). Other compiler + # classes (UnixCCompiler, in particular) are driven by information + # discovered at run-time, since there are many different ways to do + # basically the same things with Unix C compilers. + + for key, value in args.items(): + if key not in self.executables: + raise ValueError("unknown executable '%s' for class %s" % \ + (key, self.__class__.__name__)) + self.set_executable(key, value) + + def set_executable(self, key, value): + if isinstance(value, str): + setattr(self, key, split_quoted(value)) + else: + setattr(self, key, value) + + def _find_macro(self, name): + i = 0 + for defn in self.macros: + if defn[0] == name: + return i + i = i + 1 + return None + + def _check_macro_definitions(self, definitions): + """Ensures that every element of 'definitions' is a valid macro + definition, ie. either (name,value) 2-tuple or a (name,) tuple. Do + nothing if all definitions are OK, raise TypeError otherwise. + """ + for defn in definitions: + if not (isinstance(defn, tuple) and + (len(defn) == 1 or + (len(defn) == 2 and + (isinstance(defn[1], str) or defn[1] is None))) and + isinstance(defn[0], str)): + raise TypeError(("invalid macro definition '%s': " % defn) + \ + "must be tuple (string,), (string, string), or " + \ + "(string, None)") + + + # -- Bookkeeping methods ------------------------------------------- + + def define_macro(self, name, value=None): + """Define a preprocessor macro for all compilations driven by this + compiler object. The optional parameter 'value' should be a + string; if it is not supplied, then the macro will be defined + without an explicit value and the exact outcome depends on the + compiler used (XXX true? does ANSI say anything about this?) + """ + # Delete from the list of macro definitions/undefinitions if + # already there (so that this one will take precedence). + i = self._find_macro(name) + if i is not None: + del self.macros[i] + + defn = (name, value) + self.macros.append(defn) + + def undefine_macro(self, name): + """Undefine a preprocessor macro for all compilations driven by + this compiler object. If the same macro is defined by + 'define_macro()' and undefined by 'undefine_macro()' the last call + takes precedence (including multiple redefinitions or + undefinitions). If the macro is redefined/undefined on a + per-compilation basis (ie. in the call to 'compile()'), then that + takes precedence. + """ + # Delete from the list of macro definitions/undefinitions if + # already there (so that this one will take precedence). + i = self._find_macro(name) + if i is not None: + del self.macros[i] + + undefn = (name,) + self.macros.append(undefn) + + def add_include_dir(self, dir): + """Add 'dir' to the list of directories that will be searched for + header files. The compiler is instructed to search directories in + the order in which they are supplied by successive calls to + 'add_include_dir()'. + """ + self.include_dirs.append(dir) + + def set_include_dirs(self, dirs): + """Set the list of directories that will be searched to 'dirs' (a + list of strings). Overrides any preceding calls to + 'add_include_dir()'; subsequence calls to 'add_include_dir()' add + to the list passed to 'set_include_dirs()'. This does not affect + any list of standard include directories that the compiler may + search by default. + """ + self.include_dirs = dirs[:] + + def add_library(self, libname): + """Add 'libname' to the list of libraries that will be included in + all links driven by this compiler object. Note that 'libname' + should *not* be the name of a file containing a library, but the + name of the library itself: the actual filename will be inferred by + the linker, the compiler, or the compiler class (depending on the + platform). + + The linker will be instructed to link against libraries in the + order they were supplied to 'add_library()' and/or + 'set_libraries()'. It is perfectly valid to duplicate library + names; the linker will be instructed to link against libraries as + many times as they are mentioned. + """ + self.libraries.append(libname) + + def set_libraries(self, libnames): + """Set the list of libraries to be included in all links driven by + this compiler object to 'libnames' (a list of strings). This does + not affect any standard system libraries that the linker may + include by default. + """ + self.libraries = libnames[:] + + + def add_library_dir(self, dir): + """Add 'dir' to the list of directories that will be searched for + libraries specified to 'add_library()' and 'set_libraries()'. The + linker will be instructed to search for libraries in the order they + are supplied to 'add_library_dir()' and/or 'set_library_dirs()'. + """ + self.library_dirs.append(dir) + + def set_library_dirs(self, dirs): + """Set the list of library search directories to 'dirs' (a list of + strings). This does not affect any standard library search path + that the linker may search by default. + """ + self.library_dirs = dirs[:] + + def add_runtime_library_dir(self, dir): + """Add 'dir' to the list of directories that will be searched for + shared libraries at runtime. + """ + self.runtime_library_dirs.append(dir) + + def set_runtime_library_dirs(self, dirs): + """Set the list of directories to search for shared libraries at + runtime to 'dirs' (a list of strings). This does not affect any + standard search path that the runtime linker may search by + default. + """ + self.runtime_library_dirs = dirs[:] + + def add_link_object(self, object): + """Add 'object' to the list of object files (or analogues, such as + explicitly named library files or the output of "resource + compilers") to be included in every link driven by this compiler + object. + """ + self.objects.append(object) + + def set_link_objects(self, objects): + """Set the list of object files (or analogues) to be included in + every link to 'objects'. This does not affect any standard object + files that the linker may include by default (such as system + libraries). + """ + self.objects = objects[:] + + + # -- Private utility methods -------------------------------------- + # (here for the convenience of subclasses) + + # Helper method to prep compiler in subclass compile() methods + def _setup_compile(self, outdir, macros, incdirs, sources, depends, + extra): + """Process arguments and decide which source files to compile.""" + if outdir is None: + outdir = self.output_dir + elif not isinstance(outdir, str): + raise TypeError("'output_dir' must be a string or None") + + if macros is None: + macros = self.macros + elif isinstance(macros, list): + macros = macros + (self.macros or []) + else: + raise TypeError("'macros' (if supplied) must be a list of tuples") + + if incdirs is None: + incdirs = self.include_dirs + elif isinstance(incdirs, (list, tuple)): + incdirs = list(incdirs) + (self.include_dirs or []) + else: + raise TypeError( + "'include_dirs' (if supplied) must be a list of strings") + + if extra is None: + extra = [] + + # Get the list of expected output (object) files + objects = self.object_filenames(sources, + strip_dir=False, + output_dir=outdir) + assert len(objects) == len(sources) + + pp_opts = gen_preprocess_options(macros, incdirs) + + build = {} + for i in range(len(sources)): + src = sources[i] + obj = objects[i] + ext = os.path.splitext(src)[1] + self.mkpath(os.path.dirname(obj)) + build[obj] = (src, ext) + + return macros, objects, extra, pp_opts, build + + def _get_cc_args(self, pp_opts, debug, before): + # works for unixccompiler, emxccompiler, cygwinccompiler + cc_args = pp_opts + ['-c'] + if debug: + cc_args[:0] = ['-g'] + if before: + cc_args[:0] = before + return cc_args + + def _fix_compile_args(self, output_dir, macros, include_dirs): + """Typecheck and fix-up some of the arguments to the 'compile()' + method, and return fixed-up values. Specifically: if 'output_dir' + is None, replaces it with 'self.output_dir'; ensures that 'macros' + is a list, and augments it with 'self.macros'; ensures that + 'include_dirs' is a list, and augments it with 'self.include_dirs'. + Guarantees that the returned values are of the correct type, + i.e. for 'output_dir' either string or None, and for 'macros' and + 'include_dirs' either list or None. + """ + if output_dir is None: + output_dir = self.output_dir + elif not isinstance(output_dir, str): + raise TypeError("'output_dir' must be a string or None") + + if macros is None: + macros = self.macros + elif isinstance(macros, list): + macros = macros + (self.macros or []) + else: + raise TypeError("'macros' (if supplied) must be a list of tuples") + + if include_dirs is None: + include_dirs = self.include_dirs + elif isinstance(include_dirs, (list, tuple)): + include_dirs = list(include_dirs) + (self.include_dirs or []) + else: + raise TypeError( + "'include_dirs' (if supplied) must be a list of strings") + + return output_dir, macros, include_dirs + + def _fix_object_args(self, objects, output_dir): + """Typecheck and fix up some arguments supplied to various methods. + Specifically: ensure that 'objects' is a list; if output_dir is + None, replace with self.output_dir. Return fixed versions of + 'objects' and 'output_dir'. + """ + if not isinstance(objects, (list, tuple)): + raise TypeError("'objects' must be a list or tuple of strings") + objects = list(objects) + + if output_dir is None: + output_dir = self.output_dir + elif not isinstance(output_dir, str): + raise TypeError("'output_dir' must be a string or None") + + return objects, output_dir + + def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs): + """Typecheck and fix up some of the arguments supplied to the + 'link_*' methods. Specifically: ensure that all arguments are + lists, and augment them with their permanent versions + (eg. 'self.libraries' augments 'libraries'). Return a tuple with + fixed versions of all arguments. + """ + if libraries is None: + libraries = self.libraries + elif isinstance(libraries, (list, tuple)): + libraries = list(libraries) + (self.libraries or []) + else: + raise TypeError( + "'libraries' (if supplied) must be a list of strings") + + if library_dirs is None: + library_dirs = self.library_dirs + elif isinstance(library_dirs, (list, tuple)): + library_dirs = list(library_dirs) + (self.library_dirs or []) + else: + raise TypeError( + "'library_dirs' (if supplied) must be a list of strings") + + if runtime_library_dirs is None: + runtime_library_dirs = self.runtime_library_dirs + elif isinstance(runtime_library_dirs, (list, tuple)): + runtime_library_dirs = (list(runtime_library_dirs) + + (self.runtime_library_dirs or [])) + else: + raise TypeError("'runtime_library_dirs' (if supplied) " + "must be a list of strings") + + return libraries, library_dirs, runtime_library_dirs + + def _need_link(self, objects, output_file): + """Return true if we need to relink the files listed in 'objects' + to recreate 'output_file'. + """ + if self.force: + return True + else: + if self.dry_run: + newer = newer_group(objects, output_file, missing='newer') + else: + newer = newer_group(objects, output_file) + return newer + + def detect_language(self, sources): + """Detect the language of a given file, or list of files. Uses + language_map, and language_order to do the job. + """ + if not isinstance(sources, list): + sources = [sources] + lang = None + index = len(self.language_order) + for source in sources: + base, ext = os.path.splitext(source) + extlang = self.language_map.get(ext) + try: + extindex = self.language_order.index(extlang) + if extindex < index: + lang = extlang + index = extindex + except ValueError: + pass + return lang + + # -- Worker methods ------------------------------------------------ + # (must be implemented by subclasses) + + def preprocess(self, source, output_file=None, macros=None, + include_dirs=None, extra_preargs=None, extra_postargs=None): + """Preprocess a single C/C++ source file, named in 'source'. + Output will be written to file named 'output_file', or stdout if + 'output_file' not supplied. 'macros' is a list of macro + definitions as for 'compile()', which will augment the macros set + with 'define_macro()' and 'undefine_macro()'. 'include_dirs' is a + list of directory names that will be added to the default list. + + Raises PreprocessError on failure. + """ + pass + + def compile(self, sources, output_dir=None, macros=None, + include_dirs=None, debug=False, extra_preargs=None, + extra_postargs=None, depends=None): + """Compile one or more source files. + + 'sources' must be a list of filenames, most likely C/C++ + files, but in reality anything that can be handled by a + particular compiler and compiler class (eg. MSVCCompiler can + handle resource files in 'sources'). Return a list of object + filenames, one per source filename in 'sources'. Depending on + the implementation, not all source files will necessarily be + compiled, but all corresponding object filenames will be + returned. + + If 'output_dir' is given, object files will be put under it, while + retaining their original path component. That is, "foo/bar.c" + normally compiles to "foo/bar.o" (for a Unix implementation); if + 'output_dir' is "build", then it would compile to + "build/foo/bar.o". + + 'macros', if given, must be a list of macro definitions. A macro + definition is either a (name, value) 2-tuple or a (name,) 1-tuple. + The former defines a macro; if the value is None, the macro is + defined without an explicit value. The 1-tuple case undefines a + macro. Later definitions/redefinitions/ undefinitions take + precedence. + + 'include_dirs', if given, must be a list of strings, the + directories to add to the default include file search path for this + compilation only. + + 'debug' is a boolean; if true, the compiler will be instructed to + output debug symbols in (or alongside) the object file(s). + + 'extra_preargs' and 'extra_postargs' are implementation- dependent. + On platforms that have the notion of a command line (e.g. Unix, + DOS/Windows), they are most likely lists of strings: extra + command-line arguments to prepand/append to the compiler command + line. On other platforms, consult the implementation class + documentation. In any event, they are intended as an escape hatch + for those occasions when the abstract compiler framework doesn't + cut the mustard. + + 'depends', if given, is a list of filenames that all targets + depend on. If a source file is older than any file in + depends, then the source file will be recompiled. This + supports dependency tracking, but only at a coarse + granularity. + + Raises CompileError on failure. + """ + # A concrete compiler class can either override this method + # entirely or implement _compile(). + + macros, objects, extra_postargs, pp_opts, build = \ + self._setup_compile(output_dir, macros, include_dirs, sources, + depends, extra_postargs) + cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) + + # Return *all* object filenames, not just the ones we just built. + return objects + + def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + """Compile 'src' to product 'obj'.""" + + # A concrete compiler class that does not override compile() + # should implement _compile(). + pass + + def create_static_lib(self, objects, output_libname, output_dir=None, + debug=False, target_lang=None): + """Link a bunch of stuff together to create a static library file. + The "bunch of stuff" consists of the list of object files supplied + as 'objects', the extra object files supplied to + 'add_link_object()' and/or 'set_link_objects()', the libraries + supplied to 'add_library()' and/or 'set_libraries()', and the + libraries supplied as 'libraries' (if any). + + 'output_libname' should be a library name, not a filename; the + filename will be inferred from the library name. 'output_dir' is + the directory where the library file will be put. + + 'debug' is a boolean; if true, debugging information will be + included in the library (note that on most platforms, it is the + compile step where this matters: the 'debug' flag is included here + just for consistency). + + 'target_lang' is the target language for which the given objects + are being compiled. This allows specific linkage time treatment of + certain languages. + + Raises LibError on failure. + """ + pass + + # values for target_desc parameter in link() + SHARED_OBJECT = "shared_object" + SHARED_LIBRARY = "shared_library" + EXECUTABLE = "executable" + + def link(self, target_desc, objects, output_filename, output_dir=None, + libraries=None, library_dirs=None, runtime_library_dirs=None, + export_symbols=None, debug=False, extra_preargs=None, + extra_postargs=None, build_temp=None, target_lang=None): + """Link a bunch of stuff together to create an executable or + shared library file. + + The "bunch of stuff" consists of the list of object files supplied + as 'objects'. 'output_filename' should be a filename. If + 'output_dir' is supplied, 'output_filename' is relative to it + (i.e. 'output_filename' can provide directory components if + needed). + + 'libraries' is a list of libraries to link against. These are + library names, not filenames, since they're translated into + filenames in a platform-specific way (eg. "foo" becomes "libfoo.a" + on Unix and "foo.lib" on DOS/Windows). However, they can include a + directory component, which means the linker will look in that + specific directory rather than searching all the normal locations. + + 'library_dirs', if supplied, should be a list of directories to + search for libraries that were specified as bare library names + (ie. no directory component). These are on top of the system + default and those supplied to 'add_library_dir()' and/or + 'set_library_dirs()'. 'runtime_library_dirs' is a list of + directories that will be embedded into the shared library and used + to search for other shared libraries that *it* depends on at + run-time. (This may only be relevant on Unix.) + + 'export_symbols' is a list of symbols that the shared library will + export. (This appears to be relevant only on Windows.) + + 'debug' is as for 'compile()' and 'create_static_lib()', with the + slight distinction that it actually matters on most platforms (as + opposed to 'create_static_lib()', which includes a 'debug' flag + mostly for form's sake). + + 'extra_preargs' and 'extra_postargs' are as for 'compile()' (except + of course that they supply command-line arguments for the + particular linker being used). + + 'target_lang' is the target language for which the given objects + are being compiled. This allows specific linkage time treatment of + certain languages. + + Raises LinkError on failure. + """ + raise NotImplementedError + + + # Old 'link_*()' methods, rewritten to use the new 'link()' method. + + def link_shared_lib(self, objects, output_libname, output_dir=None, + libraries=None, library_dirs=None, + runtime_library_dirs=None, export_symbols=None, + debug=False, extra_preargs=None, extra_postargs=None, + build_temp=None, target_lang=None): + self.link(CCompiler.SHARED_LIBRARY, objects, + self.library_filename(output_libname, lib_type='shared'), + output_dir, + libraries, library_dirs, runtime_library_dirs, + export_symbols, debug, + extra_preargs, extra_postargs, build_temp, target_lang) + + def link_shared_object(self, objects, output_filename, output_dir=None, + libraries=None, library_dirs=None, + runtime_library_dirs=None, export_symbols=None, + debug=False, extra_preargs=None, extra_postargs=None, + build_temp=None, target_lang=None): + self.link(CCompiler.SHARED_OBJECT, objects, + output_filename, output_dir, + libraries, library_dirs, runtime_library_dirs, + export_symbols, debug, + extra_preargs, extra_postargs, build_temp, target_lang) + + def link_executable(self, objects, output_progname, output_dir=None, + libraries=None, library_dirs=None, + runtime_library_dirs=None, debug=False, + extra_preargs=None, extra_postargs=None, + target_lang=None): + self.link(CCompiler.EXECUTABLE, objects, + self.executable_filename(output_progname), output_dir, + libraries, library_dirs, runtime_library_dirs, None, + debug, extra_preargs, extra_postargs, None, target_lang) + + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function; there is + # no appropriate default implementation so subclasses should + # implement all of these. + + def library_dir_option(self, dir): + """Return the compiler option to add 'dir' to the list of + directories searched for libraries. + """ + raise NotImplementedError + + def runtime_library_dir_option(self, dir): + """Return the compiler option to add 'dir' to the list of + directories searched for runtime libraries. + """ + raise NotImplementedError + + def library_option(self, lib): + """Return the compiler option to add 'dir' to the list of libraries + linked into the shared library or executable. + """ + raise NotImplementedError + + def has_function(self, funcname, includes=None, include_dirs=None, + libraries=None, library_dirs=None): + """Return a boolean indicating whether funcname is supported on + the current platform. The optional arguments can be used to + augment the compilation environment. + """ + + # this can't be included at module scope because it tries to + # import math which might not be available at that point - maybe + # the necessary logic should just be inlined? + import tempfile + if includes is None: + includes = [] + if include_dirs is None: + include_dirs = [] + if libraries is None: + libraries = [] + if library_dirs is None: + library_dirs = [] + fd, fname = tempfile.mkstemp(".c", funcname, text=True) + f = os.fdopen(fd, "w") + try: + for incl in includes: + f.write("""#include "%s"\n""" % incl) + f.write("""\ +main (int argc, char **argv) { + %s(); +} +""" % funcname) + finally: + f.close() + try: + objects = self.compile([fname], include_dirs=include_dirs) + except CompileError: + return False + + try: + self.link_executable(objects, "a.out", + libraries=libraries, + library_dirs=library_dirs) + except (LinkError, TypeError): + return False + return True + + def find_library_file(self, dirs, lib, debug=False): + """Search the specified list of directories for a static or shared + library file 'lib' and return the full path to that file. If + 'debug' is true, look for a debugging version (if that makes sense on + the current platform). Return None if 'lib' wasn't found in any of + the specified directories. + """ + raise NotImplementedError + + # -- Filename generation methods ----------------------------------- + + # The default implementation of the filename generating methods are + # prejudiced towards the Unix/DOS/Windows view of the world: + # * object files are named by replacing the source file extension + # (eg. .c/.cpp -> .o/.obj) + # * library files (shared or static) are named by plugging the + # library name and extension into a format string, eg. + # "lib%s.%s" % (lib_name, ".a") for Unix static libraries + # * executables are named by appending an extension (possibly + # empty) to the program name: eg. progname + ".exe" for + # Windows + # + # To reduce redundant code, these methods expect to find + # several attributes in the current object (presumably defined + # as class attributes): + # * src_extensions - + # list of C/C++ source file extensions, eg. ['.c', '.cpp'] + # * obj_extension - + # object file extension, eg. '.o' or '.obj' + # * static_lib_extension - + # extension for static library files, eg. '.a' or '.lib' + # * shared_lib_extension - + # extension for shared library/object files, eg. '.so', '.dll' + # * static_lib_format - + # format string for generating static library filenames, + # eg. 'lib%s.%s' or '%s.%s' + # * shared_lib_format + # format string for generating shared library filenames + # (probably same as static_lib_format, since the extension + # is one of the intended parameters to the format string) + # * exe_extension - + # extension for executable files, eg. '' or '.exe' + + def object_filenames(self, source_filenames, strip_dir=False, output_dir=''): + if output_dir is None: + output_dir = '' + obj_names = [] + for src_name in source_filenames: + base, ext = os.path.splitext(src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base):] # If abs, chop off leading / + if ext not in self.src_extensions: + raise UnknownFileError("unknown file type '%s' (from '%s')" % + (ext, src_name)) + if strip_dir: + base = os.path.basename(base) + obj_names.append(os.path.join(output_dir, + base + self.obj_extension)) + return obj_names + + def shared_object_filename(self, basename, strip_dir=False, output_dir=''): + assert output_dir is not None + if strip_dir: + basename = os.path.basename(basename) + return os.path.join(output_dir, basename + self.shared_lib_extension) + + def executable_filename(self, basename, strip_dir=False, output_dir=''): + assert output_dir is not None + if strip_dir: + basename = os.path.basename(basename) + return os.path.join(output_dir, basename + (self.exe_extension or '')) + + def library_filename(self, libname, lib_type='static', # or 'shared' + strip_dir=False, output_dir=''): + assert output_dir is not None + if lib_type not in ("static", "shared", "dylib"): + raise ValueError( + "'lib_type' must be 'static', 'shared' or 'dylib'") + fmt = getattr(self, lib_type + "_lib_format") + ext = getattr(self, lib_type + "_lib_extension") + + dir, base = os.path.split(libname) + filename = fmt % (base, ext) + if strip_dir: + dir = '' + + return os.path.join(output_dir, dir, filename) + + + # -- Utility methods ----------------------------------------------- + + def execute(self, func, args, msg=None, level=1): + execute(func, args, msg, self.dry_run) + + def spawn(self, cmd): + spawn(cmd, dry_run=self.dry_run) + + def move_file(self, src, dst): + logger.info("moving %r to %r", src, dst) + if self.dry_run: + return + return move(src, dst) + + def mkpath(self, name, mode=0o777): + name = os.path.normpath(name) + if os.path.isdir(name) or name == '': + return + if self.dry_run: + head = '' + for part in name.split(os.sep): + logger.info("created directory %s%s", head, part) + head += part + os.sep + return + os.makedirs(name, mode) diff --git a/Lib/packaging/compiler/cygwinccompiler.py b/Lib/packaging/compiler/cygwinccompiler.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/compiler/cygwinccompiler.py @@ -0,0 +1,355 @@ +"""CCompiler implementations for Cygwin and mingw32 versions of GCC. + +This module contains the CygwinCCompiler class, a subclass of +UnixCCompiler that handles the Cygwin port of the GNU C compiler to +Windows, and the Mingw32CCompiler class which handles the mingw32 port +of GCC (same as cygwin in no-cygwin mode). +""" + +# problems: +# +# * if you use a msvc compiled python version (1.5.2) +# 1. you have to insert a __GNUC__ section in its config.h +# 2. you have to generate a import library for its dll +# - create a def-file for python??.dll +# - create a import library using +# dlltool --dllname python15.dll --def python15.def \ +# --output-lib libpython15.a +# +# see also http://starship.python.net/crew/kernr/mingw32/Notes.html +# +# * We put export_symbols in a def-file, and don't use +# --export-all-symbols because it doesn't worked reliable in some +# tested configurations. And because other windows compilers also +# need their symbols specified this no serious problem. +# +# tested configurations: +# +# * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works +# (after patching python's config.h and for C++ some other include files) +# see also http://starship.python.net/crew/kernr/mingw32/Notes.html +# * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works +# (ld doesn't support -shared, so we use dllwrap) +# * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now +# - its dllwrap doesn't work, there is a bug in binutils 2.10.90 +# see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html +# - using gcc -mdll instead dllwrap doesn't work without -static because +# it tries to link against dlls instead their import libraries. (If +# it finds the dll first.) +# By specifying -static we force ld to link against the import libraries, +# this is windows standard and there are normally not the necessary symbols +# in the dlls. +# *** only the version of June 2000 shows these problems +# * cygwin gcc 3.2/ld 2.13.90 works +# (ld supports -shared) +# * mingw gcc 3.2/ld 2.13 works +# (ld supports -shared) + + +import os +import sys +import copy + +from packaging import logger +from packaging.compiler.unixccompiler import UnixCCompiler +from packaging.util import write_file +from packaging.errors import PackagingExecError, CompileError, UnknownFileError +from packaging.util import get_compiler_versions +import sysconfig + + +def get_msvcr(): + """Include the appropriate MSVC runtime library if Python was built + with MSVC 7.0 or later. + """ + msc_pos = sys.version.find('MSC v.') + if msc_pos != -1: + msc_ver = sys.version[msc_pos+6:msc_pos+10] + if msc_ver == '1300': + # MSVC 7.0 + return ['msvcr70'] + elif msc_ver == '1310': + # MSVC 7.1 + return ['msvcr71'] + elif msc_ver == '1400': + # VS2005 / MSVC 8.0 + return ['msvcr80'] + elif msc_ver == '1500': + # VS2008 / MSVC 9.0 + return ['msvcr90'] + else: + raise ValueError("Unknown MS Compiler version %s " % msc_ver) + + +class CygwinCCompiler(UnixCCompiler): + """ Handles the Cygwin port of the GNU C compiler to Windows. + """ + name = 'cygwin' + description = 'Cygwin port of GNU C Compiler for Win32' + obj_extension = ".o" + static_lib_extension = ".a" + shared_lib_extension = ".dll" + static_lib_format = "lib%s%s" + shared_lib_format = "%s%s" + exe_extension = ".exe" + + def __init__(self, verbose=0, dry_run=False, force=False): + + UnixCCompiler.__init__(self, verbose, dry_run, force) + + status, details = check_config_h() + logger.debug("Python's GCC status: %s (details: %s)", status, details) + if status is not CONFIG_H_OK: + self.warn( + "Python's pyconfig.h doesn't seem to support your compiler. " + "Reason: %s. " + "Compiling may fail because of undefined preprocessor macros." + % details) + + self.gcc_version, self.ld_version, self.dllwrap_version = \ + get_compiler_versions() + logger.debug(self.name + ": gcc %s, ld %s, dllwrap %s\n", + self.gcc_version, + self.ld_version, + self.dllwrap_version) + + # ld_version >= "2.10.90" and < "2.13" should also be able to use + # gcc -mdll instead of dllwrap + # Older dllwraps had own version numbers, newer ones use the + # same as the rest of binutils ( also ld ) + # dllwrap 2.10.90 is buggy + if self.ld_version >= "2.10.90": + self.linker_dll = "gcc" + else: + self.linker_dll = "dllwrap" + + # ld_version >= "2.13" support -shared so use it instead of + # -mdll -static + if self.ld_version >= "2.13": + shared_option = "-shared" + else: + shared_option = "-mdll -static" + + # Hard-code GCC because that's what this is all about. + # XXX optimization, warnings etc. should be customizable. + self.set_executables(compiler='gcc -mcygwin -O -Wall', + compiler_so='gcc -mcygwin -mdll -O -Wall', + compiler_cxx='g++ -mcygwin -O -Wall', + linker_exe='gcc -mcygwin', + linker_so=('%s -mcygwin %s' % + (self.linker_dll, shared_option))) + + # cygwin and mingw32 need different sets of libraries + if self.gcc_version == "2.91.57": + # cygwin shouldn't need msvcrt, but without the dlls will crash + # (gcc version 2.91.57) -- perhaps something about initialization + self.dll_libraries=["msvcrt"] + self.warn( + "Consider upgrading to a newer version of gcc") + else: + # Include the appropriate MSVC runtime library if Python was built + # with MSVC 7.0 or later. + self.dll_libraries = get_msvcr() + + def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + """Compile the source by spawning GCC and windres if needed.""" + if ext == '.rc' or ext == '.res': + # gcc needs '.res' and '.rc' compiled to object files !!! + try: + self.spawn(["windres", "-i", src, "-o", obj]) + except PackagingExecError as msg: + raise CompileError(msg) + else: # for other files use the C-compiler + try: + self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + + extra_postargs) + except PackagingExecError as msg: + raise CompileError(msg) + + def link(self, target_desc, objects, output_filename, output_dir=None, + libraries=None, library_dirs=None, runtime_library_dirs=None, + export_symbols=None, debug=False, extra_preargs=None, + extra_postargs=None, build_temp=None, target_lang=None): + """Link the objects.""" + # use separate copies, so we can modify the lists + extra_preargs = copy.copy(extra_preargs or []) + libraries = copy.copy(libraries or []) + objects = copy.copy(objects or []) + + # Additional libraries + libraries.extend(self.dll_libraries) + + # handle export symbols by creating a def-file + # with executables this only works with gcc/ld as linker + if ((export_symbols is not None) and + (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): + # (The linker doesn't do anything if output is up-to-date. + # So it would probably better to check if we really need this, + # but for this we had to insert some unchanged parts of + # UnixCCompiler, and this is not what we want.) + + # we want to put some files in the same directory as the + # object files are, build_temp doesn't help much + # where are the object files + temp_dir = os.path.dirname(objects[0]) + # name of dll to give the helper files the same base name + dll_name, dll_extension = os.path.splitext( + os.path.basename(output_filename)) + + # generate the filenames for these files + def_file = os.path.join(temp_dir, dll_name + ".def") + lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a") + + # Generate .def file + contents = [ + "LIBRARY %s" % os.path.basename(output_filename), + "EXPORTS"] + for sym in export_symbols: + contents.append(sym) + self.execute(write_file, (def_file, contents), + "writing %s" % def_file) + + # next add options for def-file and to creating import libraries + + # dllwrap uses different options than gcc/ld + if self.linker_dll == "dllwrap": + extra_preargs.extend(("--output-lib", lib_file)) + # for dllwrap we have to use a special option + extra_preargs.extend(("--def", def_file)) + # we use gcc/ld here and can be sure ld is >= 2.9.10 + else: + # doesn't work: bfd_close build\...\libfoo.a: Invalid operation + #extra_preargs.extend(("-Wl,--out-implib,%s" % lib_file)) + # for gcc/ld the def-file is specified as any object files + objects.append(def_file) + + #end: if ((export_symbols is not None) and + # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): + + # who wants symbols and a many times larger output file + # should explicitly switch the debug mode on + # otherwise we let dllwrap/ld strip the output file + # (On my machine: 10KB < stripped_file < ??100KB + # unstripped_file = stripped_file + XXX KB + # ( XXX=254 for a typical python extension)) + if not debug: + extra_preargs.append("-s") + + UnixCCompiler.link(self, target_desc, objects, output_filename, + output_dir, libraries, library_dirs, + runtime_library_dirs, + None, # export_symbols, we do this in our def-file + debug, extra_preargs, extra_postargs, build_temp, + target_lang) + + # -- Miscellaneous methods ----------------------------------------- + + def object_filenames(self, source_filenames, strip_dir=False, + output_dir=''): + """Adds supports for rc and res files.""" + if output_dir is None: + output_dir = '' + obj_names = [] + for src_name in source_filenames: + # use normcase to make sure '.rc' is really '.rc' and not '.RC' + base, ext = os.path.splitext(os.path.normcase(src_name)) + if ext not in (self.src_extensions + ['.rc','.res']): + raise UnknownFileError("unknown file type '%s' (from '%s')" % (ext, src_name)) + if strip_dir: + base = os.path.basename (base) + if ext in ('.res', '.rc'): + # these need to be compiled to object files + obj_names.append (os.path.join(output_dir, + base + ext + self.obj_extension)) + else: + obj_names.append (os.path.join(output_dir, + base + self.obj_extension)) + return obj_names + +# the same as cygwin plus some additional parameters +class Mingw32CCompiler(CygwinCCompiler): + """ Handles the Mingw32 port of the GNU C compiler to Windows. + """ + name = 'mingw32' + description = 'MinGW32 compiler' + + def __init__(self, verbose=0, dry_run=False, force=False): + + CygwinCCompiler.__init__ (self, verbose, dry_run, force) + + # ld_version >= "2.13" support -shared so use it instead of + # -mdll -static + if self.ld_version >= "2.13": + shared_option = "-shared" + else: + shared_option = "-mdll -static" + + # A real mingw32 doesn't need to specify a different entry point, + # but cygwin 2.91.57 in no-cygwin-mode needs it. + if self.gcc_version <= "2.91.57": + entry_point = '--entry _DllMain at 12' + else: + entry_point = '' + + self.set_executables(compiler='gcc -mno-cygwin -O -Wall', + compiler_so='gcc -mno-cygwin -mdll -O -Wall', + compiler_cxx='g++ -mno-cygwin -O -Wall', + linker_exe='gcc -mno-cygwin', + linker_so='%s -mno-cygwin %s %s' + % (self.linker_dll, shared_option, + entry_point)) + # Maybe we should also append -mthreads, but then the finished + # dlls need another dll (mingwm10.dll see Mingw32 docs) + # (-mthreads: Support thread-safe exception handling on `Mingw32') + + # no additional libraries needed + self.dll_libraries=[] + + # Include the appropriate MSVC runtime library if Python was built + # with MSVC 7.0 or later. + self.dll_libraries = get_msvcr() + +# Because these compilers aren't configured in Python's pyconfig.h file by +# default, we should at least warn the user if he is using a unmodified +# version. + +CONFIG_H_OK = "ok" +CONFIG_H_NOTOK = "not ok" +CONFIG_H_UNCERTAIN = "uncertain" + +def check_config_h(): + """Check if the current Python installation appears amenable to building + extensions with GCC. + + Returns a tuple (status, details), where 'status' is one of the following + constants: + + - CONFIG_H_OK: all is well, go ahead and compile + - CONFIG_H_NOTOK: doesn't look good + - CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h + + 'details' is a human-readable string explaining the situation. + + Note there are two ways to conclude "OK": either 'sys.version' contains + the string "GCC" (implying that this Python was built with GCC), or the + installed "pyconfig.h" contains the string "__GNUC__". + """ + + # XXX since this function also checks sys.version, it's not strictly a + # "pyconfig.h" check -- should probably be renamed... + # if sys.version contains GCC then python was compiled with GCC, and the + # pyconfig.h file should be OK + if "GCC" in sys.version: + return CONFIG_H_OK, "sys.version mentions 'GCC'" + + # let's see if __GNUC__ is mentioned in python.h + fn = sysconfig.get_config_h_filename() + try: + with open(fn) as config_h: + if "__GNUC__" in config_h.read(): + return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn + else: + return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn + except IOError as exc: + return (CONFIG_H_UNCERTAIN, + "couldn't read '%s': %s" % (fn, exc.strerror)) diff --git a/Lib/packaging/compiler/extension.py b/Lib/packaging/compiler/extension.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/compiler/extension.py @@ -0,0 +1,121 @@ +"""Class representing C/C++ extension modules.""" + +from packaging import logger + +# This class is really only used by the "build_ext" command, so it might +# make sense to put it in distutils.command.build_ext. However, that +# module is already big enough, and I want to make this class a bit more +# complex to simplify some common cases ("foo" module in "foo.c") and do +# better error-checking ("foo.c" actually exists). +# +# Also, putting this in build_ext.py means every setup script would have to +# import that large-ish module (indirectly, through distutils.core) in +# order to do anything. + + +class Extension: + """Just a collection of attributes that describes an extension + module and everything needed to build it (hopefully in a portable + way, but there are hooks that let you be as unportable as you need). + + Instance attributes: + name : string + the full name of the extension, including any packages -- ie. + *not* a filename or pathname, but Python dotted name + sources : [string] + list of source filenames, relative to the distribution root + (where the setup script lives), in Unix form (slash-separated) + for portability. Source files may be C, C++, SWIG (.i), + platform-specific resource files, or whatever else is recognized + by the "build_ext" command as source for a Python extension. + include_dirs : [string] + list of directories to search for C/C++ header files (in Unix + form for portability) + define_macros : [(name : string, value : string|None)] + list of macros to define; each macro is defined using a 2-tuple, + where 'value' is either the string to define it to or None to + define it without a particular value (equivalent of "#define + FOO" in source or -DFOO on Unix C compiler command line) + undef_macros : [string] + list of macros to undefine explicitly + library_dirs : [string] + list of directories to search for C/C++ libraries at link time + libraries : [string] + list of library names (not filenames or paths) to link against + runtime_library_dirs : [string] + list of directories to search for C/C++ libraries at run time + (for shared extensions, this is when the extension is loaded) + extra_objects : [string] + list of extra files to link with (eg. object files not implied + by 'sources', static library that must be explicitly specified, + binary resource files, etc.) + extra_compile_args : [string] + any extra platform- and compiler-specific information to use + when compiling the source files in 'sources'. For platforms and + compilers where "command line" makes sense, this is typically a + list of command-line arguments, but for other platforms it could + be anything. + extra_link_args : [string] + any extra platform- and compiler-specific information to use + when linking object files together to create the extension (or + to create a new static Python interpreter). Similar + interpretation as for 'extra_compile_args'. + export_symbols : [string] + list of symbols to be exported from a shared extension. Not + used on all platforms, and not generally necessary for Python + extensions, which typically export exactly one symbol: "init" + + extension_name. + swig_opts : [string] + any extra options to pass to SWIG if a source file has the .i + extension. + depends : [string] + list of files that the extension depends on + language : string + extension language (i.e. "c", "c++", "objc"). Will be detected + from the source extensions if not provided. + optional : boolean + specifies that a build failure in the extension should not abort the + build process, but simply not install the failing extension. + """ + + # **kwargs are allowed so that a warning is emitted instead of an + # exception + def __init__(self, name, sources, include_dirs=None, define_macros=None, + undef_macros=None, library_dirs=None, libraries=None, + runtime_library_dirs=None, extra_objects=None, + extra_compile_args=None, extra_link_args=None, + export_symbols=None, swig_opts=None, depends=None, + language=None, optional=None, **kw): + if not isinstance(name, str): + raise AssertionError("'name' must be a string") + + if not isinstance(sources, list): + raise AssertionError("'sources' must be a list of strings") + + for v in sources: + if not isinstance(v, str): + raise AssertionError("'sources' must be a list of strings") + + self.name = name + self.sources = sources + self.include_dirs = include_dirs or [] + self.define_macros = define_macros or [] + self.undef_macros = undef_macros or [] + self.library_dirs = library_dirs or [] + self.libraries = libraries or [] + self.runtime_library_dirs = runtime_library_dirs or [] + self.extra_objects = extra_objects or [] + self.extra_compile_args = extra_compile_args or [] + self.extra_link_args = extra_link_args or [] + self.export_symbols = export_symbols or [] + self.swig_opts = swig_opts or [] + self.depends = depends or [] + self.language = language + self.optional = optional + + # If there are unknown keyword options, warn about them + if len(kw) > 0: + options = [repr(option) for option in kw] + options = ', '.join(sorted(options)) + logger.warning( + 'unknown arguments given to Extension: %s', options) diff --git a/Lib/packaging/compiler/msvc9compiler.py b/Lib/packaging/compiler/msvc9compiler.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/compiler/msvc9compiler.py @@ -0,0 +1,720 @@ +"""CCompiler implementation for the Microsoft Visual Studio 2008 compiler. + +The MSVCCompiler class is compatible with VS 2005 and VS 2008. Legacy +support for older versions of VS are in the msvccompiler module. +""" + +# Written by Perry Stoll +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) +# ported to VS2005 and VS 2008 by Christian Heimes +import os +import subprocess +import sys +import re + +from packaging.errors import (PackagingExecError, PackagingPlatformError, + CompileError, LibError, LinkError) +from packaging.compiler.ccompiler import CCompiler +from packaging.compiler import gen_lib_options +from packaging import logger +from packaging.util import get_platform + +import winreg + +RegOpenKeyEx = winreg.OpenKeyEx +RegEnumKey = winreg.EnumKey +RegEnumValue = winreg.EnumValue +RegError = winreg.error + +HKEYS = (winreg.HKEY_USERS, + winreg.HKEY_CURRENT_USER, + winreg.HKEY_LOCAL_MACHINE, + winreg.HKEY_CLASSES_ROOT) + +VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f" +WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows" +NET_BASE = r"Software\Microsoft\.NETFramework" + +# A map keyed by get_platform() return values to values accepted by +# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is +# the param to cross-compile on x86 targetting amd64.) +PLAT_TO_VCVARS = { + 'win32' : 'x86', + 'win-amd64' : 'amd64', + 'win-ia64' : 'ia64', +} + + +class Reg: + """Helper class to read values from the registry + """ + + def get_value(cls, path, key): + for base in HKEYS: + d = cls.read_values(base, path) + if d and key in d: + return d[key] + raise KeyError(key) + get_value = classmethod(get_value) + + def read_keys(cls, base, key): + """Return list of registry keys.""" + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + L = [] + i = 0 + while True: + try: + k = RegEnumKey(handle, i) + except RegError: + break + L.append(k) + i += 1 + return L + read_keys = classmethod(read_keys) + + def read_values(cls, base, key): + """Return dict of registry keys and values. + + All names are converted to lowercase. + """ + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + d = {} + i = 0 + while True: + try: + name, value, type = RegEnumValue(handle, i) + except RegError: + break + name = name.lower() + d[cls.convert_mbcs(name)] = cls.convert_mbcs(value) + i += 1 + return d + read_values = classmethod(read_values) + + def convert_mbcs(s): + dec = getattr(s, "decode", None) + if dec is not None: + try: + s = dec("mbcs") + except UnicodeError: + pass + return s + convert_mbcs = staticmethod(convert_mbcs) + +class MacroExpander: + + def __init__(self, version): + self.macros = {} + self.vsbase = VS_BASE % version + self.load_macros(version) + + def set_macro(self, macro, path, key): + self.macros["$(%s)" % macro] = Reg.get_value(path, key) + + def load_macros(self, version): + self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir") + self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir") + self.set_macro("FrameworkDir", NET_BASE, "installroot") + try: + if version >= 8.0: + self.set_macro("FrameworkSDKDir", NET_BASE, + "sdkinstallrootv2.0") + else: + raise KeyError("sdkinstallrootv2.0") + except KeyError: + raise PackagingPlatformError( + """Python was built with Visual Studio 2008; +extensions must be built with a compiler than can generate compatible binaries. +Visual Studio 2008 was not found on this system. If you have Cygwin installed, +you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") + + if version >= 9.0: + self.set_macro("FrameworkVersion", self.vsbase, "clr version") + self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder") + else: + p = r"Software\Microsoft\NET Framework Setup\Product" + for base in HKEYS: + try: + h = RegOpenKeyEx(base, p) + except RegError: + continue + key = RegEnumKey(h, 0) + d = Reg.get_value(base, r"%s\%s" % (p, key)) + self.macros["$(FrameworkVersion)"] = d["version"] + + def sub(self, s): + for k, v in self.macros.items(): + s = s.replace(k, v) + return s + +def get_build_version(): + """Return the version of MSVC that was used to build Python. + + For Python 2.3 and up, the version number is included in + sys.version. For earlier versions, assume the compiler is MSVC 6. + """ + prefix = "MSC v." + i = sys.version.find(prefix) + if i == -1: + return 6 + i = i + len(prefix) + s, rest = sys.version[i:].split(" ", 1) + majorVersion = int(s[:-2]) - 6 + minorVersion = int(s[2:3]) / 10.0 + # I don't think paths are affected by minor version in version 6 + if majorVersion == 6: + minorVersion = 0 + if majorVersion >= 6: + return majorVersion + minorVersion + # else we don't know what version of the compiler this is + return None + +def normalize_and_reduce_paths(paths): + """Return a list of normalized paths with duplicates removed. + + The current order of paths is maintained. + """ + # Paths are normalized so things like: /a and /a/ aren't both preserved. + reduced_paths = [] + for p in paths: + np = os.path.normpath(p) + # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set. + if np not in reduced_paths: + reduced_paths.append(np) + return reduced_paths + +def removeDuplicates(variable): + """Remove duplicate values of an environment variable. + """ + oldList = variable.split(os.pathsep) + newList = [] + for i in oldList: + if i not in newList: + newList.append(i) + newVariable = os.pathsep.join(newList) + return newVariable + +def find_vcvarsall(version): + """Find the vcvarsall.bat file + + At first it tries to find the productdir of VS 2008 in the registry. If + that fails it falls back to the VS90COMNTOOLS env var. + """ + vsbase = VS_BASE % version + try: + productdir = Reg.get_value(r"%s\Setup\VC" % vsbase, + "productdir") + except KeyError: + logger.debug("Unable to find productdir in registry") + productdir = None + + if not productdir or not os.path.isdir(productdir): + toolskey = "VS%0.f0COMNTOOLS" % version + toolsdir = os.environ.get(toolskey, None) + + if toolsdir and os.path.isdir(toolsdir): + productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC") + productdir = os.path.abspath(productdir) + if not os.path.isdir(productdir): + logger.debug("%s is not a valid directory", productdir) + return None + else: + logger.debug("env var %s is not set or invalid", toolskey) + if not productdir: + logger.debug("no productdir found") + return None + vcvarsall = os.path.join(productdir, "vcvarsall.bat") + if os.path.isfile(vcvarsall): + return vcvarsall + logger.debug("unable to find vcvarsall.bat") + return None + +def query_vcvarsall(version, arch="x86"): + """Launch vcvarsall.bat and read the settings from its environment + """ + vcvarsall = find_vcvarsall(version) + interesting = set(("include", "lib", "libpath", "path")) + result = {} + + if vcvarsall is None: + raise PackagingPlatformError("Unable to find vcvarsall.bat") + logger.debug("calling 'vcvarsall.bat %s' (version=%s)", arch, version) + popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + stdout, stderr = popen.communicate() + if popen.wait() != 0: + raise PackagingPlatformError(stderr.decode("mbcs")) + + stdout = stdout.decode("mbcs") + for line in stdout.split("\n"): + line = Reg.convert_mbcs(line) + if '=' not in line: + continue + line = line.strip() + key, value = line.split('=', 1) + key = key.lower() + if key in interesting: + if value.endswith(os.pathsep): + value = value[:-1] + result[key] = removeDuplicates(value) + + if len(result) != len(interesting): + raise ValueError(str(list(result))) + + return result + +# More globals +VERSION = get_build_version() +if VERSION < 8.0: + raise PackagingPlatformError("VC %0.1f is not supported by this module" % VERSION) +# MACROS = MacroExpander(VERSION) + +class MSVCCompiler(CCompiler) : + """Concrete class that implements an interface to Microsoft Visual C++, + as defined by the CCompiler abstract class.""" + + name = 'msvc' + description = 'Microsoft Visual C++' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + _rc_extensions = ['.rc'] + _mc_extensions = ['.mc'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = (_c_extensions + _cpp_extensions + + _rc_extensions + _mc_extensions) + res_extension = '.res' + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + def __init__(self, verbose=0, dry_run=False, force=False): + CCompiler.__init__(self, verbose, dry_run, force) + self.__version = VERSION + self.__root = r"Software\Microsoft\VisualStudio" + # self.__macros = MACROS + self.__paths = [] + # target platform (.plat_name is consistent with 'bdist') + self.plat_name = None + self.__arch = None # deprecated name + self.initialized = False + + def initialize(self, plat_name=None): + # multi-init means we would need to check platform same each time... + assert not self.initialized, "don't init multiple times" + if plat_name is None: + plat_name = get_platform() + # sanity check for platforms to prevent obscure errors later. + ok_plats = 'win32', 'win-amd64', 'win-ia64' + if plat_name not in ok_plats: + raise PackagingPlatformError("--plat-name must be one of %s" % + (ok_plats,)) + + if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): + # Assume that the SDK set up everything alright; don't try to be + # smarter + self.cc = "cl.exe" + self.linker = "link.exe" + self.lib = "lib.exe" + self.rc = "rc.exe" + self.mc = "mc.exe" + else: + # On x86, 'vcvars32.bat amd64' creates an env that doesn't work; + # to cross compile, you use 'x86_amd64'. + # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross + # compile use 'x86' (ie, it runs the x86 compiler directly) + # No idea how itanium handles this, if at all. + if plat_name == get_platform() or plat_name == 'win32': + # native build or cross-compile to win32 + plat_spec = PLAT_TO_VCVARS[plat_name] + else: + # cross compile from win32 -> some 64bit + plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \ + PLAT_TO_VCVARS[plat_name] + + vc_env = query_vcvarsall(VERSION, plat_spec) + + # take care to only use strings in the environment. + self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep) + os.environ['lib'] = vc_env['lib'].encode('mbcs') + os.environ['include'] = vc_env['include'].encode('mbcs') + + if len(self.__paths) == 0: + raise PackagingPlatformError("Python was built with %s, " + "and extensions need to be built with the same " + "version of the compiler, but it isn't installed." + % self.__product) + + self.cc = self.find_exe("cl.exe") + self.linker = self.find_exe("link.exe") + self.lib = self.find_exe("lib.exe") + self.rc = self.find_exe("rc.exe") # resource compiler + self.mc = self.find_exe("mc.exe") # message compiler + #self.set_path_env_var('lib') + #self.set_path_env_var('include') + + # extend the MSVC path with the current path + try: + for p in os.environ['path'].split(';'): + self.__paths.append(p) + except KeyError: + pass + self.__paths = normalize_and_reduce_paths(self.__paths) + os.environ['path'] = ";".join(self.__paths) + + self.preprocess_options = None + if self.__arch == "x86": + self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', + '/DNDEBUG'] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', + '/Z7', '/D_DEBUG'] + else: + # Win64 + self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' , + '/DNDEBUG'] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-', + '/Z7', '/D_DEBUG'] + + self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] + if self.__version >= 7: + self.ldflags_shared_debug = [ + '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None' + ] + self.ldflags_static = [ '/nologo'] + + self.initialized = True + + # -- Worker methods ------------------------------------------------ + + def object_filenames(self, + source_filenames, + strip_dir=False, + output_dir=''): + # Copied from ccompiler.py, extended to return .res as 'object'-file + # for .rc input file + if output_dir is None: output_dir = '' + obj_names = [] + for src_name in source_filenames: + base, ext = os.path.splitext(src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base):] # If abs, chop off leading / + if ext not in self.src_extensions: + # Better to raise an exception instead of silently continuing + # and later complain about sources and targets having + # different lengths + raise CompileError("Don't know how to compile %s" % src_name) + if strip_dir: + base = os.path.basename(base) + if ext in self._rc_extensions: + obj_names.append(os.path.join(output_dir, + base + self.res_extension)) + elif ext in self._mc_extensions: + obj_names.append(os.path.join(output_dir, + base + self.res_extension)) + else: + obj_names.append(os.path.join(output_dir, + base + self.obj_extension)) + return obj_names + + + def compile(self, sources, + output_dir=None, macros=None, include_dirs=None, debug=False, + extra_preargs=None, extra_postargs=None, depends=None): + + if not self.initialized: + self.initialize() + compile_info = self._setup_compile(output_dir, macros, include_dirs, + sources, depends, extra_postargs) + macros, objects, extra_postargs, pp_opts, build = compile_info + + compile_opts = extra_preargs or [] + compile_opts.append('/c') + if debug: + compile_opts.extend(self.compile_options_debug) + else: + compile_opts.extend(self.compile_options) + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + if debug: + # pass the full pathname to MSVC in debug mode, + # this allows the debugger to find the source file + # without asking the user to browse for it + src = os.path.abspath(src) + + if ext in self._c_extensions: + input_opt = "/Tc" + src + elif ext in self._cpp_extensions: + input_opt = "/Tp" + src + elif ext in self._rc_extensions: + # compile .RC to .RES file + input_opt = src + output_opt = "/fo" + obj + try: + self.spawn([self.rc] + pp_opts + + [output_opt] + [input_opt]) + except PackagingExecError as msg: + raise CompileError(msg) + continue + elif ext in self._mc_extensions: + # Compile .MC to .RC file to .RES file. + # * '-h dir' specifies the directory for the + # generated include file + # * '-r dir' specifies the target directory of the + # generated RC file and the binary message resource + # it includes + # + # For now (since there are no options to change this), + # we use the source-directory for the include file and + # the build directory for the RC file and message + # resources. This works at least for win32all. + h_dir = os.path.dirname(src) + rc_dir = os.path.dirname(obj) + try: + # first compile .MC to .RC and .H file + self.spawn([self.mc] + + ['-h', h_dir, '-r', rc_dir] + [src]) + base, _ = os.path.splitext(os.path.basename(src)) + rc_file = os.path.join(rc_dir, base + '.rc') + # then compile .RC to .RES file + self.spawn([self.rc] + + ["/fo" + obj] + [rc_file]) + + except PackagingExecError as msg: + raise CompileError(msg) + continue + else: + # how to handle this file? + raise CompileError("Don't know how to compile %s to %s" + % (src, obj)) + + output_opt = "/Fo" + obj + try: + self.spawn([self.cc] + compile_opts + pp_opts + + [input_opt, output_opt] + + extra_postargs) + except PackagingExecError as msg: + raise CompileError(msg) + + return objects + + + def create_static_lib(self, + objects, + output_libname, + output_dir=None, + debug=False, + target_lang=None): + + if not self.initialized: + self.initialize() + objects, output_dir = self._fix_object_args(objects, output_dir) + output_filename = self.library_filename(output_libname, + output_dir=output_dir) + + if self._need_link(objects, output_filename): + lib_args = objects + ['/OUT:' + output_filename] + if debug: + pass # XXX what goes here? + try: + self.spawn([self.lib] + lib_args) + except PackagingExecError as msg: + raise LibError(msg) + else: + logger.debug("skipping %s (up-to-date)", output_filename) + + + def link(self, target_desc, objects, output_filename, output_dir=None, + libraries=None, library_dirs=None, runtime_library_dirs=None, + export_symbols=None, debug=False, extra_preargs=None, + extra_postargs=None, build_temp=None, target_lang=None): + if not self.initialized: + self.initialize() + objects, output_dir = self._fix_object_args(objects, output_dir) + fixed_args = self._fix_lib_args(libraries, library_dirs, + runtime_library_dirs) + libraries, library_dirs, runtime_library_dirs = fixed_args + + if runtime_library_dirs: + self.warn("don't know what to do with 'runtime_library_dirs': " + + str(runtime_library_dirs)) + + lib_opts = gen_lib_options(self, + library_dirs, runtime_library_dirs, + libraries) + if output_dir is not None: + output_filename = os.path.join(output_dir, output_filename) + + if self._need_link(objects, output_filename): + if target_desc == CCompiler.EXECUTABLE: + if debug: + ldflags = self.ldflags_shared_debug[1:] + else: + ldflags = self.ldflags_shared[1:] + else: + if debug: + ldflags = self.ldflags_shared_debug + else: + ldflags = self.ldflags_shared + + export_opts = [] + for sym in (export_symbols or []): + export_opts.append("/EXPORT:" + sym) + + ld_args = (ldflags + lib_opts + export_opts + + objects + ['/OUT:' + output_filename]) + + # The MSVC linker generates .lib and .exp files, which cannot be + # suppressed by any linker switches. The .lib files may even be + # needed! Make sure they are generated in the temporary build + # directory. Since they have different names for debug and release + # builds, they can go into the same directory. + build_temp = os.path.dirname(objects[0]) + if export_symbols is not None: + dll_name, dll_ext = os.path.splitext( + os.path.basename(output_filename)) + implib_file = os.path.join( + build_temp, + self.library_filename(dll_name)) + ld_args.append('/IMPLIB:' + implib_file) + + # Embedded manifests are recommended - see MSDN article titled + # "How to: Embed a Manifest Inside a C/C++ Application" + # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx) + # Ask the linker to generate the manifest in the temp dir, so + # we can embed it later. + temp_manifest = os.path.join( + build_temp, + os.path.basename(output_filename) + ".manifest") + ld_args.append('/MANIFESTFILE:' + temp_manifest) + + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + + self.mkpath(os.path.dirname(output_filename)) + try: + self.spawn([self.linker] + ld_args) + except PackagingExecError as msg: + raise LinkError(msg) + + # embed the manifest + # XXX - this is somewhat fragile - if mt.exe fails, distutils + # will still consider the DLL up-to-date, but it will not have a + # manifest. Maybe we should link to a temp file? OTOH, that + # implies a build environment error that shouldn't go undetected. + if target_desc == CCompiler.EXECUTABLE: + mfid = 1 + else: + mfid = 2 + self._remove_visual_c_ref(temp_manifest) + out_arg = '-outputresource:%s;%s' % (output_filename, mfid) + try: + self.spawn(['mt.exe', '-nologo', '-manifest', + temp_manifest, out_arg]) + except PackagingExecError as msg: + raise LinkError(msg) + else: + logger.debug("skipping %s (up-to-date)", output_filename) + + def _remove_visual_c_ref(self, manifest_file): + try: + # Remove references to the Visual C runtime, so they will + # fall through to the Visual C dependency of Python.exe. + # This way, when installed for a restricted user (e.g. + # runtimes are not in WinSxS folder, but in Python's own + # folder), the runtimes do not need to be in every folder + # with .pyd's. + with open(manifest_file) as manifest_f: + manifest_buf = manifest_f.read() + pattern = re.compile( + r"""|)""", + re.DOTALL) + manifest_buf = re.sub(pattern, "", manifest_buf) + pattern = "\s*" + manifest_buf = re.sub(pattern, "", manifest_buf) + with open(manifest_file, 'w') as manifest_f: + manifest_f.write(manifest_buf) + except IOError: + pass + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. + + def library_dir_option(self, dir): + return "/LIBPATH:" + dir + + def runtime_library_dir_option(self, dir): + raise PackagingPlatformError( + "don't know how to set runtime library search path for MSVC++") + + def library_option(self, lib): + return self.library_filename(lib) + + + def find_library_file(self, dirs, lib, debug=False): + # Prefer a debugging library if found (and requested), but deal + # with it if we don't have one. + if debug: + try_names = [lib + "_d", lib] + else: + try_names = [lib] + for dir in dirs: + for name in try_names: + libfile = os.path.join(dir, self.library_filename(name)) + if os.path.exists(libfile): + return libfile + else: + # Oops, didn't find it in *any* of 'dirs' + return None + + # Helper methods for using the MSVC registry settings + + def find_exe(self, exe): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + for p in self.__paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + + # didn't find it; try existing path + for p in os.environ['Path'].split(';'): + fn = os.path.join(os.path.abspath(p),exe) + if os.path.isfile(fn): + return fn + + return exe diff --git a/Lib/packaging/compiler/msvccompiler.py b/Lib/packaging/compiler/msvccompiler.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/compiler/msvccompiler.py @@ -0,0 +1,636 @@ +"""CCompiler implementation for old Microsoft Visual Studio compilers. + +For a compiler compatible with VS 2005 and 2008, use msvc9compiler. +""" + +# Written by Perry Stoll +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) + + +import sys +import os + +from packaging.errors import (PackagingExecError, PackagingPlatformError, + CompileError, LibError, LinkError) +from packaging.compiler.ccompiler import CCompiler +from packaging.compiler import gen_lib_options +from packaging import logger + +_can_read_reg = False +try: + import winreg + + _can_read_reg = True + hkey_mod = winreg + + RegOpenKeyEx = winreg.OpenKeyEx + RegEnumKey = winreg.EnumKey + RegEnumValue = winreg.EnumValue + RegError = winreg.error + +except ImportError: + try: + import win32api + import win32con + _can_read_reg = True + hkey_mod = win32con + + RegOpenKeyEx = win32api.RegOpenKeyEx + RegEnumKey = win32api.RegEnumKey + RegEnumValue = win32api.RegEnumValue + RegError = win32api.error + + except ImportError: + logger.warning( + "can't read registry to find the necessary compiler setting;\n" + "make sure that Python modules _winreg, win32api or win32con " + "are installed.") + +if _can_read_reg: + HKEYS = (hkey_mod.HKEY_USERS, + hkey_mod.HKEY_CURRENT_USER, + hkey_mod.HKEY_LOCAL_MACHINE, + hkey_mod.HKEY_CLASSES_ROOT) + + +def read_keys(base, key): + """Return list of registry keys.""" + + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + L = [] + i = 0 + while True: + try: + k = RegEnumKey(handle, i) + except RegError: + break + L.append(k) + i = i + 1 + return L + + +def read_values(base, key): + """Return dict of registry keys and values. + + All names are converted to lowercase. + """ + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + d = {} + i = 0 + while True: + try: + name, value, type = RegEnumValue(handle, i) + except RegError: + break + name = name.lower() + d[convert_mbcs(name)] = convert_mbcs(value) + i = i + 1 + return d + + +def convert_mbcs(s): + enc = getattr(s, "encode", None) + if enc is not None: + try: + s = enc("mbcs") + except UnicodeError: + pass + return s + + +class MacroExpander: + + def __init__(self, version): + self.macros = {} + self.load_macros(version) + + def set_macro(self, macro, path, key): + for base in HKEYS: + d = read_values(base, path) + if d: + self.macros["$(%s)" % macro] = d[key] + break + + def load_macros(self, version): + vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version + self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir") + self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir") + net = r"Software\Microsoft\.NETFramework" + self.set_macro("FrameworkDir", net, "installroot") + try: + if version > 7.0: + self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1") + else: + self.set_macro("FrameworkSDKDir", net, "sdkinstallroot") + except KeyError: + raise PackagingPlatformError( +"""Python was built with Visual Studio 2003; extensions must be built with +a compiler than can generate compatible binaries. Visual Studio 2003 was +not found on this system. If you have Cygwin installed, you can try +compiling with MingW32, by passing "-c mingw32" to setup.py.""") +# XXX update this comment for setup.cfg + + p = r"Software\Microsoft\NET Framework Setup\Product" + for base in HKEYS: + try: + h = RegOpenKeyEx(base, p) + except RegError: + continue + key = RegEnumKey(h, 0) + d = read_values(base, r"%s\%s" % (p, key)) + self.macros["$(FrameworkVersion)"] = d["version"] + + def sub(self, s): + for k, v in self.macros.items(): + s = s.replace(k, v) + return s + + +def get_build_version(): + """Return the version of MSVC that was used to build Python. + + For Python 2.3 and up, the version number is included in + sys.version. For earlier versions, assume the compiler is MSVC 6. + """ + + prefix = "MSC v." + i = sys.version.find(prefix) + if i == -1: + return 6 + i = i + len(prefix) + s, rest = sys.version[i:].split(" ", 1) + majorVersion = int(s[:-2]) - 6 + minorVersion = int(s[2:3]) / 10.0 + # I don't think paths are affected by minor version in version 6 + if majorVersion == 6: + minorVersion = 0 + if majorVersion >= 6: + return majorVersion + minorVersion + # else we don't know what version of the compiler this is + return None + + +def get_build_architecture(): + """Return the processor architecture. + + Possible results are "Intel", "Itanium", or "AMD64". + """ + + prefix = " bit (" + i = sys.version.find(prefix) + if i == -1: + return "Intel" + j = sys.version.find(")", i) + return sys.version[i+len(prefix):j] + + +def normalize_and_reduce_paths(paths): + """Return a list of normalized paths with duplicates removed. + + The current order of paths is maintained. + """ + # Paths are normalized so things like: /a and /a/ aren't both preserved. + reduced_paths = [] + for p in paths: + np = os.path.normpath(p) + # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set. + if np not in reduced_paths: + reduced_paths.append(np) + return reduced_paths + + +class MSVCCompiler(CCompiler): + """Concrete class that implements an interface to Microsoft Visual C++, + as defined by the CCompiler abstract class.""" + + name = 'msvc' + description = "Microsoft Visual C++" + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + _rc_extensions = ['.rc'] + _mc_extensions = ['.mc'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = (_c_extensions + _cpp_extensions + + _rc_extensions + _mc_extensions) + res_extension = '.res' + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + def __init__(self, verbose=0, dry_run=False, force=False): + CCompiler.__init__(self, verbose, dry_run, force) + self.__version = get_build_version() + self.__arch = get_build_architecture() + if self.__arch == "Intel": + # x86 + if self.__version >= 7: + self.__root = r"Software\Microsoft\VisualStudio" + self.__macros = MacroExpander(self.__version) + else: + self.__root = r"Software\Microsoft\Devstudio" + self.__product = "Visual Studio version %s" % self.__version + else: + # Win64. Assume this was built with the platform SDK + self.__product = "Microsoft SDK compiler %s" % (self.__version + 6) + + self.initialized = False + + def initialize(self): + self.__paths = [] + if ("DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and + self.find_exe("cl.exe")): + # Assume that the SDK set up everything alright; don't try to be + # smarter + self.cc = "cl.exe" + self.linker = "link.exe" + self.lib = "lib.exe" + self.rc = "rc.exe" + self.mc = "mc.exe" + else: + self.__paths = self.get_msvc_paths("path") + + if len(self.__paths) == 0: + raise PackagingPlatformError("Python was built with %s " + "and extensions need to be built with the same " + "version of the compiler, but it isn't installed." % + self.__product) + + self.cc = self.find_exe("cl.exe") + self.linker = self.find_exe("link.exe") + self.lib = self.find_exe("lib.exe") + self.rc = self.find_exe("rc.exe") # resource compiler + self.mc = self.find_exe("mc.exe") # message compiler + self.set_path_env_var('lib') + self.set_path_env_var('include') + + # extend the MSVC path with the current path + try: + for p in os.environ['path'].split(';'): + self.__paths.append(p) + except KeyError: + pass + self.__paths = normalize_and_reduce_paths(self.__paths) + os.environ['path'] = ';'.join(self.__paths) + + self.preprocess_options = None + if self.__arch == "Intel": + self.compile_options = ['/nologo', '/Ox', '/MD', '/W3', '/GX', + '/DNDEBUG'] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX', + '/Z7', '/D_DEBUG'] + else: + # Win64 + self.compile_options = ['/nologo', '/Ox', '/MD', '/W3', '/GS-', + '/DNDEBUG'] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-', + '/Z7', '/D_DEBUG'] + + self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] + if self.__version >= 7: + self.ldflags_shared_debug = [ + '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG' + ] + else: + self.ldflags_shared_debug = [ + '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG' + ] + self.ldflags_static = [ '/nologo'] + + self.initialized = True + + # -- Worker methods ------------------------------------------------ + + def object_filenames(self, source_filenames, strip_dir=False, output_dir=''): + # Copied from ccompiler.py, extended to return .res as 'object'-file + # for .rc input file + if output_dir is None: + output_dir = '' + obj_names = [] + for src_name in source_filenames: + base, ext = os.path.splitext(src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base):] # If abs, chop off leading / + if ext not in self.src_extensions: + # Better to raise an exception instead of silently continuing + # and later complain about sources and targets having + # different lengths + raise CompileError("Don't know how to compile %s" % src_name) + if strip_dir: + base = os.path.basename(base) + if ext in self._rc_extensions: + obj_names.append(os.path.join(output_dir, + base + self.res_extension)) + elif ext in self._mc_extensions: + obj_names.append(os.path.join(output_dir, + base + self.res_extension)) + else: + obj_names.append(os.path.join(output_dir, + base + self.obj_extension)) + return obj_names + + def compile(self, sources, + output_dir=None, macros=None, include_dirs=None, debug=False, + extra_preargs=None, extra_postargs=None, depends=None): + + if not self.initialized: + self.initialize() + macros, objects, extra_postargs, pp_opts, build = \ + self._setup_compile(output_dir, macros, include_dirs, sources, + depends, extra_postargs) + + compile_opts = extra_preargs or [] + compile_opts.append('/c') + if debug: + compile_opts.extend(self.compile_options_debug) + else: + compile_opts.extend(self.compile_options) + + for obj in objects: + try: + src, ext = build[obj] + except KeyError: + continue + if debug: + # pass the full pathname to MSVC in debug mode, + # this allows the debugger to find the source file + # without asking the user to browse for it + src = os.path.abspath(src) + + if ext in self._c_extensions: + input_opt = "/Tc" + src + elif ext in self._cpp_extensions: + input_opt = "/Tp" + src + elif ext in self._rc_extensions: + # compile .RC to .RES file + input_opt = src + output_opt = "/fo" + obj + try: + self.spawn([self.rc] + pp_opts + + [output_opt] + [input_opt]) + except PackagingExecError as msg: + raise CompileError(msg) + continue + elif ext in self._mc_extensions: + + # Compile .MC to .RC file to .RES file. + # * '-h dir' specifies the directory for the + # generated include file + # * '-r dir' specifies the target directory of the + # generated RC file and the binary message resource + # it includes + # + # For now (since there are no options to change this), + # we use the source-directory for the include file and + # the build directory for the RC file and message + # resources. This works at least for win32all. + + h_dir = os.path.dirname(src) + rc_dir = os.path.dirname(obj) + try: + # first compile .MC to .RC and .H file + self.spawn([self.mc] + + ['-h', h_dir, '-r', rc_dir] + [src]) + base, _ = os.path.splitext(os.path.basename(src)) + rc_file = os.path.join(rc_dir, base + '.rc') + # then compile .RC to .RES file + self.spawn([self.rc] + + ["/fo" + obj] + [rc_file]) + + except PackagingExecError as msg: + raise CompileError(msg) + continue + else: + # how to handle this file? + raise CompileError( + "Don't know how to compile %s to %s" % + (src, obj)) + + output_opt = "/Fo" + obj + try: + self.spawn([self.cc] + compile_opts + pp_opts + + [input_opt, output_opt] + + extra_postargs) + except PackagingExecError as msg: + raise CompileError(msg) + + return objects + + def create_static_lib(self, objects, output_libname, output_dir=None, + debug=False, target_lang=None): + if not self.initialized: + self.initialize() + objects, output_dir = self._fix_object_args(objects, output_dir) + output_filename = \ + self.library_filename(output_libname, output_dir=output_dir) + + if self._need_link(objects, output_filename): + lib_args = objects + ['/OUT:' + output_filename] + if debug: + pass # XXX what goes here? + try: + self.spawn([self.lib] + lib_args) + except PackagingExecError as msg: + raise LibError(msg) + + else: + logger.debug("skipping %s (up-to-date)", output_filename) + + def link(self, target_desc, objects, output_filename, output_dir=None, + libraries=None, library_dirs=None, runtime_library_dirs=None, + export_symbols=None, debug=False, extra_preargs=None, + extra_postargs=None, build_temp=None, target_lang=None): + + if not self.initialized: + self.initialize() + objects, output_dir = self._fix_object_args(objects, output_dir) + libraries, library_dirs, runtime_library_dirs = \ + self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) + + if runtime_library_dirs: + self.warn("don't know what to do with 'runtime_library_dirs': %s" + % (runtime_library_dirs,)) + + lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, + libraries) + if output_dir is not None: + output_filename = os.path.join(output_dir, output_filename) + + if self._need_link(objects, output_filename): + + if target_desc == CCompiler.EXECUTABLE: + if debug: + ldflags = self.ldflags_shared_debug[1:] + else: + ldflags = self.ldflags_shared[1:] + else: + if debug: + ldflags = self.ldflags_shared_debug + else: + ldflags = self.ldflags_shared + + export_opts = [] + for sym in (export_symbols or []): + export_opts.append("/EXPORT:" + sym) + + ld_args = (ldflags + lib_opts + export_opts + + objects + ['/OUT:' + output_filename]) + + # The MSVC linker generates .lib and .exp files, which cannot be + # suppressed by any linker switches. The .lib files may even be + # needed! Make sure they are generated in the temporary build + # directory. Since they have different names for debug and release + # builds, they can go into the same directory. + if export_symbols is not None: + dll_name, dll_ext = os.path.splitext( + os.path.basename(output_filename)) + implib_file = os.path.join( + os.path.dirname(objects[0]), + self.library_filename(dll_name)) + ld_args.append('/IMPLIB:' + implib_file) + + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + + self.mkpath(os.path.dirname(output_filename)) + try: + self.spawn([self.linker] + ld_args) + except PackagingExecError as msg: + raise LinkError(msg) + + else: + logger.debug("skipping %s (up-to-date)", output_filename) + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. + + def library_dir_option(self, dir): + return "/LIBPATH:" + dir + + def runtime_library_dir_option(self, dir): + raise PackagingPlatformError("don't know how to set runtime library search path for MSVC++") + + def library_option(self, lib): + return self.library_filename(lib) + + def find_library_file(self, dirs, lib, debug=False): + # Prefer a debugging library if found (and requested), but deal + # with it if we don't have one. + if debug: + try_names = [lib + "_d", lib] + else: + try_names = [lib] + for dir in dirs: + for name in try_names: + libfile = os.path.join(dir, self.library_filename(name)) + if os.path.exists(libfile): + return libfile + else: + # Oops, didn't find it in *any* of 'dirs' + return None + + # Helper methods for using the MSVC registry settings + + def find_exe(self, exe): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + + for p in self.__paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + + # didn't find it; try existing path + for p in os.environ['Path'].split(';'): + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + + return exe + + def get_msvc_paths(self, path, platform='x86'): + """Get a list of devstudio directories (include, lib or path). + + Return a list of strings. The list will be empty if unable to + access the registry or appropriate registry keys not found. + """ + + if not _can_read_reg: + return [] + + path = path + " dirs" + if self.__version >= 7: + key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" + % (self.__root, self.__version)) + else: + key = (r"%s\6.0\Build System\Components\Platforms" + r"\Win32 (%s)\Directories" % (self.__root, platform)) + + for base in HKEYS: + d = read_values(base, key) + if d: + if self.__version >= 7: + return self.__macros.sub(d[path]).split(";") + else: + return d[path].split(";") + # MSVC 6 seems to create the registry entries we need only when + # the GUI is run. + if self.__version == 6: + for base in HKEYS: + if read_values(base, r"%s\6.0" % self.__root) is not None: + self.warn("It seems you have Visual Studio 6 installed, " + "but the expected registry settings are not present.\n" + "You must at least run the Visual Studio GUI once " + "so that these entries are created.") + break + return [] + + def set_path_env_var(self, name): + """Set environment variable 'name' to an MSVC path type value. + + This is equivalent to a SET command prior to execution of spawned + commands. + """ + + if name == "lib": + p = self.get_msvc_paths("library") + else: + p = self.get_msvc_paths(name) + if p: + os.environ[name] = ';'.join(p) + + +if get_build_version() >= 8.0: + logger.debug("importing new compiler from distutils.msvc9compiler") + OldMSVCCompiler = MSVCCompiler + from packaging.compiler.msvc9compiler import MSVCCompiler + # get_build_architecture not really relevant now we support cross-compile + from packaging.compiler.msvc9compiler import MacroExpander diff --git a/Lib/packaging/compiler/unixccompiler.py b/Lib/packaging/compiler/unixccompiler.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/compiler/unixccompiler.py @@ -0,0 +1,339 @@ +"""CCompiler implementation for Unix compilers. + +This module contains the UnixCCompiler class, a subclass of CCompiler +that handles the "typical" Unix-style command-line C compiler: + * macros defined with -Dname[=value] + * macros undefined with -Uname + * include search directories specified with -Idir + * libraries specified with -lllib + * library search directories specified with -Ldir + * compile handled by 'cc' (or similar) executable with -c option: + compiles .c to .o + * link static library handled by 'ar' command (possibly with 'ranlib') + * link shared library handled by 'cc -shared' +""" + +import os, sys + +from packaging.util import newer +from packaging.compiler.ccompiler import CCompiler +from packaging.compiler import gen_preprocess_options, gen_lib_options +from packaging.errors import (PackagingExecError, CompileError, + LibError, LinkError) +from packaging import logger +import sysconfig + + +# XXX Things not currently handled: +# * optimization/debug/warning flags; we just use whatever's in Python's +# Makefile and live with it. Is this adequate? If not, we might +# have to have a bunch of subclasses GNUCCompiler, SGICCompiler, +# SunCCompiler, and I suspect down that road lies madness. +# * even if we don't know a warning flag from an optimization flag, +# we need some way for outsiders to feed preprocessor/compiler/linker +# flags in to us -- eg. a sysadmin might want to mandate certain flags +# via a site config file, or a user might want to set something for +# compiling this module distribution only via the setup.py command +# line, whatever. As long as these options come from something on the +# current system, they can be as system-dependent as they like, and we +# should just happily stuff them into the preprocessor/compiler/linker +# options and carry on. + +def _darwin_compiler_fixup(compiler_so, cc_args): + """ + This function will strip '-isysroot PATH' and '-arch ARCH' from the + compile flags if the user has specified one them in extra_compile_flags. + + This is needed because '-arch ARCH' adds another architecture to the + build, without a way to remove an architecture. Furthermore GCC will + barf if multiple '-isysroot' arguments are present. + """ + stripArch = stripSysroot = False + + compiler_so = list(compiler_so) + kernel_version = os.uname()[2] # 8.4.3 + major_version = int(kernel_version.split('.')[0]) + + if major_version < 8: + # OSX before 10.4.0, these don't support -arch and -isysroot at + # all. + stripArch = stripSysroot = True + else: + stripArch = '-arch' in cc_args + stripSysroot = '-isysroot' in cc_args + + if stripArch or 'ARCHFLAGS' in os.environ: + while True: + try: + index = compiler_so.index('-arch') + # Strip this argument and the next one: + del compiler_so[index:index+2] + except ValueError: + break + + if 'ARCHFLAGS' in os.environ and not stripArch: + # User specified different -arch flags in the environ, + # see also the sysconfig + compiler_so = compiler_so + os.environ['ARCHFLAGS'].split() + + if stripSysroot: + try: + index = compiler_so.index('-isysroot') + # Strip this argument and the next one: + del compiler_so[index:index+2] + except ValueError: + pass + + # Check if the SDK that is used during compilation actually exists, + # the universal build requires the usage of a universal SDK and not all + # users have that installed by default. + sysroot = None + if '-isysroot' in cc_args: + idx = cc_args.index('-isysroot') + sysroot = cc_args[idx+1] + elif '-isysroot' in compiler_so: + idx = compiler_so.index('-isysroot') + sysroot = compiler_so[idx+1] + + if sysroot and not os.path.isdir(sysroot): + logger.warning( + "compiling with an SDK that doesn't seem to exist: %r;\n" + "please check your Xcode installation", sysroot) + + return compiler_so + +class UnixCCompiler(CCompiler): + + name = 'unix' + description = 'Standard UNIX-style compiler' + + # These are used by CCompiler in two places: the constructor sets + # instance attributes 'preprocessor', 'compiler', etc. from them, and + # 'set_executable()' allows any of these to be set. The defaults here + # are pretty generic; they will probably have to be set by an outsider + # (eg. using information discovered by the sysconfig about building + # Python extensions). + executables = {'preprocessor' : None, + 'compiler' : ["cc"], + 'compiler_so' : ["cc"], + 'compiler_cxx' : ["cc"], + 'linker_so' : ["cc", "-shared"], + 'linker_exe' : ["cc"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : None, + } + + if sys.platform[:6] == "darwin": + executables['ranlib'] = ["ranlib"] + + # Needed for the filename generation methods provided by the base + # class, CCompiler. NB. whoever instantiates/uses a particular + # UnixCCompiler instance should set 'shared_lib_ext' -- we set a + # reasonable common default here, but it's not necessarily used on all + # Unices! + + src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"] + obj_extension = ".o" + static_lib_extension = ".a" + shared_lib_extension = ".so" + dylib_lib_extension = ".dylib" + static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s" + if sys.platform == "cygwin": + exe_extension = ".exe" + + def preprocess(self, source, + output_file=None, macros=None, include_dirs=None, + extra_preargs=None, extra_postargs=None): + ignore, macros, include_dirs = \ + self._fix_compile_args(None, macros, include_dirs) + pp_opts = gen_preprocess_options(macros, include_dirs) + pp_args = self.preprocessor + pp_opts + if output_file: + pp_args.extend(('-o', output_file)) + if extra_preargs: + pp_args[:0] = extra_preargs + if extra_postargs: + pp_args.extend(extra_postargs) + pp_args.append(source) + + # We need to preprocess: either we're being forced to, or we're + # generating output to stdout, or there's a target output file and + # the source file is newer than the target (or the target doesn't + # exist). + if self.force or output_file is None or newer(source, output_file): + if output_file: + self.mkpath(os.path.dirname(output_file)) + try: + self.spawn(pp_args) + except PackagingExecError as msg: + raise CompileError(msg) + + def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + compiler_so = self.compiler_so + if sys.platform == 'darwin': + compiler_so = _darwin_compiler_fixup(compiler_so, cc_args + extra_postargs) + try: + self.spawn(compiler_so + cc_args + [src, '-o', obj] + + extra_postargs) + except PackagingExecError as msg: + raise CompileError(msg) + + def create_static_lib(self, objects, output_libname, + output_dir=None, debug=False, target_lang=None): + objects, output_dir = self._fix_object_args(objects, output_dir) + + output_filename = \ + self.library_filename(output_libname, output_dir=output_dir) + + if self._need_link(objects, output_filename): + self.mkpath(os.path.dirname(output_filename)) + self.spawn(self.archiver + + [output_filename] + + objects + self.objects) + + # Not many Unices required ranlib anymore -- SunOS 4.x is, I + # think the only major Unix that does. Maybe we need some + # platform intelligence here to skip ranlib if it's not + # needed -- or maybe Python's configure script took care of + # it for us, hence the check for leading colon. + if self.ranlib: + try: + self.spawn(self.ranlib + [output_filename]) + except PackagingExecError as msg: + raise LibError(msg) + else: + logger.debug("skipping %s (up-to-date)", output_filename) + + def link(self, target_desc, objects, + output_filename, output_dir=None, libraries=None, + library_dirs=None, runtime_library_dirs=None, + export_symbols=None, debug=False, extra_preargs=None, + extra_postargs=None, build_temp=None, target_lang=None): + objects, output_dir = self._fix_object_args(objects, output_dir) + libraries, library_dirs, runtime_library_dirs = \ + self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) + + lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, + libraries) + if type(output_dir) not in (str, type(None)): + raise TypeError("'output_dir' must be a string or None") + if output_dir is not None: + output_filename = os.path.join(output_dir, output_filename) + + if self._need_link(objects, output_filename): + ld_args = (objects + self.objects + + lib_opts + ['-o', output_filename]) + if debug: + ld_args[:0] = ['-g'] + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + self.mkpath(os.path.dirname(output_filename)) + try: + if target_desc == CCompiler.EXECUTABLE: + linker = self.linker_exe[:] + else: + linker = self.linker_so[:] + if target_lang == "c++" and self.compiler_cxx: + # skip over environment variable settings if /usr/bin/env + # is used to set up the linker's environment. + # This is needed on OSX. Note: this assumes that the + # normal and C++ compiler have the same environment + # settings. + i = 0 + if os.path.basename(linker[0]) == "env": + i = 1 + while '=' in linker[i]: + i = i + 1 + + linker[i] = self.compiler_cxx[i] + + if sys.platform == 'darwin': + linker = _darwin_compiler_fixup(linker, ld_args) + + self.spawn(linker + ld_args) + except PackagingExecError as msg: + raise LinkError(msg) + else: + logger.debug("skipping %s (up-to-date)", output_filename) + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. + + def library_dir_option(self, dir): + return "-L" + dir + + def _is_gcc(self, compiler_name): + return "gcc" in compiler_name or "g++" in compiler_name + + def runtime_library_dir_option(self, dir): + # XXX Hackish, at the very least. See Python bug #445902: + # http://sourceforge.net/tracker/index.php + # ?func=detail&aid=445902&group_id=5470&atid=105470 + # Linkers on different platforms need different options to + # specify that directories need to be added to the list of + # directories searched for dependencies when a dynamic library + # is sought. GCC on GNU systems (Linux, FreeBSD, ...) has to + # be told to pass the -R option through to the linker, whereas + # other compilers and gcc on other systems just know this. + # Other compilers may need something slightly different. At + # this time, there's no way to determine this information from + # the configuration data stored in the Python installation, so + # we use this hack. + + compiler = os.path.basename(sysconfig.get_config_var("CC")) + if sys.platform[:6] == "darwin": + # MacOSX's linker doesn't understand the -R flag at all + return "-L" + dir + elif sys.platform[:5] == "hp-ux": + if self._is_gcc(compiler): + return ["-Wl,+s", "-L" + dir] + return ["+s", "-L" + dir] + elif sys.platform[:7] == "irix646" or sys.platform[:6] == "osf1V5": + return ["-rpath", dir] + elif self._is_gcc(compiler): + # gcc on non-GNU systems does not need -Wl, but can + # use it anyway. Since distutils has always passed in + # -Wl whenever gcc was used in the past it is probably + # safest to keep doing so. + if sysconfig.get_config_var("GNULD") == "yes": + # GNU ld needs an extra option to get a RUNPATH + # instead of just an RPATH. + return "-Wl,--enable-new-dtags,-R" + dir + else: + return "-Wl,-R" + dir + elif sys.platform[:3] == "aix": + return "-blibpath:" + dir + else: + # No idea how --enable-new-dtags would be passed on to + # ld if this system was using GNU ld. Don't know if a + # system like this even exists. + return "-R" + dir + + def library_option(self, lib): + return "-l" + lib + + def find_library_file(self, dirs, lib, debug=False): + shared_f = self.library_filename(lib, lib_type='shared') + dylib_f = self.library_filename(lib, lib_type='dylib') + static_f = self.library_filename(lib, lib_type='static') + + for dir in dirs: + shared = os.path.join(dir, shared_f) + dylib = os.path.join(dir, dylib_f) + static = os.path.join(dir, static_f) + # We're second-guessing the linker here, with not much hard + # data to go on: GCC seems to prefer the shared library, so I'm + # assuming that *all* Unix C compilers do. And of course I'm + # ignoring even GCC's "-static" option. So sue me. + if os.path.exists(dylib): + return dylib + elif os.path.exists(shared): + return shared + elif os.path.exists(static): + return static + + # Oops, didn't find it in *any* of 'dirs' + return None diff --git a/Lib/packaging/config.py b/Lib/packaging/config.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/config.py @@ -0,0 +1,357 @@ +"""Utilities to find and read config files used by packaging.""" + +import os +import sys +import logging + +from shlex import split +from configparser import RawConfigParser +from packaging import logger +from packaging.errors import PackagingOptionError +from packaging.compiler.extension import Extension +from packaging.util import check_environ, iglob, resolve_name, strtobool +from packaging.compiler import set_compiler +from packaging.command import set_command +from packaging.markers import interpret + + +def _pop_values(values_dct, key): + """Remove values from the dictionary and convert them as a list""" + vals_str = values_dct.pop(key, '') + if not vals_str: + return + fields = [] + for field in vals_str.split(os.linesep): + tmp_vals = field.split('--') + if len(tmp_vals) == 2 and not interpret(tmp_vals[1]): + continue + fields.append(tmp_vals[0]) + # Get bash options like `gcc -print-file-name=libgcc.a` XXX bash options? + vals = split(' '.join(fields)) + if vals: + return vals + + +def _rel_path(base, path): + assert path.startswith(base) + return path[len(base):].lstrip('/') + + +def get_resources_dests(resources_root, rules): + """Find destinations for resources files""" + destinations = {} + for base, suffix, dest in rules: + prefix = os.path.join(resources_root, base) + for abs_base in iglob(prefix): + abs_glob = os.path.join(abs_base, suffix) + for abs_path in iglob(abs_glob): + resource_file = _rel_path(resources_root, abs_path) + if dest is None: # remove the entry if it was here + destinations.pop(resource_file, None) + else: + rel_path = _rel_path(abs_base, abs_path) + destinations[resource_file] = os.path.join(dest, rel_path) + return destinations + + +class Config: + """Reads configuration files and work with the Distribution instance + """ + def __init__(self, dist): + self.dist = dist + self.setup_hook = None + + def run_hook(self, config): + if self.setup_hook is None: + return + # the hook gets only the config + self.setup_hook(config) + + def find_config_files(self): + """Find as many configuration files as should be processed for this + platform, and return a list of filenames in the order in which they + should be parsed. The filenames returned are guaranteed to exist + (modulo nasty race conditions). + + There are three possible config files: packaging.cfg in the + Packaging installation directory (ie. where the top-level + Packaging __inst__.py file lives), a file in the user's home + directory named .pydistutils.cfg on Unix and pydistutils.cfg + on Windows/Mac; and setup.cfg in the current directory. + + The file in the user's home directory can be disabled with the + --no-user-cfg option. + """ + files = [] + check_environ() + + # Where to look for the system-wide Packaging config file + sys_dir = os.path.dirname(sys.modules['packaging'].__file__) + + # Look for the system config file + sys_file = os.path.join(sys_dir, "packaging.cfg") + if os.path.isfile(sys_file): + files.append(sys_file) + + # What to call the per-user config file + if os.name == 'posix': + user_filename = ".pydistutils.cfg" + else: + user_filename = "pydistutils.cfg" + + # And look for the user config file + if self.dist.want_user_cfg: + user_file = os.path.join(os.path.expanduser('~'), user_filename) + if os.path.isfile(user_file): + files.append(user_file) + + # All platforms support local setup.cfg + local_file = "setup.cfg" + if os.path.isfile(local_file): + files.append(local_file) + + if logger.isEnabledFor(logging.DEBUG): + logger.debug("using config files: %s", ', '.join(files)) + return files + + def _convert_metadata(self, name, value): + # converts a value found in setup.cfg into a valid metadata + # XXX + return value + + def _multiline(self, value): + value = [v for v in + [v.strip() for v in value.split('\n')] + if v != ''] + return value + + def _read_setup_cfg(self, parser, cfg_filename): + cfg_directory = os.path.dirname(os.path.abspath(cfg_filename)) + content = {} + for section in parser.sections(): + content[section] = dict(parser.items(section)) + + # global:setup_hook is called *first* + if 'global' in content: + if 'setup_hook' in content['global']: + setup_hook = content['global']['setup_hook'] + try: + self.setup_hook = resolve_name(setup_hook) + except ImportError as e: + logger.warning('could not import setup_hook: %s', + e.args[0]) + else: + self.run_hook(content) + + metadata = self.dist.metadata + + # setting the metadata values + if 'metadata' in content: + for key, value in content['metadata'].items(): + key = key.replace('_', '-') + if metadata.is_multi_field(key): + value = self._multiline(value) + + if key == 'project-url': + value = [(label.strip(), url.strip()) + for label, url in + [v.split(',') for v in value]] + + if key == 'description-file': + if 'description' in content['metadata']: + msg = ("description and description-file' are " + "mutually exclusive") + raise PackagingOptionError(msg) + + if isinstance(value, list): + filenames = value + else: + filenames = value.split() + + # concatenate each files + value = '' + for filename in filenames: + # will raise if file not found + with open(filename) as description_file: + value += description_file.read().strip() + '\n' + # 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 = content['files'] + self.dist.package_dir = files.pop('packages_root', None) + + files = dict((key, self._multiline(value)) for key, value in + files.items()) + + self.dist.packages = [] + + 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', []) + if isinstance(self.dist.py_modules, str): + self.dist.py_modules = [self.dist.py_modules] + self.dist.scripts = files.get('scripts', []) + if isinstance(self.dist.scripts, str): + self.dist.scripts = [self.dist.scripts] + + self.dist.package_data = {} + for data in files.get('package_data', []): + data = data.split('=') + if len(data) != 2: + continue # XXX error should never pass silently + key, value = data + self.dist.package_data[key.strip()] = value.strip() + + self.dist.data_files = [] + for data in files.get('data_files', []): + data = data.split('=') + if len(data) != 2: + continue + key, value = data + values = [v.strip() for v in value.split(',')] + self.dist.data_files.append((key, values)) + + # manifest template + self.dist.extra_files = files.get('extra_files', []) + + resources = [] + for rule in files.get('resources', []): + glob, destination = rule.split('=', 1) + rich_glob = glob.strip().split(' ', 1) + if len(rich_glob) == 2: + prefix, suffix = rich_glob + else: + assert len(rich_glob) == 1 + prefix = '' + suffix = glob + if destination == '': + destination = None + resources.append( + (prefix.strip(), suffix.strip(), destination.strip())) + self.dist.data_files = get_resources_dests( + cfg_directory, resources) + + 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() + + logger.debug("Distribution.parse_config_files():") + + parser = RawConfigParser() + + for filename in filenames: + logger.debug(" reading %s", filename) + parser.read(filename) + + if os.path.split(filename)[-1] == 'setup.cfg': + self._read_setup_cfg(parser, filename) + + for section in parser.sections(): + if section == 'global': + if parser.has_option('global', 'compilers'): + self._load_compilers(parser.get('global', 'compilers')) + + if parser.has_option('global', 'commands'): + self._load_commands(parser.get('global', 'commands')) + + options = parser.options(section) + opt_dict = self.dist.get_option_dict(section) + + for opt in options: + if opt == '__name__': + continue + val = parser.get(section, opt) + opt = opt.replace('-', '_') + + if opt == 'sub_commands': + val = self._multiline(val) + if isinstance(val, str): + val = [val] + + # Hooks use a suffix system to prevent being overriden + # by a config file processed later (i.e. a hook set in + # the user config file cannot be replaced by a hook + # set in a project config file, unless they have the + # same suffix). + if (opt.startswith("pre_hook.") or + opt.startswith("post_hook.")): + hook_type, alias = opt.split(".") + hook_dict = opt_dict.setdefault( + hook_type, (filename, {}))[1] + hook_dict[alias] = val + else: + opt_dict[opt] = filename, val + + # Make the RawConfigParser forget everything (so we retain + # the original filenames that options come from) + parser.__init__() + + # If there was a "global" section in the config file, use it + # to set Distribution options. + if 'global' in self.dist.command_options: + for opt, (src, val) in self.dist.command_options['global'].items(): + alias = self.dist.negative_opt.get(opt) + try: + if alias: + setattr(self.dist, alias, not strtobool(val)) + elif opt == 'dry_run': # FIXME ugh! + setattr(self.dist, opt, strtobool(val)) + else: + setattr(self.dist, opt, val) + except ValueError as msg: + raise PackagingOptionError(msg) + + def _load_compilers(self, compilers): + compilers = self._multiline(compilers) + if isinstance(compilers, str): + compilers = [compilers] + for compiler in compilers: + set_compiler(compiler.strip()) + + def _load_commands(self, commands): + commands = self._multiline(commands) + if isinstance(commands, str): + commands = [commands] + for command in commands: + set_command(command.strip()) diff --git a/Lib/packaging/create.py b/Lib/packaging/create.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/create.py @@ -0,0 +1,693 @@ +#!/usr/bin/env python +"""Interactive helper used to create a setup.cfg file. + +This script will generate a packaging configuration file by looking at +the current directory and asking the user questions. It is intended to +be called as + + pysetup create + +or + + python3.3 -m packaging.create +""" + +# Original code by Sean Reifschneider + +# Original TODO list: +# Look for a license file and automatically add the category. +# When a .c file is found during the walk, can we add it as an extension? +# Ask if there is a maintainer different that the author +# Ask for the platform (can we detect this via "import win32" or something?) +# 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 imp +import sys +import glob +import re +import shutil +import sysconfig +from configparser import RawConfigParser +from textwrap import dedent +from hashlib import md5 +from functools import cmp_to_key +# importing this with an underscore as it should be replaced by the +# dict form or another structures for all purposes +from packaging._trove import all_classifiers as _CLASSIFIERS_LIST +from packaging.version import is_valid_version + +_FILENAME = 'setup.cfg' +_DEFAULT_CFG = '.pypkgcreate' + +_helptext = { + 'name': ''' +The name of the program to be packaged, usually a single word composed +of lower-case characters such as "python", "sqlalchemy", or "CherryPy". +''', + 'version': ''' +Version number of the software, typically 2 or 3 numbers separated by dots +such as "1.00", "0.6", or "3.02.01". "0.1.0" is recommended for initial +development. +''', + 'summary': ''' +A one-line summary of what this project is or does, typically a sentence 80 +characters or less in length. +''', + 'author': ''' +The full name of the author (typically you). +''', + 'author_email': ''' +E-mail address of the project author (typically you). +''', + 'do_classifier': ''' +Trove classifiers are optional identifiers that allow you to specify the +intended audience by saying things like "Beta software with a text UI +for Linux under the PSF license. However, this can be a somewhat involved +process. +''', + 'packages': ''' +You can provide a package name contained in your project. +''', + 'modules': ''' +You can provide a python module contained in your project. +''', + 'extra_files': ''' +You can provide extra files/dirs contained in your project. +It has to follow the template syntax. XXX add help here. +''', + + 'home_page': ''' +The home page for the project, typically starting with "http://". +''', + 'trove_license': ''' +Optionally you can specify a license. Type a string that identifies a common +license, and then you can select a list of license specifiers. +''', + 'trove_generic': ''' +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", +''', +} + +PROJECT_MATURITY = ['Development Status :: 1 - Planning', + 'Development Status :: 2 - Pre-Alpha', + 'Development Status :: 3 - Alpha', + 'Development Status :: 4 - Beta', + 'Development Status :: 5 - Production/Stable', + 'Development Status :: 6 - Mature', + 'Development Status :: 7 - Inactive'] + +# XXX everything needs docstrings and tests (both low-level tests of various +# methods and functional tests of running the script) + + +def load_setup(): + """run the setup script (i.e the setup.py file) + + This function load the setup file in all cases (even if it have already + been loaded before, because we are monkey patching its setup function with + a particular one""" + with open("setup.py") as f: + imp.load_module("setup", f, "setup.py", (".py", "r", imp.PY_SOURCE)) + + +def ask_yn(question, default=None, helptext=None): + question += ' (y/n)' + while True: + answer = ask(question, default, helptext, required=True) + if answer and answer[0].lower() in 'yn': + return answer[0].lower() + + print('\nERROR: You must select "Y" or "N".\n') + + +def ask(question, default=None, helptext=None, required=True, + lengthy=False, multiline=False): + prompt = '%s: ' % (question,) + if default: + prompt = '%s [%s]: ' % (question, default) + if default and len(question) + len(default) > 70: + prompt = '%s\n [%s]: ' % (question, default) + if lengthy or multiline: + prompt += '\n > ' + + if not helptext: + helptext = 'No additional help available.' + + helptext = helptext.strip("\n") + + while True: + sys.stdout.write(prompt) + sys.stdout.flush() + + line = sys.stdin.readline().strip() + if line == '?': + print('=' * 70) + print(helptext) + print('=' * 70) + continue + if default and not line: + return default + if not line and required: + print('*' * 70) + print('This value cannot be empty.') + print('===========================') + if helptext: + print(helptext) + print('*' * 70) + continue + return line + + +def convert_yn_to_bool(yn, yes=True, no=False): + """Convert a y/yes or n/no to a boolean value.""" + if yn.lower().startswith('y'): + return yes + else: + return no + + +def _build_classifiers_dict(classifiers): + d = {} + for key in classifiers: + subDict = d + for subkey in key.split(' :: '): + if not subkey in subDict: + subDict[subkey] = {} + subDict = subDict[subkey] + return d + +CLASSIFIERS = _build_classifiers_dict(_CLASSIFIERS_LIST) + + +def _build_licences(classifiers): + res = [] + for index, item in enumerate(classifiers): + if not item.startswith('License :: '): + continue + res.append((index, item.split(' :: ')[-1].lower())) + return res + +LICENCES = _build_licences(_CLASSIFIERS_LIST) + + +class MainProgram: + """Make a project setup configuration file (setup.cfg).""" + + def __init__(self): + self.configparser = None + self.classifiers = set() + self.data = {'name': '', + 'version': '1.0.0', + 'classifier': self.classifiers, + 'packages': [], + 'modules': [], + 'platform': [], + 'resources': [], + 'extra_files': [], + 'scripts': [], + } + self._load_defaults() + + def __call__(self): + setupcfg_defined = False + if self.has_setup_py() and self._prompt_user_for_conversion(): + setupcfg_defined = self.convert_py_to_cfg() + if not setupcfg_defined: + self.define_cfg_values() + self._write_cfg() + + def has_setup_py(self): + """Test for the existance of a setup.py file.""" + return os.path.exists('setup.py') + + def define_cfg_values(self): + self.inspect() + self.query_user() + + def _lookup_option(self, key): + if not self.configparser.has_option('DEFAULT', key): + return None + return self.configparser.get('DEFAULT', key) + + def _load_defaults(self): + # Load default values from a user configuration file + self.configparser = RawConfigParser() + # TODO replace with section in distutils config file + default_cfg = os.path.expanduser(os.path.join('~', _DEFAULT_CFG)) + self.configparser.read(default_cfg) + self.data['author'] = self._lookup_option('author') + self.data['author_email'] = self._lookup_option('author_email') + + def _prompt_user_for_conversion(self): + # Prompt the user about whether they would like to use the setup.py + # conversion utility to generate a setup.cfg or generate the setup.cfg + # from scratch + answer = ask_yn(('A legacy setup.py has been found.\n' + 'Would you like to convert it to a setup.cfg?'), + default="y", + helptext=_helptext['setup.py found']) + return convert_yn_to_bool(answer) + + def _dotted_packages(self, data): + packages = sorted(data) + modified_pkgs = [] + for pkg in packages: + pkg = pkg.lstrip('./') + pkg = pkg.replace('/', '.') + modified_pkgs.append(pkg) + return modified_pkgs + + def _write_cfg(self): + if os.path.exists(_FILENAME): + if os.path.exists('%s.old' % _FILENAME): + print("ERROR: %(name)s.old backup exists, please check that " + "current %(name)s is correct and remove %(name)s.old" % + {'name': _FILENAME}) + return + shutil.move(_FILENAME, '%s.old' % _FILENAME) + + with open(_FILENAME, 'w') as fp: + fp.write('[metadata]\n') + # 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 + 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('\nresources =\n') + for src, dest in self.data['resources']: + fp.write(' %s = %s\n' % (src, dest)) + fp.write('\n') + + os.chmod(_FILENAME, 0o644) + print('Wrote "%s".' % _FILENAME) + + def convert_py_to_cfg(self): + """Generate a setup.cfg from an existing setup.py. + + It only exports the distutils metadata (setuptools specific metadata + is not currently supported). + """ + data = self.data + + def setup_mock(**attrs): + """Mock the setup(**attrs) in order to retrieve 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. retrieve metadata fields that are quite similar in + # PEP 314 and PEP 345 + 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'), + # backport only for 2.5+ + ('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. retrieve data that requires special processing + 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 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 = list(sysconfig.get_paths(vars=vars).items()) + + def length_comparison(x, y): + len_x = len(x[1]) + len_y = len(y[1]) + if len_x == len_y: + return 0 + elif len_x < len_y: + return -1 + else: + return 1 + + # sort tokens to use the longest one first + path_tokens.sort(key=cmp_to_key(length_comparison)) + 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 iter(dist.package_data.items()) or []: + package_dir = package_dirs.get(package, package) + files = [os.path.join(package_dir, f) for f in extras] + data['extra_files'].extend(files) + + # Use README file if its content is the desciption + if "description" in data: + ref = md5(re.sub('\s', '', + self.data['description']).lower().encode()) + ref = ref.digest() + for readme in glob.glob('README*'): + with open(readme) as fp: + contents = fp.read() + val = md5(re.sub('\s', '', + contents.lower()).encode()).digest() + if val == ref: + del data['description'] + data['description-file'] = readme + break + + # apply monkey patch to distutils (v1) and setuptools (if needed) + # (abort the feature if distutils v1 has been killed) + try: + from distutils import core + core.setup # make sure it's not d2 maskerading as d1 + except (ImportError, AttributeError): + return + saved_setups = [(core, core.setup)] + core.setup = setup_mock + try: + import setuptools + except ImportError: + pass + else: + saved_setups.append((setuptools, setuptools.setup)) + setuptools.setup = setup_mock + # get metadata by executing the setup.py with the patched setup(...) + success = False # for python < 2.4 + try: + load_setup() + 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): + with open(path, 'r') as fp: + for _ in range(10): + line = fp.readline() + m = re.match(r'^#!.*python((?P\d)(\.\d+)?)?$', line) + if m: + if m.group('major') == '3': + self.classifiers.add( + 'Programming Language :: Python :: 3') + else: + self.classifiers.add( + 'Programming Language :: Python :: 2') + + def inspect(self): + """Inspect the current working diretory for a name and version. + + This information is harvested in where the directory is named + like [name]-[version]. + """ + dir_name = os.path.basename(os.getcwd()) + self.data['name'] = dir_name + match = re.match(r'(.*)-(\d.+)', dir_name) + if match: + self.data['name'] = match.group(1) + self.data['version'] = match.group(2) + # TODO Needs tested! + if not is_valid_version(self.data['version']): + msg = "Invalid version discovered: %s" % self.data['version'] + raise RuntimeError(msg) + + def query_user(self): + self.data['name'] = ask('Project name', self.data['name'], + _helptext['name']) + + self.data['version'] = ask('Current version number', + self.data.get('version'), _helptext['version']) + self.data['summary'] = ask('Package summary', + self.data.get('summary'), _helptext['summary'], + lengthy=True) + self.data['author'] = ask('Author name', + self.data.get('author'), _helptext['author']) + self.data['author_email'] = ask('Author e-mail address', + self.data.get('author_email'), _helptext['author_email']) + self.data['home_page'] = ask('Project Home Page', + self.data.get('home_page'), _helptext['home_page'], + required=False) + + if ask_yn('Do you want me to automatically build the file list ' + 'with everything I can find in the current directory ? ' + 'If you say no, you will have to define them manually.') == 'y': + self._find_files() + else: + while ask_yn('Do you want to add a single module ?' + ' (you will be able to add full packages next)', + helptext=_helptext['modules']) == 'y': + self._set_multi('Module name', 'modules') + + while ask_yn('Do you want to add a package ?', + helptext=_helptext['packages']) == 'y': + self._set_multi('Package name', 'packages') + + while ask_yn('Do you want to add an extra file ?', + helptext=_helptext['extra_files']) == 'y': + self._set_multi('Extra file/dir name', 'extra_files') + + if ask_yn('Do you want to set Trove classifiers?', + helptext=_helptext['do_classifier']) == 'y': + self.set_classifier() + + def _find_files(self): + # we are looking for python modules and packages, + # other stuff are added as regular files + pkgs = self.data['packages'] + modules = self.data['modules'] + extra_files = self.data['extra_files'] + + def is_package(path): + return os.path.exists(os.path.join(path, '__init__.py')) + + curdir = os.getcwd() + scanned = [] + _pref = ['lib', 'include', 'dist', 'build', '.', '~'] + _suf = ['.pyc'] + + def to_skip(path): + path = relative(path) + + for pref in _pref: + if path.startswith(pref): + return True + + for suf in _suf: + if path.endswith(suf): + return True + + return False + + def relative(path): + return path[len(curdir) + 1:] + + def dotted(path): + res = relative(path).replace(os.path.sep, '.') + if res.endswith('.py'): + res = res[:-len('.py')] + return res + + # first pass: packages + for root, dirs, files in os.walk(curdir): + if to_skip(root): + continue + for dir_ in sorted(dirs): + if to_skip(dir_): + continue + fullpath = os.path.join(root, dir_) + dotted_name = dotted(fullpath) + if is_package(fullpath) and dotted_name not in pkgs: + pkgs.append(dotted_name) + scanned.append(fullpath) + + # modules and extra files + for root, dirs, files in os.walk(curdir): + if to_skip(root): + continue + + if any(root.startswith(path) for path in scanned): + continue + + for file in sorted(files): + fullpath = os.path.join(root, file) + if to_skip(fullpath): + continue + # single module? + if os.path.splitext(file)[-1] == '.py': + modules.append(dotted(fullpath)) + else: + extra_files.append(relative(fullpath)) + + def _set_multi(self, question, name): + existing_values = self.data[name] + value = ask(question, helptext=_helptext[name]).strip() + if value not in existing_values: + existing_values.append(value) + + def set_classifier(self): + self.set_maturity_status(self.classifiers) + self.set_license(self.classifiers) + self.set_other_classifier(self.classifiers) + + def set_other_classifier(self, classifiers): + if ask_yn('Do you want to set other trove identifiers', 'n', + _helptext['trove_generic']) != 'y': + return + self.walk_classifiers(classifiers, [CLASSIFIERS], '') + + def walk_classifiers(self, classifiers, trovepath, desc): + trove = trovepath[-1] + + if not trove: + return + + for key in sorted(trove): + if len(trove[key]) == 0: + if ask_yn('Add "%s"' % desc[4:] + ' :: ' + key, 'n') == 'y': + classifiers.add(desc[4:] + ' :: ' + key) + continue + + if ask_yn('Do you want to set items under\n "%s" (%d sub-items)' + % (key, len(trove[key])), 'n', + _helptext['trove_generic']) == 'y': + self.walk_classifiers(classifiers, trovepath + [trove[key]], + desc + ' :: ' + key) + + def set_license(self, classifiers): + while True: + license = ask('What license do you use', + helptext=_helptext['trove_license'], required=False) + if not license: + return + + license_words = license.lower().split(' ') + found_list = [] + + for index, licence in LICENCES: + for word in license_words: + if word in licence: + found_list.append(index) + break + + if len(found_list) == 0: + print('ERROR: Could not find a matching license for "%s"' % + license) + continue + + question = 'Matching licenses:\n\n' + + for index, list_index in enumerate(found_list): + question += ' %s) %s\n' % (index + 1, + _CLASSIFIERS_LIST[list_index]) + + question += ('\nType the number of the license you wish to use or ' + '? to try again:') + choice = ask(question, required=False) + + if choice == '?': + continue + if choice == '': + return + + try: + index = found_list[int(choice) - 1] + except ValueError: + print("ERROR: Invalid selection, type a number from the list " + "above.") + + classifiers.add(_CLASSIFIERS_LIST[index]) + + def set_maturity_status(self, classifiers): + maturity_name = lambda mat: mat.split('- ')[-1] + maturity_question = '''\ + Please select the project status: + + %s + + Status''' % '\n'.join('%s - %s' % (i, maturity_name(n)) + for i, n in enumerate(PROJECT_MATURITY)) + while True: + choice = ask(dedent(maturity_question), required=False) + + if choice: + try: + choice = int(choice) - 1 + key = PROJECT_MATURITY[choice] + classifiers.add(key) + return + except (IndexError, ValueError): + print("ERROR: Invalid selection, type a single digit " + "number.") + + +def main(): + """Main entry point.""" + program = MainProgram() + # # uncomment when implemented + # if not program.load_existing_setup_script(): + # program.inspect_directory() + # program.query_user() + # program.update_config_file() + # program.write_setup_script() + # packaging.util.cfg_to_args() + program() + + +if __name__ == '__main__': + main() diff --git a/Lib/packaging/database.py b/Lib/packaging/database.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/database.py @@ -0,0 +1,627 @@ +"""PEP 376 implementation.""" + +import io +import os +import re +import csv +import sys +import zipimport +from hashlib import md5 +from packaging import logger +from packaging.errors import PackagingError +from packaging.version import suggest_normalized_version, VersionPredicate +from packaging.metadata import Metadata + + +__all__ = [ + 'Distribution', 'EggInfoDistribution', 'distinfo_dirname', + 'get_distributions', 'get_distribution', 'get_file_users', + 'provides_distribution', 'obsoletes_distribution', + 'enable_cache', 'disable_cache', 'clear_cache', +] + + +# TODO update docs + +DIST_FILES = ('INSTALLER', 'METADATA', 'RECORD', 'REQUESTED', 'RESOURCES') + +# 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_enabled = True + + +def enable_cache(): + """ + Enables the internal cache. + + Note that this function will not clear the cache in any case, for that + functionality see :func:`clear_cache`. + """ + global _cache_enabled + + _cache_enabled = True + + +def disable_cache(): + """ + Disables the internal cache. + + Note that this function will not clear the cache in any case, for that + functionality see :func:`clear_cache`. + """ + global _cache_enabled + + _cache_enabled = False + + +def clear_cache(): + """ Clears the internal cache. """ + global _cache_name, _cache_name_egg, _cache_path, _cache_path_egg, \ + _cache_generated, _cache_generated_egg + + _cache_name = {} + _cache_name_egg = {} + _cache_path = {} + _cache_path_egg = {} + _cache_generated = False + _cache_generated_egg = False + + +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 paths: + realpath = os.path.realpath(path) + if not os.path.isdir(realpath): + continue + for dir in os.listdir(realpath): + dist_path = os.path.join(realpath, dir) + if include_dist and dir.endswith('.dist-info'): + yield Distribution(dist_path) + elif include_egg and (dir.endswith('.egg-info') or + dir.endswith('.egg')): + yield EggInfoDistribution(dist_path) + + +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): + return + else: + gen_dist = not _cache_generated + gen_egg = use_egg_info + + 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: + _cache_name[dist.name] = [] + _cache_name[dist.name].append(dist) + else: + _cache_path_egg[dist.path] = dist + if not dist.name in _cache_name_egg: + _cache_name_egg[dist.name] = [] + _cache_name_egg[dist.name].append(dist) + + if gen_dist: + _cache_generated = True + if gen_egg: + _cache_generated_egg = True + + +class Distribution: + """Created with the *path* of the ``.dist-info`` directory provided to the + constructor. It reads the metadata contained in ``METADATA`` when it is + instantiated.""" + + name = '' + """The name of the distribution.""" + + version = '' + """The version of the distribution.""" + + metadata = None + """A :class:`packaging.metadata.Metadata` instance loaded with + the distribution's ``METADATA`` file.""" + + requested = False + """A boolean that indicates whether the ``REQUESTED`` metadata file is + present (in other words, whether the package was installed by user + request or it was installed as a dependency).""" + + def __init__(self, path): + if _cache_enabled and path in _cache_path: + self.metadata = _cache_path[path].metadata + else: + metadata_path = os.path.join(path, 'METADATA') + self.metadata = Metadata(path=metadata_path) + + self.name = self.metadata['Name'] + self.version = self.metadata['Version'] + self.path = path + + if _cache_enabled and not path in _cache_path: + _cache_path[path] = self + + def __repr__(self): + return '' % ( + self.name, self.version, self.path) + + def _get_records(self, local=False): + with self.get_distinfo_file('RECORD') as record: + record_reader = csv.reader(record, delimiter=',') + # XXX needs an explaining comment + for row in record_reader: + path, checksum, size = (row[:] + + [None for i in range(len(row), 3)]) + if local: + path = path.replace('/', os.sep) + path = os.path.join(sys.prefix, path) + yield path, checksum, size + + def get_resource_path(self, relative_path): + with self.get_distinfo_file('RESOURCES') as resources_file: + resources_reader = csv.reader(resources_file, delimiter=',') + for relative, destination in resources_reader: + if relative == relative_path: + return destination + raise KeyError( + 'no resource file with relative path %r is installed' % + relative_path) + + def list_installed_files(self, local=False): + """ + Iterates over the ``RECORD`` entries and returns a tuple + ``(path, md5, size)`` for each line. If *local* is ``True``, + the returned path is transformed into a local absolute path. + Otherwise the raw value from RECORD is returned. + + A local absolute path is an absolute path in which occurrences of + ``'/'`` have been replaced by the system separator given by ``os.sep``. + + :parameter local: flag to say if the path should be returned a local + absolute path + + :type local: boolean + :returns: iterator of (path, md5, size) + """ + return self._get_records(local) + + def uses(self, path): + """ + Returns ``True`` if path is listed in ``RECORD``. *path* can be a local + absolute path or a relative ``'/'``-separated path. + + :rtype: boolean + """ + for p, checksum, size in self._get_records(): + local_absolute = os.path.join(sys.prefix, p) + if path == p or path == local_absolute: + return True + return False + + def get_distinfo_file(self, path, binary=False): + """ + Returns a file located under the ``.dist-info`` directory. Returns a + ``file`` instance for the file pointed by *path*. + + :parameter path: a ``'/'``-separated path relative to the + ``.dist-info`` directory or an absolute path; + If *path* is an absolute path and doesn't start + with the ``.dist-info`` directory path, + a :class:`PackagingError` is raised + :type path: string + :parameter binary: If *binary* is ``True``, opens the file in read-only + binary mode (``rb``), otherwise opens it in + read-only mode (``r``). + :rtype: file object + """ + open_flags = 'r' + if binary: + open_flags += 'b' + + # Check if it is an absolute path # XXX use relpath, add tests + if path.find(os.sep) >= 0: + # it's an absolute path? + distinfo_dirname, path = path.split(os.sep)[-2:] + if distinfo_dirname != self.path.split(os.sep)[-1]: + raise PackagingError( + 'dist-info file %r does not belong to the %r %s ' + 'distribution' % (path, self.name, self.version)) + + # The file must be relative + if path not in DIST_FILES: + raise PackagingError('invalid path for a dist-info file: %r' % + path) + + path = os.path.join(self.path, path) + return open(path, open_flags) + + def list_distinfo_files(self, local=False): + """ + Iterates over the ``RECORD`` entries and returns paths for each line if + the path is pointing to a file located in the ``.dist-info`` directory + or one of its subdirectories. + + :parameter local: If *local* is ``True``, each returned path is + transformed into a local absolute path. Otherwise the + raw value from ``RECORD`` is returned. + :type local: boolean + :returns: iterator of paths + """ + for path, checksum, size in self._get_records(local): + yield path + + def __eq__(self, other): + return isinstance(other, Distribution) and self.path == other.path + + # See http://docs.python.org/reference/datamodel#object.__hash__ + __hash__ = object.__hash__ + + +class EggInfoDistribution: + """Created with the *path* of the ``.egg-info`` directory or file provided + to the constructor. It reads the metadata contained in the file itself, or + if the given path happens to be a directory, the metadata is read from the + file ``PKG-INFO`` under that directory.""" + + name = '' + """The name of the distribution.""" + + version = '' + """The version of the distribution.""" + + metadata = None + """A :class:`packaging.metadata.Metadata` instance loaded with + the distribution's ``METADATA`` file.""" + + _REQUIREMENT = re.compile( + r'(?P[-A-Za-z0-9_.]+)\s*' + r'(?P(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)?\s*' + r'(?P(?:\s*,\s*(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)*)\s*' + r'(?P\[.*\])?') + + def __init__(self, path): + self.path = path + if _cache_enabled and path in _cache_path_egg: + self.metadata = _cache_path_egg[path].metadata + self.name = self.metadata['Name'] + self.version = self.metadata['Version'] + return + + # reused from Distribute's pkg_resources + def yield_lines(strs): + """Yield non-empty/non-comment lines of a ``basestring`` + or sequence""" + if isinstance(strs, str): + for s in strs.splitlines(): + s = s.strip() + # skip blank lines/comments + if s and not s.startswith('#'): + yield s + else: + for ss in strs: + for s in yield_lines(ss): + yield s + + requires = None + + if path.endswith('.egg'): + if os.path.isdir(path): + meta_path = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + self.metadata = Metadata(path=meta_path) + try: + req_path = os.path.join(path, 'EGG-INFO', 'requires.txt') + with open(req_path, 'r') as fp: + requires = fp.read() + except IOError: + requires = None + else: + # FIXME handle the case where zipfile is not available + zipf = zipimport.zipimporter(path) + fileobj = io.StringIO( + zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8')) + self.metadata = Metadata(fileobj=fileobj) + try: + requires = zipf.get_data('EGG-INFO/requires.txt') + except IOError: + requires = None + self.name = self.metadata['Name'] + self.version = self.metadata['Version'] + + elif path.endswith('.egg-info'): + if os.path.isdir(path): + path = os.path.join(path, 'PKG-INFO') + try: + with open(os.path.join(path, 'requires.txt'), 'r') as fp: + requires = fp.read() + except IOError: + requires = None + self.metadata = Metadata(path=path) + self.name = self.metadata['name'] + self.version = self.metadata['Version'] + + else: + raise ValueError('path must end with .egg-info or .egg, got %r' % + path) + + if requires is not None: + if self.metadata['Metadata-Version'] == '1.1': + # we can't have 1.1 metadata *and* Setuptools requires + for field in ('Obsoletes', 'Requires', 'Provides'): + del self.metadata[field] + + reqs = [] + + if requires is not None: + for line in yield_lines(requires): + if line.startswith('['): + logger.warning( + 'extensions in requires.txt are not supported ' + '(used by %r %s)', self.name, self.version) + break + else: + match = self._REQUIREMENT.match(line.strip()) + if not match: + # this happens when we encounter extras; since they + # are written at the end of the file we just exit + break + else: + if match.group('extras'): + msg = ('extra requirements are not supported ' + '(used by %r %s)', self.name, self.version) + logger.warning(msg, self.name) + name = match.group('name') + version = None + if match.group('first'): + version = match.group('first') + if match.group('rest'): + version += match.group('rest') + version = version.replace(' ', '') # trim spaces + if version is None: + reqs.append(name) + else: + reqs.append('%s (%s)' % (name, version)) + + if len(reqs) > 0: + self.metadata['Requires-Dist'] += reqs + + if _cache_enabled: + _cache_path_egg[self.path] = self + + def __repr__(self): + return '' % ( + self.name, self.version, self.path) + + def list_installed_files(self, local=False): + + def _md5(path): + with open(path, 'rb') as f: + content = f.read() + 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): + return False + + def __eq__(self, other): + return (isinstance(other, EggInfoDistribution) and + self.path == other.path) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + __hash__ = object.__hash__ + + +def distinfo_dirname(name, version): + """ + The *name* and *version* parameters are converted into their + filename-escaped form, i.e. any ``'-'`` characters are replaced + with ``'_'`` other than the one in ``'dist-info'`` and the one + separating the name from the version number. + + :parameter name: is converted to a standard distribution name by replacing + any runs of non- alphanumeric characters with a single + ``'-'``. + :type name: string + :parameter version: is converted to a standard version string. Spaces + become dots, and all other non-alphanumeric characters + (except dots) become dashes, with runs of multiple + dashes condensed to a single dash. + :type version: string + :returns: directory name + :rtype: string""" + file_extension = '.dist-info' + 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 + if normalized_version is None: + # Unable to achieve normality? + normalized_version = version + return '-'.join([name, normalized_version]) + file_extension + + +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 + them. If the parameters *use_egg_info* is ``True``, then the ``.egg-info`` + files and directores are iterated as well. + + :rtype: iterator of :class:`Distribution` and :class:`EggInfoDistribution` + instances + """ + if not _cache_enabled: + for dist in _yield_distributions(True, use_egg_info, paths): + yield dist + else: + _generate_cache(use_egg_info, paths) + + for dist in _cache_path.values(): + yield dist + + if use_egg_info: + for dist in _cache_path_egg.values(): + yield dist + + +def get_distribution(name, use_egg_info=False, paths=None): + """ + Scans all elements in ``sys.path`` and looks for all directories + ending with ``.dist-info``. Returns a :class:`Distribution` + corresponding to the ``.dist-info`` directory that contains the + ``METADATA`` that matches *name* for the *name* metadata field. + If no distribution exists with the given *name* and the parameter + *use_egg_info* is set to ``True``, then all files and directories ending + with ``.egg-info`` are scanned. A :class:`EggInfoDistribution` instance is + returned if one is found that has metadata that matches *name* for the + *name* metadata field. + + This function only returns the first result found, as no more than one + value is expected. If the directory is not found, ``None`` is returned. + + :rtype: :class:`Distribution` or :class:`EggInfoDistribution` or None + """ + if paths == None: + paths = sys.path + + if not _cache_enabled: + for dist in _yield_distributions(True, use_egg_info, paths): + if dist.name == name: + return dist + else: + _generate_cache(use_egg_info, paths) + + if name in _cache_name: + return _cache_name[name][0] + elif use_egg_info and name in _cache_name_egg: + return _cache_name_egg[name][0] + else: + return None + + +def obsoletes_distribution(name, version=None, use_egg_info=False): + """ + Iterates over all distributions to find which distributions obsolete + *name*. + + If a *version* is provided, it will be used to filter the results. + If the argument *use_egg_info* is set to ``True``, then ``.egg-info`` + distributions will be considered as well. + + :type name: string + :type version: string + :parameter name: + """ + for dist in get_distributions(use_egg_info): + obsoleted = (dist.metadata['Obsoletes-Dist'] + + dist.metadata['Obsoletes']) + for obs in obsoleted: + o_components = obs.split(' ', 1) + if len(o_components) == 1 or version is None: + if name == o_components[0]: + yield dist + break + else: + try: + predicate = VersionPredicate(obs) + except ValueError: + raise PackagingError( + 'distribution %r has ill-formed obsoletes field: ' + '%r' % (dist.name, obs)) + if name == o_components[0] and predicate.match(version): + yield dist + break + + +def provides_distribution(name, version=None, use_egg_info=False): + """ + Iterates over all distributions to find which distributions provide *name*. + If a *version* is provided, it will be used to filter the results. Scans + all elements in ``sys.path`` and looks for all directories ending with + ``.dist-info``. Returns a :class:`Distribution` corresponding to the + ``.dist-info`` directory that contains a ``METADATA`` that matches *name* + for the name metadata. If the argument *use_egg_info* is set to ``True``, + then all files and directories ending with ``.egg-info`` are considered + as well and returns an :class:`EggInfoDistribution` instance. + + This function only returns the first result found, since no more than + one values are expected. If the directory is not found, returns ``None``. + + :parameter version: a version specifier that indicates the version + required, conforming to the format in ``PEP-345`` + + :type name: string + :type version: string + """ + predicate = None + if not version is None: + try: + predicate = VersionPredicate(name + ' (' + version + ')') + except ValueError: + raise PackagingError('invalid name or version: %r, %r' % + (name, version)) + + for dist in get_distributions(use_egg_info): + provided = dist.metadata['Provides-Dist'] + dist.metadata['Provides'] + + for p in provided: + p_components = p.rsplit(' ', 1) + if len(p_components) == 1 or predicate is None: + if name == p_components[0]: + yield dist + break + else: + p_name, p_ver = p_components + if len(p_ver) < 2 or p_ver[0] != '(' or p_ver[-1] != ')': + raise PackagingError( + 'distribution %r has invalid Provides field: %r' % + (dist.name, p)) + p_ver = p_ver[1:-1] # trim off the parenthesis + if p_name == name and predicate.match(p_ver): + yield dist + break + + +def get_file_users(path): + """ + Iterates over all distributions to find out which distributions use + *path*. + + :parameter path: can be a local absolute path or a relative + ``'/'``-separated path. + :type path: string + :rtype: iterator of :class:`Distribution` instances + """ + for dist in get_distributions(): + if dist.uses(path): + yield dist diff --git a/Lib/packaging/depgraph.py b/Lib/packaging/depgraph.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/depgraph.py @@ -0,0 +1,270 @@ +"""Class and functions dealing with dependencies between distributions. + +This module provides a DependencyGraph class to represent the +dependencies between distributions. Auxiliary functions can generate a +graph, find reverse dependencies, and print a graph in DOT format. +""" + +import sys + +from io import StringIO +from packaging.errors import PackagingError +from packaging.version import VersionPredicate, IrrationalVersionError + +__all__ = ['DependencyGraph', 'generate_graph', 'dependent_dists', + 'graph_to_dot'] + + +class DependencyGraph: + """ + Represents a dependency graph between distributions. + + The dependency relationships are stored in an ``adjacency_list`` that maps + distributions to a list of ``(other, label)`` tuples where ``other`` + is a distribution and the edge is labeled with ``label`` (i.e. the version + specifier, if such was provided). Also, for more efficient traversal, for + every distribution ``x``, a list of predecessors is kept in + ``reverse_list[x]``. An edge from distribution ``a`` to + distribution ``b`` means that ``a`` depends on ``b``. If any missing + dependencies are found, they are stored in ``missing``, which is a + dictionary that maps distributions to a list of requirements that were not + provided by any other distributions. + """ + + def __init__(self): + self.adjacency_list = {} + self.reverse_list = {} + self.missing = {} + + def add_distribution(self, distribution): + """Add the *distribution* to the graph. + + :type distribution: :class:`packaging.database.Distribution` or + :class:`packaging.database.EggInfoDistribution` + """ + self.adjacency_list[distribution] = [] + self.reverse_list[distribution] = [] + self.missing[distribution] = [] + + def add_edge(self, x, y, label=None): + """Add an edge from distribution *x* to distribution *y* with the given + *label*. + + :type x: :class:`packaging.database.Distribution` or + :class:`packaging.database.EggInfoDistribution` + :type y: :class:`packaging.database.Distribution` or + :class:`packaging.database.EggInfoDistribution` + :type label: ``str`` or ``None`` + """ + self.adjacency_list[x].append((y, label)) + # multiple edges are allowed, so be careful + if not x in self.reverse_list[y]: + self.reverse_list[y].append(x) + + def add_missing(self, distribution, requirement): + """ + Add a missing *requirement* for the given *distribution*. + + :type distribution: :class:`packaging.database.Distribution` or + :class:`packaging.database.EggInfoDistribution` + :type requirement: ``str`` + """ + self.missing[distribution].append(requirement) + + def _repr_dist(self, dist): + return '%s %s' % (dist.name, dist.metadata['Version']) + + def repr_node(self, dist, level=1): + """Prints only a subgraph""" + output = [] + output.append(self._repr_dist(dist)) + for other, label in self.adjacency_list[dist]: + dist = self._repr_dist(other) + if label is not None: + dist = '%s [%s]' % (dist, label) + output.append(' ' * level + str(dist)) + suboutput = self.repr_node(other, level + 1) + subs = suboutput.split('\n') + output.extend(subs[1:]) + return '\n'.join(output) + + def __repr__(self): + """Representation of the graph""" + output = [] + for dist, adjs in self.adjacency_list.items(): + output.append(self.repr_node(dist)) + return '\n'.join(output) + + +def graph_to_dot(graph, f, skip_disconnected=True): + """Writes a DOT output for the graph to the provided file *f*. + + If *skip_disconnected* is set to ``True``, then all distributions + that are not dependent on any other distribution are skipped. + + :type f: has to support ``file``-like operations + :type skip_disconnected: ``bool`` + """ + disconnected = [] + + f.write("digraph dependencies {\n") + for dist, adjs in graph.adjacency_list.items(): + if len(adjs) == 0 and not skip_disconnected: + disconnected.append(dist) + for other, label in adjs: + if not label is None: + f.write('"%s" -> "%s" [label="%s"]\n' % + (dist.name, other.name, label)) + else: + f.write('"%s" -> "%s"\n' % (dist.name, other.name)) + if not skip_disconnected and len(disconnected) > 0: + f.write('subgraph disconnected {\n') + f.write('label = "Disconnected"\n') + f.write('bgcolor = red\n') + + for dist in disconnected: + f.write('"%s"' % dist.name) + f.write('\n') + f.write('}\n') + f.write('}\n') + + +def generate_graph(dists): + """Generates a dependency graph from the given distributions. + + :parameter dists: a list of distributions + :type dists: list of :class:`packaging.database.Distribution` and + :class:`packaging.database.EggInfoDistribution` instances + :rtype: a :class:`DependencyGraph` instance + """ + graph = DependencyGraph() + provided = {} # maps names to lists of (version, dist) tuples + + # first, build the graph and find out the provides + for dist in dists: + graph.add_distribution(dist) + provides = (dist.metadata['Provides-Dist'] + + dist.metadata['Provides'] + + ['%s (%s)' % (dist.name, dist.metadata['Version'])]) + + for p in provides: + comps = p.strip().rsplit(" ", 1) + name = comps[0] + version = None + if len(comps) == 2: + version = comps[1] + if len(version) < 3 or version[0] != '(' or version[-1] != ')': + raise PackagingError('Distribution %s has ill formed' \ + 'provides field: %s' % (dist.name, p)) + version = version[1:-1] # trim off parenthesis + if not name in provided: + provided[name] = [] + provided[name].append((version, dist)) + + # now make the edges + for dist in dists: + requires = dist.metadata['Requires-Dist'] + dist.metadata['Requires'] + for req in requires: + try: + predicate = VersionPredicate(req) + except IrrationalVersionError: + # XXX compat-mode if cannot read the version + name = req.split()[0] + predicate = VersionPredicate(name) + + name = predicate.name + + if not name in provided: + graph.add_missing(dist, req) + else: + matched = False + for version, provider in provided[name]: + try: + match = predicate.match(version) + except IrrationalVersionError: + # XXX small compat-mode + if version.split(' ') == 1: + match = True + else: + match = False + + if match: + graph.add_edge(dist, provider, req) + matched = True + break + if not matched: + graph.add_missing(dist, req) + return graph + + +def dependent_dists(dists, dist): + """Recursively generate a list of distributions from *dists* that are + dependent on *dist*. + + :param dists: a list of distributions + :param dist: a distribution, member of *dists* for which we are interested + """ + if not dist in dists: + raise ValueError('The given distribution is not a member of the list') + graph = generate_graph(dists) + + dep = [dist] # dependent distributions + fringe = graph.reverse_list[dist] # list of nodes we should inspect + + while not len(fringe) == 0: + node = fringe.pop() + dep.append(node) + for prev in graph.reverse_list[node]: + if not prev in dep: + fringe.append(prev) + + dep.pop(0) # remove dist from dep, was there to prevent infinite loops + return dep + + +def main(): + from packaging.database import get_distributions + tempout = StringIO() + try: + old = sys.stderr + sys.stderr = tempout + try: + dists = list(get_distributions(use_egg_info=True)) + graph = generate_graph(dists) + finally: + sys.stderr = old + except Exception as e: + tempout.seek(0) + tempout = tempout.read() + print('Could not generate the graph\n%s\n%s\n' % (tempout, e)) + sys.exit(1) + + for dist, reqs in graph.missing.items(): + if len(reqs) > 0: + print("Warning: Missing dependencies for %s:" % dist.name, + ", ".join(reqs)) + # XXX replace with argparse + if len(sys.argv) == 1: + print('Dependency graph:') + print(' ' + repr(graph).replace('\n', '\n ')) + sys.exit(0) + elif len(sys.argv) > 1 and sys.argv[1] in ('-d', '--dot'): + if len(sys.argv) > 2: + filename = sys.argv[2] + else: + filename = 'depgraph.dot' + + with open(filename, 'w') as f: + graph_to_dot(graph, f, True) + tempout.seek(0) + tempout = tempout.read() + print(tempout) + print('Dot file written at "%s"' % filename) + sys.exit(0) + else: + print('Supported option: -d [filename]') + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/Lib/packaging/dist.py b/Lib/packaging/dist.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/dist.py @@ -0,0 +1,819 @@ +"""Class representing the distribution being built/installed/etc.""" + +import os +import re + +from packaging.errors import (PackagingOptionError, PackagingArgError, + PackagingModuleError, PackagingClassError) +from packaging.fancy_getopt import FancyGetopt +from packaging.util import strtobool, resolve_name +from packaging import logger +from packaging.metadata import Metadata +from packaging.config import Config +from packaging.command import get_command_class, STANDARD_COMMANDS + +# Regex to define acceptable Packaging command names. This is not *quite* +# the same as a Python NAME -- I don't allow leading underscores. The fact +# that they're very similar is no coincidence; the default naming scheme is +# to look for a Python module named after the command. +command_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$') + +USAGE = """\ +usage: %(script)s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] + or: %(script)s --help [cmd1 cmd2 ...] + or: %(script)s --help-commands + or: %(script)s cmd --help +""" + + +def gen_usage(script_name): + script = os.path.basename(script_name) + return USAGE % {'script': script} + + +class Distribution: + """The core of the Packaging. Most of the work hiding behind 'setup' + is really done within a Distribution instance, which farms the work out + to the Packaging commands specified on the command line. + + Setup scripts will almost never instantiate Distribution directly, + unless the 'setup()' function is totally inadequate to their needs. + However, it is conceivable that a setup script might wish to subclass + Distribution for some specialized purpose, and then pass the subclass + to 'setup()' as the 'distclass' keyword argument. If so, it is + necessary to respect the expectations that 'setup' has of Distribution. + See the code for 'setup()', in run.py, for details. + """ + + # 'global_options' describes the command-line options that may be + # supplied to the setup script prior to any actual commands. + # Eg. "./setup.py -n" or "./setup.py --dry-run" both take advantage of + # these global options. This list should be kept to a bare minimum, + # since every global option is also valid as a command option -- and we + # don't want to pollute the commands with too many options that they + # have minimal control over. + global_options = [ + ('dry-run', 'n', "don't actually do anything"), + ('help', 'h', "show detailed help message"), + ('no-user-cfg', None, 'ignore pydistutils.cfg in your home directory'), + ] + + # 'common_usage' is a short (2-3 line) string describing the common + # usage of the setup script. + common_usage = """\ +Common commands: (see '--help-commands' for more) + + setup.py build will build the package underneath 'build/' + setup.py install will install the package +""" + + # options that are not propagated to the commands + display_options = [ + ('help-commands', None, + "list all available commands"), + ('name', None, + "print package name"), + ('version', 'V', + "print package version"), + ('fullname', None, + "print -"), + ('author', None, + "print the author's name"), + ('author-email', None, + "print the author's email address"), + ('maintainer', None, + "print the maintainer's name"), + ('maintainer-email', None, + "print the maintainer's email address"), + ('contact', None, + "print the maintainer's name if known, else the author's"), + ('contact-email', None, + "print the maintainer's email address if known, else the author's"), + ('url', None, + "print the URL for this package"), + ('license', None, + "print the license of the package"), + ('licence', None, + "alias for --license"), + ('description', None, + "print the package description"), + ('long-description', None, + "print the long package description"), + ('platforms', None, + "print the list of platforms"), + ('classifier', None, + "print the list of classifiers"), + ('keywords', None, + "print the list of keywords"), + ('provides', None, + "print the list of packages/modules provided"), + ('requires', None, + "print the list of packages/modules required"), + ('obsoletes', None, + "print the list of packages/modules made obsolete"), + ('use-2to3', None, + "use 2to3 to make source python 3.x compatible"), + ('convert-2to3-doctests', None, + "use 2to3 to convert doctests in seperate text files"), + ] + display_option_names = [x[0].replace('-', '_') for x in display_options] + + # negative options are options that exclude other options + negative_opt = {} + + # -- Creation/initialization methods ------------------------------- + def __init__(self, attrs=None): + """Construct a new Distribution instance: initialize all the + attributes of a Distribution, and then use 'attrs' (a dictionary + mapping attribute names to values) to assign some of those + attributes their "real" values. (Any attributes not mentioned in + 'attrs' will be assigned to some null value: 0, None, an empty list + or dictionary, etc.) Most importantly, initialize the + 'command_obj' attribute to the empty dictionary; this will be + filled in with real command objects by 'parse_command_line()'. + """ + + # Default values for our command-line options + self.dry_run = False + self.help = False + for attr in self.display_option_names: + setattr(self, attr, False) + + # Store the configuration + self.config = Config(self) + + # Store the distribution metadata (name, version, author, and so + # forth) in a separate object -- we're getting to have enough + # information here (and enough command-line options) that it's + # worth it. + self.metadata = Metadata() + + # 'cmdclass' maps command names to class objects, so we + # can 1) quickly figure out which class to instantiate when + # we need to create a new command object, and 2) have a way + # for the setup script to override command classes + self.cmdclass = {} + + # 'script_name' and 'script_args' are usually set to sys.argv[0] + # and sys.argv[1:], but they can be overridden when the caller is + # not necessarily a setup script run from the command line. + self.script_name = None + self.script_args = None + + # 'command_options' is where we store command options between + # parsing them (from config files, the command line, etc.) and when + # they are actually needed -- ie. when the command in question is + # instantiated. It is a dictionary of dictionaries of 2-tuples: + # command_options = { command_name : { option : (source, value) } } + self.command_options = {} + + # 'dist_files' is the list of (command, pyversion, file) that + # have been created by any dist commands run so far. This is + # filled regardless of whether the run is dry or not. pyversion + # gives sysconfig.get_python_version() if the dist file is + # specific to a Python version, 'any' if it is good for all + # Python versions on the target platform, and '' for a source + # file. pyversion should not be used to specify minimum or + # maximum required Python versions; use the metainfo for that + # instead. + self.dist_files = [] + + # These options are really the business of various commands, rather + # than of the Distribution itself. We provide aliases for them in + # Distribution as a convenience to the developer. + self.packages = [] + self.package_data = {} + self.package_dir = None + self.py_modules = [] + self.libraries = [] + self.headers = [] + self.ext_modules = [] + self.ext_package = None + self.include_dirs = [] + self.extra_path = None + self.scripts = [] + self.data_files = {} + self.password = '' + self.use_2to3 = False + self.convert_2to3_doctests = [] + self.extra_files = [] + + # And now initialize bookkeeping stuff that can't be supplied by + # the caller at all. 'command_obj' maps command names to + # Command instances -- that's how we enforce that every command + # class is a singleton. + self.command_obj = {} + + # 'have_run' maps command names to boolean values; it keeps track + # of whether we have actually run a particular command, to make it + # cheap to "run" a command whenever we think we might need to -- if + # it's already been done, no need for expensive filesystem + # operations, we just check the 'have_run' dictionary and carry on. + # It's only safe to query 'have_run' for a command class that has + # been instantiated -- a false value will be inserted when the + # command object is created, and replaced with a true value when + # the command is successfully run. Thus it's probably best to use + # '.get()' rather than a straight lookup. + self.have_run = {} + + # Now we'll use the attrs dictionary (ultimately, keyword args from + # the setup script) to possibly override any or all of these + # distribution options. + + if attrs is not None: + # Pull out the set of command options and work on them + # specifically. Note that this order guarantees that aliased + # command options will override any supplied redundantly + # through the general options dictionary. + options = attrs.get('options') + if options is not None: + del attrs['options'] + for command, cmd_options in options.items(): + opt_dict = self.get_option_dict(command) + for opt, val in cmd_options.items(): + opt_dict[opt] = ("setup script", val) + + # Now work on the rest of the attributes. Any attribute that's + # not already defined is invalid! + for key, val in attrs.items(): + if self.metadata.is_metadata_field(key): + self.metadata[key] = val + elif hasattr(self, key): + setattr(self, key, val) + else: + logger.warning( + 'unknown argument given to Distribution: %r', key) + + # no-user-cfg is handled before other command line args + # because other args override the config files, and this + # one is needed before we can load the config files. + # If attrs['script_args'] wasn't passed, assume false. + # + # This also make sure we just look at the global options + self.want_user_cfg = True + + if self.script_args is not None: + for arg in self.script_args: + if not arg.startswith('-'): + break + if arg == '--no-user-cfg': + self.want_user_cfg = False + break + + self.finalize_options() + + def get_option_dict(self, command): + """Get the option dictionary for a given command. If that + command's option dictionary hasn't been created yet, then create it + and return the new dictionary; otherwise, return the existing + option dictionary. + """ + d = self.command_options.get(command) + if d is None: + d = self.command_options[command] = {} + return d + + def get_fullname(self): + return self.metadata.get_fullname() + + def dump_option_dicts(self, header=None, commands=None, indent=""): + from pprint import pformat + + if commands is None: # dump all command option dicts + commands = sorted(self.command_options) + + if header is not None: + logger.info(indent + header) + indent = indent + " " + + if not commands: + logger.info(indent + "no commands known yet") + return + + for cmd_name in commands: + opt_dict = self.command_options.get(cmd_name) + if opt_dict is None: + logger.info(indent + "no option dict for %r command", + cmd_name) + else: + logger.info(indent + "option dict for %r command:", cmd_name) + out = pformat(opt_dict) + for line in out.split('\n'): + logger.info(indent + " " + line) + + # -- Config file finding/parsing methods --------------------------- + # XXX to be removed + def parse_config_files(self, filenames=None): + return self.config.parse_config_files(filenames) + + def find_config_files(self): + return self.config.find_config_files() + + # -- Command-line parsing methods ---------------------------------- + + def parse_command_line(self): + """Parse the setup script's command line, taken from the + 'script_args' instance attribute (which defaults to 'sys.argv[1:]' + -- see 'setup()' in run.py). This list is first processed for + "global options" -- options that set attributes of the Distribution + instance. Then, it is alternately scanned for Packaging commands + and options for that command. Each new command terminates the + options for the previous command. The allowed options for a + command are determined by the 'user_options' attribute of the + command class -- thus, we have to be able to load command classes + in order to parse the command line. Any error in that 'options' + attribute raises PackagingGetoptError; any error on the + command line raises PackagingArgError. If no Packaging commands + were found on the command line, raises PackagingArgError. Return + true if command line was successfully parsed and we should carry + on with executing commands; false if no errors but we shouldn't + execute commands (currently, this only happens if user asks for + help). + """ + # + # We now have enough information to show the Macintosh dialog + # that allows the user to interactively specify the "command line". + # + toplevel_options = self._get_toplevel_options() + + # We have to parse the command line a bit at a time -- global + # options, then the first command, then its options, and so on -- + # because each command will be handled by a different class, and + # the options that are valid for a particular class aren't known + # until we have loaded the command class, which doesn't happen + # until we know what the command is. + + self.commands = [] + parser = FancyGetopt(toplevel_options + self.display_options) + parser.set_negative_aliases(self.negative_opt) + parser.set_aliases({'licence': 'license'}) + args = parser.getopt(args=self.script_args, object=self) + option_order = parser.get_option_order() + + # for display options we return immediately + if self.handle_display_options(option_order): + return + + while args: + args = self._parse_command_opts(parser, args) + if args is None: # user asked for help (and got it) + return + + # Handle the cases of --help as a "global" option, ie. + # "setup.py --help" and "setup.py --help command ...". For the + # former, we show global options (--dry-run, etc.) + # and display-only options (--name, --version, etc.); for the + # latter, we omit the display-only options and show help for + # each command listed on the command line. + if self.help: + self._show_help(parser, + display_options=len(self.commands) == 0, + commands=self.commands) + return + + return 1 + + def _get_toplevel_options(self): + """Return the non-display options recognized at the top level. + + This includes options that are recognized *only* at the top + level as well as options recognized for commands. + """ + return self.global_options + + def _parse_command_opts(self, parser, args): + """Parse the command-line options for a single command. + 'parser' must be a FancyGetopt instance; 'args' must be the list + of arguments, starting with the current command (whose options + we are about to parse). Returns a new version of 'args' with + the next command at the front of the list; will be the empty + list if there are no more commands on the command line. Returns + None if the user asked for help on this command. + """ + # Pull the current command from the head of the command line + command = args[0] + if not command_re.match(command): + raise SystemExit("invalid command name %r" % command) + self.commands.append(command) + + # Dig up the command class that implements this command, so we + # 1) know that it's a valid command, and 2) know which options + # it takes. + try: + cmd_class = get_command_class(command) + except PackagingModuleError as msg: + raise PackagingArgError(msg) + + # XXX We want to push this in packaging.command + # + # Require that the command class be derived from Command -- want + # to be sure that the basic "command" interface is implemented. + for meth in ('initialize_options', 'finalize_options', 'run'): + if hasattr(cmd_class, meth): + continue + raise PackagingClassError( + 'command %r must implement %r' % (cmd_class, meth)) + + # Also make sure that the command object provides a list of its + # known options. + if not (hasattr(cmd_class, 'user_options') and + isinstance(cmd_class.user_options, list)): + raise PackagingClassError( + "command class %s must provide " + "'user_options' attribute (a list of tuples)" % cmd_class) + + # If the command class has a list of negative alias options, + # merge it in with the global negative aliases. + negative_opt = self.negative_opt + if hasattr(cmd_class, 'negative_opt'): + negative_opt = negative_opt.copy() + negative_opt.update(cmd_class.negative_opt) + + # Check for help_options in command class. They have a different + # format (tuple of four) so we need to preprocess them here. + if (hasattr(cmd_class, 'help_options') and + isinstance(cmd_class.help_options, list)): + help_options = cmd_class.help_options[:] + else: + help_options = [] + + # All commands support the global options too, just by adding + # in 'global_options'. + parser.set_option_table(self.global_options + + cmd_class.user_options + + help_options) + parser.set_negative_aliases(negative_opt) + args, opts = parser.getopt(args[1:]) + if hasattr(opts, 'help') and opts.help: + self._show_help(parser, display_options=False, + commands=[cmd_class]) + return + + if (hasattr(cmd_class, 'help_options') and + isinstance(cmd_class.help_options, list)): + help_option_found = False + for help_option, short, desc, func in cmd_class.help_options: + if hasattr(opts, help_option.replace('-', '_')): + help_option_found = True + if hasattr(func, '__call__'): + func() + else: + raise PackagingClassError( + "invalid help function %r for help option %r: " + "must be a callable object (function, etc.)" + % (func, help_option)) + + if help_option_found: + return + + # Put the options from the command line into their official + # holding pen, the 'command_options' dictionary. + opt_dict = self.get_option_dict(command) + for name, value in vars(opts).items(): + opt_dict[name] = ("command line", value) + + return args + + def finalize_options(self): + """Set final values for all the options on the Distribution + instance, analogous to the .finalize_options() method of Command + objects. + """ + if getattr(self, 'convert_2to3_doctests', None): + self.convert_2to3_doctests = [os.path.join(p) + for p in self.convert_2to3_doctests] + else: + self.convert_2to3_doctests = [] + + def _show_help(self, parser, global_options=True, display_options=True, + commands=[]): + """Show help for the setup script command line in the form of + several lists of command-line options. 'parser' should be a + FancyGetopt instance; do not expect it to be returned in the + same state, as its option table will be reset to make it + generate the correct help text. + + If 'global_options' is true, lists the global options: + --dry-run, etc. If 'display_options' is true, lists + the "display-only" options: --name, --version, etc. Finally, + lists per-command help for every command name or command class + in 'commands'. + """ + # late import because of mutual dependence between these modules + from packaging.command.cmd import Command + + if global_options: + if display_options: + options = self._get_toplevel_options() + else: + options = self.global_options + parser.set_option_table(options) + parser.print_help(self.common_usage + "\nGlobal options:") + print('') + + if display_options: + parser.set_option_table(self.display_options) + parser.print_help( + "Information display options (just display " + + "information, ignore any commands)") + print('') + + for command in self.commands: + if isinstance(command, type) and issubclass(command, Command): + cls = command + else: + cls = get_command_class(command) + if (hasattr(cls, 'help_options') and + isinstance(cls.help_options, list)): + parser.set_option_table(cls.user_options + cls.help_options) + else: + parser.set_option_table(cls.user_options) + parser.print_help("Options for %r command:" % cls.__name__) + print('') + + print(gen_usage(self.script_name)) + + def handle_display_options(self, option_order): + """If there were any non-global "display-only" options + (--help-commands or the metadata display options) on the command + line, display the requested info and return true; else return + false. + """ + # User just wants a list of commands -- we'll print it out and stop + # processing now (ie. if they ran "setup --help-commands foo bar", + # we ignore "foo bar"). + if self.help_commands: + self.print_commands() + print('') + print(gen_usage(self.script_name)) + return 1 + + # If user supplied any of the "display metadata" options, then + # display that metadata in the order in which the user supplied the + # metadata options. + any_display_options = False + is_display_option = set() + for option in self.display_options: + is_display_option.add(option[0]) + + for opt, val in option_order: + if val and opt in is_display_option: + opt = opt.replace('-', '_') + value = self.metadata[opt] + if opt in ('keywords', 'platform'): + print(','.join(value)) + elif opt in ('classifier', 'provides', 'requires', + 'obsoletes'): + print('\n'.join(value)) + else: + print(value) + any_display_options = True + + return any_display_options + + def print_command_list(self, commands, header, max_length): + """Print a subset of the list of all commands -- used by + 'print_commands()'. + """ + print(header + ":") + + for cmd in commands: + cls = self.cmdclass.get(cmd) or get_command_class(cmd) + description = getattr(cls, 'description', + '(no description available)') + + print(" %-*s %s" % (max_length, cmd, description)) + + def _get_command_groups(self): + """Helper function to retrieve all the command class names divided + into standard commands (listed in + packaging2.command.STANDARD_COMMANDS) and extra commands (given in + self.cmdclass and not standard commands). + """ + extra_commands = [cmd for cmd in self.cmdclass + if cmd not in STANDARD_COMMANDS] + return STANDARD_COMMANDS, extra_commands + + def print_commands(self): + """Print out a help message listing all available commands with a + description of each. The list is divided into standard commands + (listed in packaging2.command.STANDARD_COMMANDS) and extra commands + (given in self.cmdclass and not standard commands). The + descriptions come from the command class attribute + 'description'. + """ + std_commands, extra_commands = self._get_command_groups() + max_length = 0 + for cmd in (std_commands + extra_commands): + if len(cmd) > max_length: + max_length = len(cmd) + + self.print_command_list(std_commands, + "Standard commands", + max_length) + if extra_commands: + print() + self.print_command_list(extra_commands, + "Extra commands", + max_length) + + # -- Command class/object methods ---------------------------------- + + def get_command_obj(self, command, create=True): + """Return the command object for 'command'. Normally this object + is cached on a previous call to 'get_command_obj()'; if no command + object for 'command' is in the cache, then we either create and + return it (if 'create' is true) or return None. + """ + cmd_obj = self.command_obj.get(command) + if not cmd_obj and create: + logger.debug("Distribution.get_command_obj(): " \ + "creating %r command object", command) + + cls = get_command_class(command) + cmd_obj = self.command_obj[command] = cls(self) + self.have_run[command] = 0 + + # Set any options that were supplied in config files + # or on the command line. (NB. support for error + # reporting is lame here: any errors aren't reported + # until 'finalize_options()' is called, which means + # we won't report the source of the error.) + options = self.command_options.get(command) + if options: + self._set_command_options(cmd_obj, options) + + return cmd_obj + + def _set_command_options(self, command_obj, option_dict=None): + """Set the options for 'command_obj' from 'option_dict'. Basically + this means copying elements of a dictionary ('option_dict') to + attributes of an instance ('command'). + + 'command_obj' must be a Command instance. If 'option_dict' is not + supplied, uses the standard option dictionary for this command + (from 'self.command_options'). + """ + command_name = command_obj.get_command_name() + if option_dict is None: + option_dict = self.get_option_dict(command_name) + + logger.debug(" setting options for %r command:", command_name) + + for option, (source, value) in option_dict.items(): + logger.debug(" %s = %s (from %s)", option, value, source) + try: + bool_opts = [x.replace('-', '_') + for x in command_obj.boolean_options] + except AttributeError: + bool_opts = [] + try: + neg_opt = command_obj.negative_opt + except AttributeError: + neg_opt = {} + + try: + is_string = isinstance(value, str) + if option in neg_opt and is_string: + setattr(command_obj, neg_opt[option], not strtobool(value)) + elif option in bool_opts and is_string: + setattr(command_obj, option, strtobool(value)) + elif hasattr(command_obj, option): + setattr(command_obj, option, value) + else: + raise PackagingOptionError( + "error in %s: command %r has no such option %r" % + (source, command_name, option)) + except ValueError as msg: + raise PackagingOptionError(msg) + + def get_reinitialized_command(self, command, reinit_subcommands=False): + """Reinitializes a command to the state it was in when first + returned by 'get_command_obj()': ie., initialized but not yet + finalized. This provides the opportunity to sneak option + values in programmatically, overriding or supplementing + user-supplied values from the config files and command line. + You'll have to re-finalize the command object (by calling + 'finalize_options()' or 'ensure_finalized()') before using it for + real. + + 'command' should be a command name (string) or command object. If + 'reinit_subcommands' is true, also reinitializes the command's + sub-commands, as declared by the 'sub_commands' class attribute (if + it has one). See the "install_dist" command for an example. Only + reinitializes the sub-commands that actually matter, ie. those + whose test predicates return true. + + Returns the reinitialized command object. + """ + from packaging.command.cmd import Command + if not isinstance(command, Command): + command_name = command + command = self.get_command_obj(command_name) + else: + command_name = command.get_command_name() + + if not command.finalized: + return command + command.initialize_options() + self.have_run[command_name] = 0 + command.finalized = False + self._set_command_options(command) + + if reinit_subcommands: + for sub in command.get_sub_commands(): + self.get_reinitialized_command(sub, reinit_subcommands) + + return command + + # -- Methods that operate on the Distribution ---------------------- + + def run_commands(self): + """Run each command that was seen on the setup script command line. + Uses the list of commands found and cache of command objects + created by 'get_command_obj()'. + """ + for cmd in self.commands: + self.run_command(cmd) + + # -- Methods that operate on its Commands -------------------------- + + def run_command(self, command, options=None): + """Do whatever it takes to run a command (including nothing at all, + if the command has already been run). Specifically: if we have + already created and run the command named by 'command', return + silently without doing anything. If the command named by 'command' + doesn't even have a command object yet, create one. Then invoke + 'run()' on that command object (or an existing one). + """ + # Already been here, done that? then return silently. + if self.have_run.get(command): + return + + if options is not None: + self.command_options[command] = options + + cmd_obj = self.get_command_obj(command) + cmd_obj.ensure_finalized() + self.run_command_hooks(cmd_obj, 'pre_hook') + logger.info("running %s", command) + cmd_obj.run() + self.run_command_hooks(cmd_obj, 'post_hook') + self.have_run[command] = 1 + + def run_command_hooks(self, cmd_obj, hook_kind): + """Run hooks registered for that command and phase. + + *cmd_obj* is a finalized command object; *hook_kind* is either + 'pre_hook' or 'post_hook'. + """ + if hook_kind not in ('pre_hook', 'post_hook'): + raise ValueError('invalid hook kind: %r' % hook_kind) + + hooks = getattr(cmd_obj, hook_kind, None) + + if hooks is None: + return + + for hook in hooks.values(): + if isinstance(hook, str): + try: + hook_obj = resolve_name(hook) + except ImportError as e: + raise PackagingModuleError(e) + else: + hook_obj = hook + + if not hasattr(hook_obj, '__call__'): + raise PackagingOptionError('hook %r is not callable' % hook) + + logger.info('running %s %s for command %s', + hook_kind, hook, cmd_obj.get_command_name()) + hook_obj(cmd_obj) + + # -- Distribution query methods ------------------------------------ + def has_pure_modules(self): + return len(self.packages or self.py_modules or []) > 0 + + def has_ext_modules(self): + return self.ext_modules and len(self.ext_modules) > 0 + + def has_c_libraries(self): + return self.libraries and len(self.libraries) > 0 + + def has_modules(self): + return self.has_pure_modules() or self.has_ext_modules() + + def has_headers(self): + return self.headers and len(self.headers) > 0 + + def has_scripts(self): + return self.scripts and len(self.scripts) > 0 + + def has_data_files(self): + return self.data_files and len(self.data_files) > 0 + + def is_pure(self): + return (self.has_pure_modules() and + not self.has_ext_modules() and + not self.has_c_libraries()) diff --git a/Lib/packaging/errors.py b/Lib/packaging/errors.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/errors.py @@ -0,0 +1,142 @@ +"""Exceptions used throughout the package. + +Submodules of packaging may raise exceptions defined in this module as +well as standard exceptions; in particular, SystemExit is usually raised +for errors that are obviously the end-user's fault (e.g. bad +command-line arguments). +""" + + +class PackagingError(Exception): + """The root of all Packaging evil.""" + + +class PackagingModuleError(PackagingError): + """Unable to load an expected module, or to find an expected class + within some module (in particular, command modules and classes).""" + + +class PackagingClassError(PackagingError): + """Some command class (or possibly distribution class, if anyone + feels a need to subclass Distribution) is found not to be holding + up its end of the bargain, ie. implementing some part of the + "command "interface.""" + + +class PackagingGetoptError(PackagingError): + """The option table provided to 'fancy_getopt()' is bogus.""" + + +class PackagingArgError(PackagingError): + """Raised by fancy_getopt in response to getopt.error -- ie. an + error in the command line usage.""" + + +class PackagingFileError(PackagingError): + """Any problems in the filesystem: expected file not found, etc. + Typically this is for problems that we detect before IOError or + OSError could be raised.""" + + +class PackagingOptionError(PackagingError): + """Syntactic/semantic errors in command options, such as use of + mutually conflicting options, or inconsistent options, + badly-spelled values, etc. No distinction is made between option + values originating in the setup script, the command line, config + files, or what-have-you -- but if we *know* something originated in + the setup script, we'll raise PackagingSetupError instead.""" + + +class PackagingSetupError(PackagingError): + """For errors that can be definitely blamed on the setup script, + such as invalid keyword arguments to 'setup()'.""" + + +class PackagingPlatformError(PackagingError): + """We don't know how to do something on the current platform (but + we do know how to do it on some platform) -- eg. trying to compile + C files on a platform not supported by a CCompiler subclass.""" + + +class PackagingExecError(PackagingError): + """Any problems executing an external program (such as the C + compiler, when compiling C files).""" + + +class PackagingInternalError(PackagingError): + """Internal inconsistencies or impossibilities (obviously, this + should never be seen if the code is working!).""" + + +class PackagingTemplateError(PackagingError): + """Syntax error in a file list template.""" + + +class PackagingByteCompileError(PackagingError): + """Byte compile error.""" + + +class PackagingPyPIError(PackagingError): + """Any problem occuring during using the indexes.""" + + +# Exception classes used by the CCompiler implementation classes +class CCompilerError(Exception): + """Some compile/link operation failed.""" + + +class PreprocessError(CCompilerError): + """Failure to preprocess one or more C/C++ files.""" + + +class CompileError(CCompilerError): + """Failure to compile one or more C/C++ source files.""" + + +class LibError(CCompilerError): + """Failure to create a static library from one or more C/C++ object + files.""" + + +class LinkError(CCompilerError): + """Failure to link one or more C/C++ object files into an executable + or shared library file.""" + + +class UnknownFileError(CCompilerError): + """Attempt to process an unknown file type.""" + + +class MetadataMissingError(PackagingError): + """A required metadata is missing""" + + +class MetadataConflictError(PackagingError): + """Attempt to read or write metadata fields that are conflictual.""" + + +class MetadataUnrecognizedVersionError(PackagingError): + """Unknown metadata version number.""" + + +class IrrationalVersionError(Exception): + """This is an irrational version.""" + pass + + +class HugeMajorVersionNumError(IrrationalVersionError): + """An irrational version because the major version number is huge + (often because a year or date was used). + + See `error_on_huge_major_num` option in `NormalizedVersion` for details. + This guard can be disabled by setting that option False. + """ + pass + + +class InstallationException(Exception): + """Base exception for installation scripts""" + + +class InstallationConflict(InstallationException): + """Raised when a conflict is detected""" diff --git a/Lib/packaging/fancy_getopt.py b/Lib/packaging/fancy_getopt.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/fancy_getopt.py @@ -0,0 +1,451 @@ +"""Command line parsing machinery. + +The FancyGetopt class is a Wrapper around the getopt module that +provides the following additional features: + * short and long options are tied together + * options have help strings, so fancy_getopt could potentially + create a complete usage summary + * options set attributes of a passed-in object. + +It is used under the hood by the command classes. Do not use directly. +""" + +import getopt +import re +import sys +import string +import textwrap + +from packaging.errors import PackagingGetoptError, PackagingArgError + +# Much like command_re in packaging.core, this is close to but not quite +# the same as a Python NAME -- except, in the spirit of most GNU +# utilities, we use '-' in place of '_'. (The spirit of LISP lives on!) +# The similarities to NAME are again not a coincidence... +longopt_pat = r'[a-zA-Z](?:[a-zA-Z0-9-]*)' +longopt_re = re.compile(r'^%s$' % longopt_pat) + +# For recognizing "negative alias" options, eg. "quiet=!verbose" +neg_alias_re = re.compile("^(%s)=!(%s)$" % (longopt_pat, longopt_pat)) + + +class FancyGetopt: + """Wrapper around the standard 'getopt()' module that provides some + handy extra functionality: + * short and long options are tied together + * options have help strings, and help text can be assembled + from them + * options set attributes of a passed-in object + * boolean options can have "negative aliases" -- eg. if + --quiet is the "negative alias" of --verbose, then "--quiet" + on the command line sets 'verbose' to false + """ + + def __init__(self, option_table=None): + + # The option table is (currently) a list of tuples. The + # tuples may have 3 or four values: + # (long_option, short_option, help_string [, repeatable]) + # if an option takes an argument, its long_option should have '=' + # appended; short_option should just be a single character, no ':' + # in any case. If a long_option doesn't have a corresponding + # short_option, short_option should be None. All option tuples + # must have long options. + self.option_table = option_table + + # 'option_index' maps long option names to entries in the option + # table (ie. those 3-tuples). + self.option_index = {} + if self.option_table: + self._build_index() + + # 'alias' records (duh) alias options; {'foo': 'bar'} means + # --foo is an alias for --bar + self.alias = {} + + # 'negative_alias' keeps track of options that are the boolean + # opposite of some other option + self.negative_alias = {} + + # These keep track of the information in the option table. We + # don't actually populate these structures until we're ready to + # parse the command line, since the 'option_table' passed in here + # isn't necessarily the final word. + self.short_opts = [] + self.long_opts = [] + self.short2long = {} + self.attr_name = {} + self.takes_arg = {} + + # And 'option_order' is filled up in 'getopt()'; it records the + # original order of options (and their values) on the command line, + # but expands short options, converts aliases, etc. + self.option_order = [] + + def _build_index(self): + self.option_index.clear() + for option in self.option_table: + self.option_index[option[0]] = option + + def set_option_table(self, option_table): + self.option_table = option_table + self._build_index() + + def add_option(self, long_option, short_option=None, help_string=None): + if long_option in self.option_index: + raise PackagingGetoptError( + "option conflict: already an option '%s'" % long_option) + else: + option = (long_option, short_option, help_string) + self.option_table.append(option) + self.option_index[long_option] = option + + def has_option(self, long_option): + """Return true if the option table for this parser has an + option with long name 'long_option'.""" + return long_option in self.option_index + + def _check_alias_dict(self, aliases, what): + assert isinstance(aliases, dict) + for alias, opt in aliases.items(): + if alias not in self.option_index: + raise PackagingGetoptError( + ("invalid %s '%s': " + "option '%s' not defined") % (what, alias, alias)) + if opt not in self.option_index: + raise PackagingGetoptError( + ("invalid %s '%s': " + "aliased option '%s' not defined") % (what, alias, opt)) + + def set_aliases(self, alias): + """Set the aliases for this option parser.""" + self._check_alias_dict(alias, "alias") + self.alias = alias + + def set_negative_aliases(self, negative_alias): + """Set the negative aliases for this option parser. + 'negative_alias' should be a dictionary mapping option names to + option names, both the key and value must already be defined + in the option table.""" + self._check_alias_dict(negative_alias, "negative alias") + self.negative_alias = negative_alias + + def _grok_option_table(self): + """Populate the various data structures that keep tabs on the + option table. Called by 'getopt()' before it can do anything + worthwhile. + """ + self.long_opts = [] + self.short_opts = [] + self.short2long.clear() + self.repeat = {} + + for option in self.option_table: + if len(option) == 3: + integer, short, help = option + repeat = 0 + elif len(option) == 4: + integer, short, help, repeat = option + else: + # the option table is part of the code, so simply + # assert that it is correct + raise ValueError("invalid option tuple: %r" % option) + + # Type- and value-check the option names + if not isinstance(integer, str) or len(integer) < 2: + raise PackagingGetoptError( + ("invalid long option '%s': " + "must be a string of length >= 2") % integer) + + if (not ((short is None) or + (isinstance(short, str) and len(short) == 1))): + raise PackagingGetoptError( + ("invalid short option '%s': " + "must be a single character or None") % short) + + self.repeat[integer] = repeat + self.long_opts.append(integer) + + if integer[-1] == '=': # option takes an argument? + if short: + short = short + ':' + integer = integer[0:-1] + self.takes_arg[integer] = 1 + else: + + # Is option is a "negative alias" for some other option (eg. + # "quiet" == "!verbose")? + alias_to = self.negative_alias.get(integer) + if alias_to is not None: + if self.takes_arg[alias_to]: + raise PackagingGetoptError( + ("invalid negative alias '%s': " + "aliased option '%s' takes a value") % \ + (integer, alias_to)) + + self.long_opts[-1] = integer # XXX redundant?! + self.takes_arg[integer] = 0 + + else: + self.takes_arg[integer] = 0 + + # If this is an alias option, make sure its "takes arg" flag is + # the same as the option it's aliased to. + alias_to = self.alias.get(integer) + if alias_to is not None: + if self.takes_arg[integer] != self.takes_arg[alias_to]: + raise PackagingGetoptError( + ("invalid alias '%s': inconsistent with " + "aliased option '%s' (one of them takes a value, " + "the other doesn't") % (integer, alias_to)) + + # Now enforce some bondage on the long option name, so we can + # later translate it to an attribute name on some object. Have + # to do this a bit late to make sure we've removed any trailing + # '='. + if not longopt_re.match(integer): + raise PackagingGetoptError( + ("invalid long option name '%s' " + + "(must be letters, numbers, hyphens only") % integer) + + self.attr_name[integer] = integer.replace('-', '_') + if short: + self.short_opts.append(short) + self.short2long[short[0]] = integer + + def getopt(self, args=None, object=None): + """Parse command-line options in args. Store as attributes on object. + + If 'args' is None or not supplied, uses 'sys.argv[1:]'. If + 'object' is None or not supplied, creates a new OptionDummy + object, stores option values there, and returns a tuple (args, + object). If 'object' is supplied, it is modified in place and + 'getopt()' just returns 'args'; in both cases, the returned + 'args' is a modified copy of the passed-in 'args' list, which + is left untouched. + """ + if args is None: + args = sys.argv[1:] + if object is None: + object = OptionDummy() + created_object = 1 + else: + created_object = 0 + + self._grok_option_table() + + short_opts = ' '.join(self.short_opts) + + try: + opts, args = getopt.getopt(args, short_opts, self.long_opts) + except getopt.error as msg: + raise PackagingArgError(msg) + + for opt, val in opts: + if len(opt) == 2 and opt[0] == '-': # it's a short option + opt = self.short2long[opt[1]] + else: + assert len(opt) > 2 and opt[:2] == '--' + opt = opt[2:] + + alias = self.alias.get(opt) + if alias: + opt = alias + + if not self.takes_arg[opt]: # boolean option? + assert val == '', "boolean option can't have value" + alias = self.negative_alias.get(opt) + if alias: + opt = alias + val = 0 + else: + val = 1 + + attr = self.attr_name[opt] + # The only repeating option at the moment is 'verbose'. + # It has a negative option -q quiet, which should set verbose = 0. + if val and self.repeat.get(attr) is not None: + val = getattr(object, attr, 0) + 1 + setattr(object, attr, val) + self.option_order.append((opt, val)) + + # for opts + if created_object: + return args, object + else: + return args + + def get_option_order(self): + """Returns the list of (option, value) tuples processed by the + previous run of 'getopt()'. Raises RuntimeError if + 'getopt()' hasn't been called yet. + """ + if self.option_order is None: + raise RuntimeError("'getopt()' hasn't been called yet") + else: + return self.option_order + + return self.option_order + + def generate_help(self, header=None): + """Generate help text (a list of strings, one per suggested line of + output) from the option table for this FancyGetopt object. + """ + # Blithely assume the option table is good: probably wouldn't call + # 'generate_help()' unless you've already called 'getopt()'. + + # First pass: determine maximum length of long option names + max_opt = 0 + for option in self.option_table: + integer = option[0] + short = option[1] + l = len(integer) + if integer[-1] == '=': + l = l - 1 + if short is not None: + l = l + 5 # " (-x)" where short == 'x' + if l > max_opt: + max_opt = l + + opt_width = max_opt + 2 + 2 + 2 # room for indent + dashes + gutter + + # Typical help block looks like this: + # --foo controls foonabulation + # Help block for longest option looks like this: + # --flimflam set the flim-flam level + # and with wrapped text: + # --flimflam set the flim-flam level (must be between + # 0 and 100, except on Tuesdays) + # Options with short names will have the short name shown (but + # it doesn't contribute to max_opt): + # --foo (-f) controls foonabulation + # If adding the short option would make the left column too wide, + # we push the explanation off to the next line + # --flimflam (-l) + # set the flim-flam level + # Important parameters: + # - 2 spaces before option block start lines + # - 2 dashes for each long option name + # - min. 2 spaces between option and explanation (gutter) + # - 5 characters (incl. space) for short option name + + # Now generate lines of help text. (If 80 columns were good enough + # for Jesus, then 78 columns are good enough for me!) + line_width = 78 + text_width = line_width - opt_width + big_indent = ' ' * opt_width + if header: + lines = [header] + else: + lines = ['Option summary:'] + + for option in self.option_table: + integer, short, help = option[:3] + text = textwrap.wrap(help, text_width) + + # Case 1: no short option at all (makes life easy) + if short is None: + if text: + lines.append(" --%-*s %s" % (max_opt, integer, text[0])) + else: + lines.append(" --%-*s " % (max_opt, integer)) + + # Case 2: we have a short option, so we have to include it + # just after the long option + else: + opt_names = "%s (-%s)" % (integer, short) + if text: + lines.append(" --%-*s %s" % + (max_opt, opt_names, text[0])) + else: + lines.append(" --%-*s" % opt_names) + + for l in text[1:]: + lines.append(big_indent + l) + + return lines + + def print_help(self, header=None, file=None): + if file is None: + file = sys.stdout + for line in self.generate_help(header): + file.write(line + "\n") + + +def fancy_getopt(options, negative_opt, object, args): + parser = FancyGetopt(options) + parser.set_negative_aliases(negative_opt) + return parser.getopt(args, object) + + +WS_TRANS = str.maketrans(string.whitespace, ' ' * len(string.whitespace)) + + +def wrap_text(text, width): + """Split *text* into lines of no more than *width* characters each. + + *text* is a str and *width* an int. Returns a list of str. + """ + + if text is None: + return [] + if len(text) <= width: + return [text] + + text = text.expandtabs() + text = text.translate(WS_TRANS) + + chunks = re.split(r'( +|-+)', text) + chunks = [_f for _f in chunks if _f] # ' - ' results in empty strings + lines = [] + + while chunks: + + cur_line = [] # list of chunks (to-be-joined) + cur_len = 0 # length of current line + + while chunks: + l = len(chunks[0]) + if cur_len + l <= width: # can squeeze (at least) this chunk in + cur_line.append(chunks[0]) + del chunks[0] + cur_len = cur_len + l + else: # this line is full + # drop last chunk if all space + if cur_line and cur_line[-1][0] == ' ': + del cur_line[-1] + break + + if chunks: # any chunks left to process? + + # if the current line is still empty, then we had a single + # chunk that's too big too fit on a line -- so we break + # down and break it up at the line width + if cur_len == 0: + cur_line.append(chunks[0][0:width]) + chunks[0] = chunks[0][width:] + + # all-whitespace chunks at the end of a line can be discarded + # (and we know from the re.split above that if a chunk has + # *any* whitespace, it is *all* whitespace) + if chunks[0][0] == ' ': + del chunks[0] + + # and store this line in the list-of-all-lines -- as a single + # string, of course! + lines.append(''.join(cur_line)) + + # while chunks + + return lines + + +class OptionDummy: + """Dummy class just used as a place to hold command-line option + values as instance attributes.""" + + def __init__(self, options=[]): + """Create a new OptionDummy instance. The attributes listed in + 'options' will be initialized to None.""" + for opt in options: + setattr(self, opt, None) diff --git a/Lib/packaging/install.py b/Lib/packaging/install.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/install.py @@ -0,0 +1,483 @@ +"""Building blocks for installers. + +When used as a script, this module installs a release thanks to info +obtained from an index (e.g. PyPI), with dependencies. + +This is a higher-level module built on packaging.database and +packaging.pypi. +""" + +import os +import sys +import stat +import errno +import shutil +import logging +import tempfile +from sysconfig import get_config_var + +from packaging import logger +from packaging.dist import Distribution +from packaging.util import (_is_archive_file, ask, get_install_method, + egginfo_to_distinfo) +from packaging.pypi import wrapper +from packaging.version import get_version_predicate +from packaging.database import get_distributions, get_distribution +from packaging.depgraph import generate_graph + +from packaging.errors import (PackagingError, InstallationException, + InstallationConflict, CCompilerError) +from packaging.pypi.errors import ProjectNotFound, ReleaseNotFound + +__all__ = ['install_dists', 'install_from_infos', 'get_infos', 'remove', + 'install', 'install_local_project'] + + +def _move_files(files, destination): + """Move the list of files in the destination folder, keeping the same + structure. + + Return a list of tuple (old, new) emplacement of files + + :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 = tempfile.mkdtemp() + + for old in files: + # not using os.path.join() because basename() might not be + # unique in destination + new = "%s%s" % (destination, old) + + # try to make the paths. + try: + os.makedirs(os.path.dirname(new)) + except OSError as e: + if e.errno == errno.EEXIST: + pass + else: + raise e + os.rename(old, new) + yield old, new + + +def _run_distutils_install(path): + # backward compat: using setuptools or plain-distutils + cmd = '%s setup.py install --record=%s' + record_file = os.path.join(path, 'RECORD') + os.system(cmd % (sys.executable, record_file)) + if not os.path.exists(record_file): + raise ValueError('failed to install') + else: + egginfo_to_distinfo(record_file, remove_egginfo=True) + + +def _run_setuptools_install(path): + cmd = '%s setup.py install --record=%s --single-version-externally-managed' + record_file = os.path.join(path, 'RECORD') + os.system(cmd % (sys.executable, record_file)) + if not os.path.exists(record_file): + raise ValueError('failed to install') + else: + egginfo_to_distinfo(record_file, remove_egginfo=True) + + +def _run_packaging_install(path): + # XXX check for a valid setup.cfg? + dist = Distribution() + dist.parse_config_files() + try: + dist.run_command('install_dist') + except (IOError, os.error, PackagingError, CCompilerError) as msg: + raise SystemExit("error: " + str(msg)) + + +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 packaging or distutils1. + """ + where = dist.unpack() + + if where is None: + raise ValueError('Cannot locate the unpacked archive') + + return _run_install_from_archive(where) + + +def install_local_project(path): + """Install a distribution from a source directory. + + If the source directory contains a setup.py install using distutils1. + If a setup.cfg is found, install using the install_dist command. + + """ + path = os.path.abspath(path) + if os.path.isdir(path): + logger.info('installing from source directory: %s', path) + _run_install_from_dir(path) + elif _is_archive_file(path): + logger.info('installing from archive: %s', path) + _unpacked_dir = tempfile.mkdtemp() + shutil.unpack_archive(path, _unpacked_dir) + _run_install_from_archive(_unpacked_dir) + else: + logger.warning('no projects to install') + + +def _run_install_from_archive(source_dir): + # XXX need a better way + for item in os.listdir(source_dir): + fullpath = os.path.join(source_dir, item) + if os.path.isdir(fullpath): + source_dir = fullpath + break + return _run_install_from_dir(source_dir) + + +install_methods = { + 'packaging': _run_packaging_install, + 'setuptools': _run_setuptools_install, + 'distutils': _run_distutils_install} + + +def _run_install_from_dir(source_dir): + old_dir = os.getcwd() + os.chdir(source_dir) + install_method = get_install_method(source_dir) + func = install_methods[install_method] + try: + func = install_methods[install_method] + return func(source_dir) + finally: + os.chdir(old_dir) + + +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 + the installed distribution (in the context if this function). + + Return a list of installed dists. + + :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 + """ + if not path: + path = tempfile.mkdtemp() + + installed_dists = [] + for dist in dists: + logger.info('installing %s %s', dist.name, dist.version) + try: + _install_dist(dist, path) + installed_dists.append(dist) + except Exception as e: + logger.info('failed: %s', e) + + # reverting + for installed_dist in installed_dists: + logger.info('reverting %s', installed_dist) + _remove_dist(installed_dist, paths) + raise e + return installed_dists + + +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. + The aim of this script is to povide a way to install/remove what's asked, + and to rollback if needed. + + So, it's not possible to be in an inconsistant state, it could be either + installed, either uninstalled, not half-installed. + + The process follow those steps: + + 1. Move all distributions that will be removed in a temporary location + 2. Install all the distributions that will be installed in a temp. loc. + 3. If the installation fails, rollback (eg. move back) those + distributions, or remove what have been installed. + 4. Else, move the distributions to the right locations, and remove for + real the distributions thats need to be removed. + + :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 paths: list of paths (defaults to sys.path) to look for info + """ + # 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.list_installed_files() + temp_files[dist] = _move_files(files, temp_dir) + try: + if install: + 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(): + for old, new in files: + shutil.move(new, old) + if temp_dir: + shutil.rmtree(temp_dir) + # now re-raising + raise + + # we can remove them for good + 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): + # 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. + + :param requirements: is a *string* containing the requirements for this + project (for instance "FooBar 1.1" or "BarBaz (<1.2)") + :param index: If an index is specified, use this one, otherwise, use + :class index.ClientWrapper: to get project metadatas. + :param installed: a list of already installed distributions. + :param prefer_final: when picking up the releases, prefer a "final" one + over a beta/alpha/etc one. + + The results are returned in a dict, containing all the operations + needed to install the given requirements:: + + >>> get_install_info("FooBar (<=1.2)") + {'install': [], 'remove': [], 'conflict': []} + + Conflict contains all the conflicting distributions, if there is a + conflict. + """ + # this function does several things: + # 1. get a release specified by the requirements + # 2. gather its metadata, using setuptools compatibility if needed + # 3. compare this tree with what is currently installed on the system, + # return the requirements of what is missing + # 4. do that recursively and merge back the results + # 5. return a dict containing information about what is needed to install + # or remove + + if not installed: + logger.info('reading installed distributions') + installed = list(get_distributions(use_egg_info=True)) + + infos = {'install': [], 'remove': [], 'conflict': []} + # Is a compatible version of the project already installed ? + predicate = get_version_predicate(requirements) + found = False + + # check that the project isn't 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 we already have something installed, check it matches the + # requirements + 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: + release = index.get_release(requirements) + except (ReleaseNotFound, ProjectNotFound): + raise InstallationException('Release not found: "%s"' % requirements) + + if release is None: + logger.info('could not find a matching project') + return infos + + metadata = release.fetch_metadata() + + # we need to build setuptools deps if any + if 'requires_dist' not in metadata: + metadata['requires_dist'] = _get_setuptools_deps(release) + + # build the dependency graph with local and required dependencies + dists = list(installed) + dists.append(release) + depgraph = generate_graph(dists) + + # Get what the missing deps are + 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]]) + infos['install'].append(release) + return infos + + +def _update_infos(infos, new_infos): + """extends the lists contained in the `info` dict with those contained + in the `new_info` one + """ + for key, value in infos.items(): + if key in new_infos: + infos[key].extend(new_infos[key]) + + +def _remove_dist(dist, paths=sys.path): + remove(dist.name, paths) + + +def remove(project_name, paths=sys.path, auto_confirm=True): + """Removes a single project from the installation""" + dist = get_distribution(project_name, use_egg_info=True, paths=paths) + if dist is None: + raise PackagingError('Distribution "%s" not found' % project_name) + files = dist.list_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_) + 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) + finally: + shutil.rmtree(tmp) + + logger.info('removing %r: ', project_name) + + for file_ in rmfiles: + logger.info(' %s', file_) + + # Taken from the pip project + if auto_confirm: + response = 'y' + else: + response = ask('Proceed (y/n)? ', ('y', 'n')) + + if response == 'y': + file_count = 0 + for file_ in rmfiles: + os.remove(file_) + file_count += 1 + + dir_count = 0 + for dirname in rmdirs: + 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 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 ? + if os.path.exists(dist.path): + shutil.rmtree(dist.path) + + logger.info('success: removed %d files and %d dirs', + file_count, dir_count) + + +def install(project): + logger.info('getting information about %r', project) + try: + info = get_infos(project) + except InstallationException: + logger.info('cound not find %r', project) + return + + if info['install'] == []: + logger.info('nothing to install') + return + + install_path = get_config_var('base') + try: + install_from_infos(install_path, + info['install'], info['remove'], info['conflict']) + + except InstallationConflict as e: + if logger.isEnabledFor(logging.INFO): + projects = ['%s %s' % (p.name, p.version) for p in e.args[0]] + logger.info('%r 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() diff --git a/Lib/packaging/manifest.py b/Lib/packaging/manifest.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/manifest.py @@ -0,0 +1,372 @@ +"""Class representing the list of files in a distribution. + +The Manifest class can be used to: + + - read or write a MANIFEST file + - read a template file and find out the file list +""" +# XXX todo: document + add tests +import re +import os +import fnmatch + +from packaging import logger +from packaging.util import write_file, convert_path +from packaging.errors import (PackagingTemplateError, + PackagingInternalError) + +__all__ = ['Manifest'] + +# a \ followed by some spaces + EOL +_COLLAPSE_PATTERN = re.compile('\\\w*\n', re.M) +_COMMENTED_LINE = re.compile('#.*?(?=\n)|\n(?=$)', re.M | re.S) + + +class Manifest(object): + """A list of files built by on exploring the filesystem and filtered by + applying various patterns to what we find there. + """ + + def __init__(self): + self.allfiles = None + self.files = [] + + # + # Public API + # + + def findall(self, dir=os.curdir): + self.allfiles = _findall(dir) + + def append(self, item): + self.files.append(item) + + def extend(self, items): + self.files.extend(items) + + def sort(self): + # Not a strict lexical sort! + self.files = [os.path.join(*path_tuple) for path_tuple in + sorted(os.path.split(path) for path in self.files)] + + def clear(self): + """Clear all collected files.""" + self.files = [] + if self.allfiles is not None: + self.allfiles = [] + + def remove_duplicates(self): + # Assumes list has been sorted! + for i in range(len(self.files) - 1, 0, -1): + if self.files[i] == self.files[i - 1]: + del self.files[i] + + def read_template(self, path_or_file): + """Read and parse a manifest template file. + 'path' can be a path or a file-like object. + + Updates the list accordingly. + """ + if isinstance(path_or_file, str): + f = open(path_or_file) + else: + f = path_or_file + + try: + content = f.read() + # first, let's unwrap collapsed lines + content = _COLLAPSE_PATTERN.sub('', content) + # next, let's remove commented lines and empty lines + content = _COMMENTED_LINE.sub('', content) + + # now we have our cleaned up lines + lines = [line.strip() for line in content.split('\n')] + finally: + f.close() + + for line in lines: + if line == '': + continue + try: + self._process_template_line(line) + except PackagingTemplateError as msg: + logger.warning("%s, %s", path_or_file, msg) + + def write(self, path): + """Write the file list in 'self.filelist' (presumably as filled in + by 'add_defaults()' and 'read_template()') to the manifest file + named by 'self.manifest'. + """ + if os.path.isfile(path): + with open(path) as fp: + first_line = fp.readline() + + if first_line != '# file GENERATED by packaging, do NOT edit\n': + logger.info("not writing to manually maintained " + "manifest file %r", path) + return + + self.sort() + self.remove_duplicates() + content = self.files[:] + content.insert(0, '# file GENERATED by packaging, do NOT edit') + logger.info("writing manifest file %r", path) + write_file(path, content) + + def read(self, path): + """Read the manifest file (named by 'self.manifest') and use it to + fill in 'self.filelist', the list of files to include in the source + distribution. + """ + logger.info("reading manifest file %r", path) + with open(path) as manifest: + for line in manifest.readlines(): + self.append(line) + + def exclude_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Remove strings (presumably filenames) from 'files' that match + 'pattern'. + + Other parameters are the same as for 'include_pattern()', above. + The list 'self.files' is modified in place. Return True if files are + found. + """ + files_found = False + pattern_re = _translate_pattern(pattern, anchor, prefix, is_regex) + for i in range(len(self.files) - 1, -1, -1): + if pattern_re.search(self.files[i]): + del self.files[i] + files_found = True + + return files_found + + # + # Private API + # + + def _parse_template_line(self, line): + words = line.split() + if len(words) == 1: + # no action given, let's use the default 'include' + words.insert(0, 'include') + + action = words[0] + patterns = dir = dir_pattern = None + + if action in ('include', 'exclude', + 'global-include', 'global-exclude'): + if len(words) < 2: + raise PackagingTemplateError( + "%r expects ..." % action) + + patterns = [convert_path(word) for word in words[1:]] + + elif action in ('recursive-include', 'recursive-exclude'): + if len(words) < 3: + raise PackagingTemplateError( + "%r expects

    ..." % action) + + dir = convert_path(words[1]) + patterns = [convert_path(word) for word in words[2:]] + + elif action in ('graft', 'prune'): + if len(words) != 2: + raise PackagingTemplateError( + "%r expects a single " % action) + + dir_pattern = convert_path(words[1]) + + else: + raise PackagingTemplateError("unknown action %r" % action) + + return action, patterns, dir, dir_pattern + + def _process_template_line(self, line): + # Parse the line: split it up, make sure the right number of words + # is there, and return the relevant words. 'action' is always + # defined: it's the first word of the line. Which of the other + # three are defined depends on the action; it'll be either + # patterns, (dir and patterns), or (dir_pattern). + action, patterns, dir, dir_pattern = self._parse_template_line(line) + + # OK, now we know that the action is valid and we have the + # right number of words on the line for that action -- so we + # can proceed with minimal error-checking. + if action == 'include': + for pattern in patterns: + if not self._include_pattern(pattern, anchor=True): + logger.warning("no files found matching %r", pattern) + + elif action == 'exclude': + for pattern in patterns: + if not self.exclude_pattern(pattern, anchor=True): + logger.warning("no previously-included files " + "found matching %r", pattern) + + elif action == 'global-include': + for pattern in patterns: + if not self._include_pattern(pattern, anchor=False): + logger.warning("no files found matching %r " + "anywhere in distribution", pattern) + + elif action == 'global-exclude': + for pattern in patterns: + if not self.exclude_pattern(pattern, anchor=False): + logger.warning("no previously-included files " + "matching %r found anywhere in " + "distribution", pattern) + + elif action == 'recursive-include': + for pattern in patterns: + if not self._include_pattern(pattern, prefix=dir): + logger.warning("no files found matching %r " + "under directory %r", pattern, dir) + + elif action == 'recursive-exclude': + for pattern in patterns: + if not self.exclude_pattern(pattern, prefix=dir): + logger.warning("no previously-included files " + "matching %r found under directory %r", + pattern, dir) + + elif action == 'graft': + if not self._include_pattern(None, prefix=dir_pattern): + logger.warning("no directories found matching %r", + dir_pattern) + + elif action == 'prune': + if not self.exclude_pattern(None, prefix=dir_pattern): + logger.warning("no previously-included directories found " + "matching %r", dir_pattern) + else: + raise PackagingInternalError( + "this cannot happen: invalid action %r" % action) + + def _include_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Select strings (presumably filenames) from 'self.files' that + match 'pattern', a Unix-style wildcard (glob) pattern. + + Patterns are not quite the same as implemented by the 'fnmatch' + module: '*' and '?' match non-special characters, where "special" + is platform-dependent: slash on Unix; colon, slash, and backslash on + DOS/Windows; and colon on Mac OS. + + If 'anchor' is true (the default), then the pattern match is more + stringent: "*.py" will match "foo.py" but not "foo/bar.py". If + 'anchor' is false, both of these will match. + + If 'prefix' is supplied, then only filenames starting with 'prefix' + (itself a pattern) and ending with 'pattern', with anything in between + them, will match. 'anchor' is ignored in this case. + + If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and + 'pattern' is assumed to be either a string containing a regex or a + regex object -- no translation is done, the regex is just compiled + and used as-is. + + Selected strings will be added to self.files. + + Return True if files are found. + """ + files_found = False + pattern_re = _translate_pattern(pattern, anchor, prefix, is_regex) + + # delayed loading of allfiles list + if self.allfiles is None: + self.findall() + + for name in self.allfiles: + if pattern_re.search(name): + self.files.append(name) + files_found = True + + return files_found + + +# +# Utility functions +# +def _findall(dir=os.curdir): + """Find all files under 'dir' and return the list of full filenames + (relative to 'dir'). + """ + from stat import S_ISREG, S_ISDIR, S_ISLNK + + list = [] + stack = [dir] + pop = stack.pop + push = stack.append + + while stack: + dir = pop() + names = os.listdir(dir) + + for name in names: + if dir != os.curdir: # avoid the dreaded "./" syndrome + fullname = os.path.join(dir, name) + else: + fullname = name + + # Avoid excess stat calls -- just one will do, thank you! + stat = os.stat(fullname) + mode = stat.st_mode + if S_ISREG(mode): + list.append(fullname) + elif S_ISDIR(mode) and not S_ISLNK(mode): + push(fullname) + + return list + + +def _glob_to_re(pattern): + """Translate a shell-like glob pattern to a regular expression. + + Return a string containing the regex. Differs from + 'fnmatch.translate()' in that '*' does not match "special characters" + (which are platform-specific). + """ + pattern_re = fnmatch.translate(pattern) + + # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which + # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, + # and by extension they shouldn't match such "special characters" under + # any OS. So change all non-escaped dots in the RE to match any + # character except the special characters. + # XXX currently the "special characters" are just slash -- i.e. this is + # Unix-only. + pattern_re = re.sub(r'((?': 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(), + 'platform.python_implementation': platform.python_implementation()} + + +class _Operation: + + 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: + 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: + 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() + + +def interpret(marker, execution_context=None): + """Interpret a marker and return a result depending on environment.""" + marker = marker.strip().encode() + ops = [] + op_starting = True + for token in tokenize(BytesIO(marker).readline): + # Unpack token + toktype, tokval, rowcol, line, logical_line = token + if toktype not in (NAME, OP, STRING, ENDMARKER, ENCODING): + raise SyntaxError('Type not supported "%s"' % tokval) + + if op_starting: + op = _Operation(execution_context) + if len(ops) > 0: + last = ops[-1] + if isinstance(last, (_OR, _AND)) and not last.filled(): + last.right = op + else: + ops.append(op) + else: + ops.append(op) + op_starting = False + else: + op = ops[-1] + + if (toktype == ENDMARKER or + (toktype == NAME and tokval in ('and', 'or'))): + if toktype == NAME and tokval == 'and': + ops.append(_AND(ops.pop())) + elif toktype == NAME and tokval == 'or': + ops.append(_OR(ops.pop())) + op_starting = True + continue + + 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 + + for op in ops: + if not op(): + return False + return True diff --git a/Lib/packaging/metadata.py b/Lib/packaging/metadata.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/metadata.py @@ -0,0 +1,552 @@ +"""Implementation of the Metadata for Python packages PEPs. + +Supports all metadata formats (1.0, 1.1, 1.2). +""" + +import re +import logging + +from io import StringIO +from email import message_from_file +from packaging import logger +from packaging.markers import interpret +from packaging.version import (is_valid_predicate, is_valid_version, + is_valid_versions) +from packaging.errors import (MetadataMissingError, + MetadataConflictError, + MetadataUnrecognizedVersionError) + +try: + # docutils is installed + from docutils.utils import Reporter + from docutils.parsers.rst import Parser + from docutils import frontend + from docutils import nodes + + class SilentReporter(Reporter): + + def __init__(self, source, report_level, halt_level, stream=None, + debug=0, encoding='ascii', error_handler='replace'): + self.messages = [] + Reporter.__init__(self, source, report_level, halt_level, stream, + debug, encoding, error_handler) + + def system_message(self, level, message, *children, **kwargs): + self.messages.append((level, message, children, kwargs)) + + _HAS_DOCUTILS = True +except ImportError: + # docutils is not installed + _HAS_DOCUTILS = False + +# public API of this module +__all__ = ['Metadata', 'PKG_INFO_ENCODING', 'PKG_INFO_PREFERRED_VERSION'] + +# Encoding used for the PKG-INFO files +PKG_INFO_ENCODING = 'utf-8' + +# preferred version. Hopefully will be changed +# to 1.2 once PEP 345 is supported everywhere +PKG_INFO_PREFERRED_VERSION = '1.0' + +_LINE_PREFIX = re.compile('\n \|') +_241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'License') + +_314_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'License', 'Classifier', 'Download-URL', 'Obsoletes', + 'Provides', 'Requires') + +_314_MARKERS = ('Obsoletes', 'Provides', 'Requires') + +_345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'Maintainer', 'Maintainer-email', 'License', + 'Classifier', 'Download-URL', 'Obsoletes-Dist', + 'Project-URL', 'Provides-Dist', 'Requires-Dist', + 'Requires-Python', 'Requires-External') + +_345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python', + 'Obsoletes-Dist', 'Requires-External', 'Maintainer', + 'Maintainer-email', 'Project-URL') + +_ALL_FIELDS = set() +_ALL_FIELDS.update(_241_FIELDS) +_ALL_FIELDS.update(_314_FIELDS) +_ALL_FIELDS.update(_345_FIELDS) + + +def _version2fieldlist(version): + if version == '1.0': + return _241_FIELDS + elif version == '1.1': + return _314_FIELDS + elif version == '1.2': + return _345_FIELDS + raise MetadataUnrecognizedVersionError(version) + + +def _best_version(fields): + """Detect the best version depending on the fields used.""" + def _has_marker(keys, markers): + for marker in markers: + if marker in keys: + return True + return False + + keys = list(fields) + possible_versions = ['1.0', '1.1', '1.2'] + + # first let's try to see if a field is not part of one of the version + for key in keys: + if key not in _241_FIELDS and '1.0' in possible_versions: + possible_versions.remove('1.0') + if key not in _314_FIELDS and '1.1' in possible_versions: + possible_versions.remove('1.1') + if key not in _345_FIELDS and '1.2' in possible_versions: + possible_versions.remove('1.2') + + # possible_version contains qualified versions + if len(possible_versions) == 1: + return possible_versions[0] # found ! + elif len(possible_versions) == 0: + raise MetadataConflictError('Unknown metadata set') + + # let's see if one unique marker is found + is_1_1 = '1.1' in possible_versions and _has_marker(keys, _314_MARKERS) + is_1_2 = '1.2' in possible_versions and _has_marker(keys, _345_MARKERS) + if is_1_1 and is_1_2: + raise MetadataConflictError('You used incompatible 1.1 and 1.2 fields') + + # we have the choice, either 1.0, or 1.2 + # - 1.0 has a broken Summary field but works with all tools + # - 1.1 is to avoid + # - 1.2 fixes Summary but is not widespread yet + if not is_1_1 and not is_1_2: + # we couldn't find any specific marker + if PKG_INFO_PREFERRED_VERSION in possible_versions: + return PKG_INFO_PREFERRED_VERSION + if is_1_1: + return '1.1' + + # default marker when 1.0 is disqualified + return '1.2' + + +_ATTR2FIELD = { + 'metadata_version': 'Metadata-Version', + 'name': 'Name', + 'version': 'Version', + 'platform': 'Platform', + 'supported_platform': 'Supported-Platform', + 'summary': 'Summary', + 'description': 'Description', + 'keywords': 'Keywords', + 'home_page': 'Home-page', + 'author': 'Author', + 'author_email': 'Author-email', + 'maintainer': 'Maintainer', + 'maintainer_email': 'Maintainer-email', + 'license': 'License', + 'classifier': 'Classifier', + 'download_url': 'Download-URL', + 'obsoletes_dist': 'Obsoletes-Dist', + 'provides_dist': 'Provides-Dist', + 'requires_dist': 'Requires-Dist', + 'requires_python': 'Requires-Python', + 'requires_external': 'Requires-External', + 'requires': 'Requires', + 'provides': 'Provides', + 'obsoletes': 'Obsoletes', + 'project_url': 'Project-URL', +} + +_PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist') +_VERSIONS_FIELDS = ('Requires-Python',) +_VERSION_FIELDS = ('Version',) +_LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', + 'Requires', 'Provides', 'Obsoletes-Dist', + 'Provides-Dist', 'Requires-Dist', 'Requires-External', + 'Project-URL', 'Supported-Platform') +_LISTTUPLEFIELDS = ('Project-URL',) + +_ELEMENTSFIELD = ('Keywords',) + +_UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description') + +_MISSING = object() + + +class NoDefault: + """Marker object used for clean representation""" + def __repr__(self): + return '' + +_MISSING = NoDefault() + + +class Metadata: + """The metadata of a release. + + Supports versions 1.0, 1.1 and 1.2 (auto-detected). You can + instantiate the class with one of these arguments (or none): + - *path*, the path to a METADATA file + - *fileobj* give a file-like object with METADATA as content + - *mapping* is a dict-like object + """ + # TODO document that execution_context and platform_dependent are used + # to filter on query, not when setting a key + # also document the mapping API and UNKNOWN default key + + def __init__(self, path=None, platform_dependent=False, + execution_context=None, fileobj=None, mapping=None): + self._fields = {} + self.requires_files = [] + self.docutils_support = _HAS_DOCUTILS + self.platform_dependent = platform_dependent + self.execution_context = execution_context + if [path, fileobj, mapping].count(None) < 2: + raise TypeError('path, fileobj and mapping are exclusive') + if path is not None: + self.read(path) + elif fileobj is not None: + self.read_file(fileobj) + elif mapping is not None: + self.update(mapping) + + def _set_best_version(self): + self._fields['Metadata-Version'] = _best_version(self._fields) + + def _write_field(self, file, name, value): + file.write('%s: %s\n' % (name, value)) + + def __getitem__(self, name): + return self.get(name) + + def __setitem__(self, name, value): + return self.set(name, value) + + def __delitem__(self, name): + field_name = self._convert_name(name) + try: + del self._fields[field_name] + except KeyError: + raise KeyError(name) + self._set_best_version() + + def __contains__(self, name): + return (name in self._fields or + self._convert_name(name) in self._fields) + + def _convert_name(self, name): + if name in _ALL_FIELDS: + return name + name = name.replace('-', '_').lower() + return _ATTR2FIELD.get(name, name) + + def _default_value(self, name): + if name in _LISTFIELDS or name in _ELEMENTSFIELD: + return [] + return 'UNKNOWN' + + def _check_rst_data(self, data): + """Return warnings when the provided data has syntax errors.""" + source_path = StringIO() + parser = Parser() + settings = frontend.OptionParser().get_default_values() + settings.tab_width = 4 + settings.pep_references = None + settings.rfc_references = None + reporter = SilentReporter(source_path, + settings.report_level, + settings.halt_level, + stream=settings.warning_stream, + debug=settings.debug, + encoding=settings.error_encoding, + error_handler=settings.error_encoding_error_handler) + + document = nodes.document(settings, reporter, source=source_path) + document.note_source(source_path, -1) + try: + parser.parse(data, document) + except AttributeError: + reporter.messages.append((-1, 'Could not finish the parsing.', + '', {})) + + return reporter.messages + + def _platform(self, value): + if not self.platform_dependent or ';' not in value: + return True, value + value, marker = value.split(';') + return interpret(marker, self.execution_context), value + + def _remove_line_prefix(self, value): + return _LINE_PREFIX.sub('\n', value) + + # + # 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.""" + with open(filepath, 'r', encoding='ascii') as fp: + self.read_file(fp) + + def read_file(self, fileob): + """Read the metadata values from a file object.""" + msg = message_from_file(fileob) + self._fields['Metadata-Version'] = msg['metadata-version'] + + for field in _version2fieldlist(self['Metadata-Version']): + if field in _LISTFIELDS: + # we can have multiple lines + values = msg.get_all(field) + if field in _LISTTUPLEFIELDS and values is not None: + values = [tuple(value.split(',')) for value in values] + self.set(field, values) + else: + # single line + value = msg[field] + if value is not None and value != 'UNKNOWN': + self.set(field, value) + + def write(self, filepath): + """Write the metadata fields to filepath.""" + with open(filepath, 'w') as fp: + self.write_file(fp) + + def write_file(self, fileobject): + """Write the PKG-INFO format data to a file object.""" + self._set_best_version() + for field in _version2fieldlist(self['Metadata-Version']): + values = self.get(field) + if field in _ELEMENTSFIELD: + self._write_field(fileobject, field, ','.join(values)) + continue + if field not in _LISTFIELDS: + if field == 'Description': + values = values.replace('\n', '\n |') + values = [values] + + if field in _LISTTUPLEFIELDS: + values = [','.join(value) for value in values] + + for value in values: + self._write_field(fileobject, field, value) + + def update(self, other=None, **kwargs): + """Set metadata values from the given iterable `other` and kwargs. + + Behavior is like `dict.update`: If `other` has a ``keys`` method, + they are looped over and ``self[key]`` is assigned ``other[key]``. + Else, ``other`` is an iterable of ``(key, value)`` iterables. + + Keys that don't match a metadata field or that have an empty value are + dropped. + """ + def _set(key, value): + if key in _ATTR2FIELD and value: + self.set(self._convert_name(key), value) + + if other is None: + pass + elif hasattr(other, 'keys'): + for k in other.keys(): + _set(k, other[k]) + else: + for k, v in other: + _set(k, v) + + if kwargs: + self.update(kwargs) + + def set(self, name, value): + """Control then set a metadata field.""" + name = self._convert_name(name) + + if ((name in _ELEMENTSFIELD or name == 'Platform') and + not isinstance(value, (list, tuple))): + if isinstance(value, str): + value = [v.strip() for v in value.split(',')] + else: + value = [] + elif (name in _LISTFIELDS and + not isinstance(value, (list, tuple))): + if isinstance(value, str): + value = [value] + else: + value = [] + + if logger.isEnabledFor(logging.WARNING): + if name in _PREDICATE_FIELDS and value is not None: + for v in value: + # check that the values are valid predicates + if not is_valid_predicate(v.split(';')[0]): + logger.warning( + '%r is not a valid predicate (field %r)', + v, name) + # FIXME this rejects UNKNOWN, is that right? + elif name in _VERSIONS_FIELDS and value is not None: + if not is_valid_versions(value): + logger.warning('%r is not a valid version (field %r)', + value, name) + elif name in _VERSION_FIELDS and value is not None: + if not is_valid_version(value): + logger.warning('%r is not a valid version (field %r)', + value, name) + + if name in _UNICODEFIELDS: + if name == 'Description': + value = self._remove_line_prefix(value) + + self._fields[name] = value + self._set_best_version() + + def get(self, name, default=_MISSING): + """Get a metadata field.""" + name = self._convert_name(name) + if name not in self._fields: + if default is _MISSING: + default = self._default_value(name) + return default + if name in _UNICODEFIELDS: + value = self._fields[name] + return value + elif name in _LISTFIELDS: + value = self._fields[name] + if value is None: + return [] + res = [] + for val in value: + valid, val = self._platform(val) + if not valid: + continue + if name not in _LISTTUPLEFIELDS: + res.append(val) + else: + # That's for Project-URL + res.append((val[0], val[1])) + return res + + elif name in _ELEMENTSFIELD: + valid, value = self._platform(self._fields[name]) + if not valid: + return [] + if isinstance(value, str): + return value.split(',') + valid, value = self._platform(self._fields[name]) + if not valid: + return None + return value + + def check(self, strict=False, restructuredtext=False): + """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 = [], [] + + for attr in ('Name', 'Version'): # required by PEP 345 + 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', 'Author'): + if attr not in self: + missing.append(attr) + + if _HAS_DOCUTILS and restructuredtext: + warnings.extend(self._check_rst_data(self['Description'])) + + # checking metadata 1.2 (XXX needs to check 1.1, 1.0) + if self['Metadata-Version'] != '1.2': + return missing, warnings + + def is_valid_predicates(value): + for v in value: + if not is_valid_predicate(v.split(';')[0]): + return False + return True + + for fields, controller in ((_PREDICATE_FIELDS, is_valid_predicates), + (_VERSIONS_FIELDS, is_valid_versions), + (_VERSION_FIELDS, is_valid_version)): + for field in fields: + value = self.get(field, None) + if value is not None and not controller(value): + warnings.append('Wrong value for %r: %s' % (field, value)) + + return missing, warnings + + def todict(self): + """Return fields as a dict. + + Field names will be converted to use the underscore-lowercase style + instead of hyphen-mixed case (i.e. home_page instead of Home-page). + """ + data = { + 'metadata_version': self['Metadata-Version'], + 'name': self['Name'], + 'version': self['Version'], + 'summary': self['Summary'], + 'home_page': self['Home-page'], + 'author': self['Author'], + 'author_email': self['Author-email'], + 'license': self['License'], + 'description': self['Description'], + 'keywords': self['Keywords'], + 'platform': self['Platform'], + 'classifier': self['Classifier'], + 'download_url': self['Download-URL'], + } + + if self['Metadata-Version'] == '1.2': + data['requires_dist'] = self['Requires-Dist'] + data['requires_python'] = self['Requires-Python'] + data['requires_external'] = self['Requires-External'] + data['provides_dist'] = self['Provides-Dist'] + data['obsoletes_dist'] = self['Obsoletes-Dist'] + data['project_url'] = [','.join(url) for url in + self['Project-URL']] + + elif self['Metadata-Version'] == '1.1': + data['provides'] = self['Provides'] + data['requires'] = self['Requires'] + data['obsoletes'] = self['Obsoletes'] + + return data + + # Mapping API + + def keys(self): + return _version2fieldlist(self['Metadata-Version']) + + def __iter__(self): + for key in self.keys(): + yield key + + def values(self): + return [self[key] for key in list(self.keys())] + + def items(self): + return [(key, self[key]) for key in list(self.keys())] diff --git a/Lib/packaging/pypi/__init__.py b/Lib/packaging/pypi/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/pypi/__init__.py @@ -0,0 +1,9 @@ +"""Low-level and high-level APIs to interact with project indexes.""" + +__all__ = ['simple', + 'xmlrpc', + 'dist', + 'errors', + 'mirrors'] + +from packaging.pypi.dist import ReleaseInfo, ReleasesList, DistInfo diff --git a/Lib/packaging/pypi/base.py b/Lib/packaging/pypi/base.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/pypi/base.py @@ -0,0 +1,48 @@ +"""Base class for index crawlers.""" + +from packaging.pypi.dist import ReleasesList + + +class BaseClient: + """Base class containing common methods for the index crawlers/clients""" + + def __init__(self, prefer_final, prefer_source): + self._prefer_final = prefer_final + self._prefer_source = prefer_source + self._index = self + + def _get_prefer_final(self, prefer_final=None): + """Return the prefer_final internal parameter or the specified one if + provided""" + if prefer_final: + return prefer_final + else: + return self._prefer_final + + def _get_prefer_source(self, prefer_source=None): + """Return the prefer_source internal parameter or the specified one if + provided""" + if prefer_source: + return prefer_source + else: + return self._prefer_source + + def _get_project(self, project_name): + """Return an project instance, create it if necessary""" + return self._projects.setdefault(project_name.lower(), + ReleasesList(project_name, index=self._index)) + + def download_distribution(self, requirements, temp_path=None, + prefer_source=None, prefer_final=None): + """Download a distribution from the last release according to the + requirements. + + If temp_path is provided, download to this path, otherwise, create a + temporary location for the download and return it. + """ + prefer_final = self._get_prefer_final(prefer_final) + prefer_source = self._get_prefer_source(prefer_source) + release = self.get_release(requirements, prefer_final) + if release: + dist = release.get_distribution(prefer_source=prefer_source) + return dist.download(temp_path) diff --git a/Lib/packaging/pypi/dist.py b/Lib/packaging/pypi/dist.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/pypi/dist.py @@ -0,0 +1,547 @@ +"""Classes representing releases and distributions retrieved from indexes. + +A project (= unique name) can have several releases (= versions) and +each release can have several distributions (= sdist and bdists). + +Release objects contain metadata-related information (see PEP 376); +distribution objects contain download-related information. +""" + +import sys +import mimetypes +import re +import tempfile +import urllib.request +import urllib.parse +import urllib.error +import urllib.parse +import hashlib +from shutil import unpack_archive + +from packaging.errors import IrrationalVersionError +from packaging.version import (suggest_normalized_version, NormalizedVersion, + get_version_predicate) +from packaging.metadata import Metadata +from packaging.pypi.errors import (HashDoesNotMatch, UnsupportedHashName, + CantParseArchiveName) + + +__all__ = ['ReleaseInfo', 'DistInfo', 'ReleasesList', 'get_infos_from_url'] + +EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz .egg".split() +MD5_HASH = re.compile(r'^.*#md5=([a-f0-9]+)$') +DIST_TYPES = ['bdist', 'sdist'] + + +class IndexReference: + """Mixin used to store the index reference""" + def set_index(self, index=None): + self._index = index + + +class ReleaseInfo(IndexReference): + """Represent a release of a project (a project with a specific version). + The release contain the _metadata informations related to this specific + version, and is also a container for distribution related informations. + + See the DistInfo class for more information about distributions. + """ + + def __init__(self, name, version, metadata=None, hidden=False, + index=None, **kwargs): + """ + :param name: the name of the distribution + :param version: the version of the distribution + :param metadata: the metadata fields of the release. + :type metadata: dict + :param kwargs: optional arguments for a new distribution. + """ + self.set_index(index) + self.name = name + self._version = None + self.version = version + if metadata: + self.metadata = Metadata(mapping=metadata) + else: + self.metadata = None + self.dists = {} + self.hidden = hidden + + if 'dist_type' in kwargs: + dist_type = kwargs.pop('dist_type') + self.add_distribution(dist_type, **kwargs) + + def set_version(self, version): + try: + self._version = NormalizedVersion(version) + except IrrationalVersionError: + suggestion = suggest_normalized_version(version) + if suggestion: + self.version = suggestion + else: + raise IrrationalVersionError(version) + + def get_version(self): + return self._version + + version = property(get_version, set_version) + + def fetch_metadata(self): + """If the metadata is not set, use the indexes to get it""" + if not self.metadata: + self._index.get_metadata(self.name, str(self.version)) + return self.metadata + + @property + def is_final(self): + """proxy to version.is_final""" + return self.version.is_final + + def fetch_distributions(self): + if self.dists is None: + self._index.get_distributions(self.name, str(self.version)) + if self.dists is None: + self.dists = {} + return self.dists + + def add_distribution(self, dist_type='sdist', python_version=None, + **params): + """Add distribution informations to this release. + If distribution information is already set for this distribution type, + add the given url paths to the distribution. This can be useful while + some of them fails to download. + + :param dist_type: the distribution type (eg. "sdist", "bdist", etc.) + :param params: the fields to be passed to the distribution object + (see the :class:DistInfo constructor). + """ + if dist_type not in DIST_TYPES: + raise ValueError(dist_type) + if dist_type in self.dists: + self.dists[dist_type].add_url(**params) + else: + self.dists[dist_type] = DistInfo(self, dist_type, + index=self._index, **params) + if python_version: + self.dists[dist_type].python_version = python_version + + def get_distribution(self, dist_type=None, prefer_source=True): + """Return a distribution. + + If dist_type is set, find first for this distribution type, and just + act as an alias of __get_item__. + + If prefer_source is True, search first for source distribution, and if + not return one existing distribution. + """ + if len(self.dists) == 0: + raise LookupError() + if dist_type: + return self[dist_type] + if prefer_source: + if "sdist" in self.dists: + dist = self["sdist"] + else: + dist = next(self.dists.values()) + 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. + + If more than one distribution match the requirements, use the last + version. + Download the distribution, and put it in the temp_path. If no temp_path + is given, creates and return one. + + Returns the complete absolute path to the downloaded archive. + """ + return self.get_distribution(prefer_source=prefer_source)\ + .download(path=temp_path) + + def set_metadata(self, metadata): + if not self.metadata: + self.metadata = Metadata() + self.metadata.update(metadata) + + def __getitem__(self, item): + """distributions are available using release["sdist"]""" + return self.dists[item] + + def _check_is_comparable(self, other): + if not isinstance(other, ReleaseInfo): + raise TypeError("cannot compare %s and %s" + % (type(self).__name__, type(other).__name__)) + elif self.name != other.name: + raise TypeError("cannot compare %s and %s" + % (self.name, other.name)) + + def __repr__(self): + return "<%s %s>" % (self.name, self.version) + + def __eq__(self, other): + self._check_is_comparable(other) + return self.version == other.version + + def __lt__(self, other): + self._check_is_comparable(other) + return self.version < other.version + + def __ne__(self, other): + return not self.__eq__(other) + + def __gt__(self, other): + return not (self.__lt__(other) or self.__eq__(other)) + + def __le__(self, other): + return self.__eq__(other) or self.__lt__(other) + + def __ge__(self, other): + return self.__eq__(other) or self.__gt__(other) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + __hash__ = object.__hash__ + + +class DistInfo(IndexReference): + """Represents a distribution retrieved from an index (sdist, bdist, ...) + """ + + def __init__(self, release, dist_type=None, url=None, hashname=None, + hashval=None, is_external=True, python_version=None, + index=None): + """Create a new instance of DistInfo. + + :param release: a DistInfo class is relative to a release. + :param dist_type: the type of the dist (eg. source, bin-*, etc.) + :param url: URL where we found this distribution + :param hashname: the name of the hash we want to use. Refer to the + hashlib.new documentation for more information. + :param hashval: the hash value. + :param is_external: we need to know if the provided url comes from + an index browsing, or from an external resource. + + """ + self.set_index(index) + self.release = release + self.dist_type = dist_type + self.python_version = python_version + self._unpacked_dir = None + # set the downloaded path to None by default. The goal here + # is to not download distributions multiple times + self.downloaded_location = None + # We store urls in dict, because we need to have a bit more infos + # than the simple URL. It will be used later to find the good url to + # use. + # We have two _url* attributes: _url and urls. urls contains a list + # of dict for the different urls, and _url contains the choosen url, in + # order to dont make the selection process multiple times. + self.urls = [] + self._url = None + self.add_url(url, hashname, hashval, is_external) + + def add_url(self, url=None, hashname=None, hashval=None, is_external=True): + """Add a new url to the list of urls""" + if hashname is not None: + try: + hashlib.new(hashname) + except ValueError: + raise UnsupportedHashName(hashname) + if not url in [u['url'] for u in self.urls]: + self.urls.append({ + 'url': url, + 'hashname': hashname, + 'hashval': hashval, + 'is_external': is_external, + }) + # reset the url selection process + self._url = None + + @property + def url(self): + """Pick up the right url for the list of urls in self.urls""" + # We return internal urls over externals. + # If there is more than one internal or external, return the first + # one. + if self._url is None: + if len(self.urls) > 1: + internals_urls = [u for u in self.urls \ + if u['is_external'] == False] + if len(internals_urls) >= 1: + self._url = internals_urls[0] + if self._url is None: + self._url = self.urls[0] + return self._url + + @property + def is_source(self): + """return if the distribution is a source one or not""" + return self.dist_type == 'sdist' + + def download(self, path=None): + """Download the distribution to a path, and return it. + + If the path is given in path, use this, otherwise, generates a new one + Return the download location. + """ + if path is None: + path = tempfile.mkdtemp() + + # if we do not have downloaded it yet, do it. + if self.downloaded_location is None: + url = self.url['url'] + archive_name = urllib.parse.urlparse(url)[2].split('/')[-1] + filename, headers = urllib.request.urlretrieve(url, + path + "/" + archive_name) + self.downloaded_location = filename + self._check_md5(filename) + return self.downloaded_location + + def unpack(self, path=None): + """Unpack the distribution to the given path. + + If not destination is given, creates a temporary location. + + Returns the location of the extracted files (root). + """ + if not self._unpacked_dir: + if path is None: + path = tempfile.mkdtemp() + + filename = self.download(path) + content_type = mimetypes.guess_type(filename)[0] + unpack_archive(filename, path) + self._unpacked_dir = path + + return path + + def _check_md5(self, filename): + """Check that the md5 checksum of the given file matches the one in + url param""" + hashname = self.url['hashname'] + expected_hashval = self.url['hashval'] + if not None in (expected_hashval, hashname): + with open(filename, 'rb') as f: + hashval = hashlib.new(hashname) + hashval.update(f.read()) + + if hashval.hexdigest() != expected_hashval: + raise HashDoesNotMatch("got %s instead of %s" + % (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 "") + + +class ReleasesList(IndexReference): + """A container of Release. + + Provides useful methods and facilities to sort and filter releases. + """ + def __init__(self, name, releases=None, contains_hidden=False, index=None): + self.set_index(index) + self.releases = [] + self.name = name + self.contains_hidden = contains_hidden + if releases: + self.add_releases(releases) + + def fetch_releases(self): + self._index.get_releases(self.name) + return self.releases + + def filter(self, predicate): + """Filter and return a subset of releases matching the given predicate. + """ + return ReleasesList(self.name, [release for release in self.releases + if predicate.match(release.version)], + index=self._index) + + def get_last(self, requirements, prefer_final=None): + """Return the "last" release, that satisfy the given predicates. + + "last" is defined by the version number of the releases, you also could + set prefer_final parameter to True or False to change the order results + """ + 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] + + def add_releases(self, releases): + """Add releases in the release list. + + :param: releases is a list of ReleaseInfo objects. + """ + for r in releases: + self.add_release(release=r) + + def add_release(self, version=None, dist_type='sdist', release=None, + **dist_args): + """Add a release to the list. + + The release can be passed in the `release` parameter, and in this case, + it will be crawled to extract the useful informations if necessary, or + the release informations can be directly passed in the `version` and + `dist_type` arguments. + + Other keywords arguments can be provided, and will be forwarded to the + distribution creation (eg. the arguments of the DistInfo constructor). + """ + if release: + if release.name.lower() != self.name.lower(): + raise ValueError("%s is not the same project as %s" % + (release.name, self.name)) + version = str(release.version) + + if not version in self.get_versions(): + # append only if not already exists + self.releases.append(release) + for dist in release.dists.values(): + for url in dist.urls: + self.add_release(version, dist.dist_type, **url) + else: + matches = [r for r in self.releases + if str(r.version) == version and r.name == self.name] + if not matches: + release = ReleaseInfo(self.name, version, index=self._index) + self.releases.append(release) + else: + release = matches[0] + + release.add_distribution(dist_type=dist_type, **dist_args) + + def sort_releases(self, prefer_final=False, reverse=True, *args, **kwargs): + """Sort the results with the given properties. + + The `prefer_final` argument can be used to specify if final + distributions (eg. not dev, bet or alpha) would be prefered or not. + + Results can be inverted by using `reverse`. + + Any other parameter provided will be forwarded to the sorted call. You + cannot redefine the key argument of "sorted" here, as it is used + internally to sort the releases. + """ + + sort_by = [] + if prefer_final: + sort_by.append("is_final") + sort_by.append("version") + + self.releases.sort( + key=lambda i: tuple(getattr(i, arg) for arg in sort_by), + reverse=reverse, *args, **kwargs) + + def get_release(self, version): + """Return a release from its version.""" + matches = [r for r in self.releases if str(r.version) == version] + if len(matches) != 1: + raise KeyError(version) + return matches[0] + + def get_versions(self): + """Return a list of releases versions contained""" + return [str(r.version) for r in self.releases] + + def __getitem__(self, key): + return self.releases[key] + + def __len__(self): + return len(self.releases) + + def __repr__(self): + string = 'Project "%s"' % self.name + if self.get_versions(): + string += ' versions: %s' % ', '.join(self.get_versions()) + return '<%s>' % string + + +def get_infos_from_url(url, probable_dist_name=None, is_external=True): + """Get useful informations from an URL. + + Return a dict of (name, version, url, hashtype, hash, is_external) + + :param url: complete url of the distribution + :param probable_dist_name: A probable name of the project. + :param is_external: Tell if the url commes from an index or from + an external URL. + """ + # if the url contains a md5 hash, get it. + md5_hash = None + match = MD5_HASH.match(url) + if match is not None: + md5_hash = match.group(1) + # remove the hash + url = url.replace("#md5=%s" % md5_hash, "") + + # parse the archive name to find dist name and version + archive_name = urllib.parse.urlparse(url)[2].split('/')[-1] + extension_matched = False + # remove the extension from the name + for ext in EXTENSIONS: + if archive_name.endswith(ext): + archive_name = archive_name[:-len(ext)] + extension_matched = True + + name, version = split_archive_name(archive_name) + if extension_matched is True: + return {'name': name, + 'version': version, + 'url': url, + 'hashname': "md5", + 'hashval': md5_hash, + 'is_external': is_external, + 'dist_type': 'sdist'} + + +def split_archive_name(archive_name, probable_name=None): + """Split an archive name into two parts: name and version. + + Return the tuple (name, version) + """ + # Try to determine wich part is the name and wich is the version using the + # "-" separator. Take the larger part to be the version number then reduce + # if this not works. + def eager_split(str, maxsplit=2): + # split using the "-" separator + splits = str.rsplit("-", maxsplit) + name = splits[0] + version = "-".join(splits[1:]) + if version.startswith("-"): + version = version[1:] + if suggest_normalized_version(version) is None and maxsplit >= 0: + # we dont get a good version number: recurse ! + return eager_split(str, maxsplit - 1) + else: + return name, version + if probable_name is not None: + probable_name = probable_name.lower() + name = None + if probable_name is not None and probable_name in archive_name: + # we get the name from probable_name, if given. + name = probable_name + version = archive_name.lstrip(name) + else: + name, version = eager_split(archive_name) + + version = suggest_normalized_version(version) + if version is not None and name != "": + return name.lower(), version + else: + raise CantParseArchiveName(archive_name) diff --git a/Lib/packaging/pypi/errors.py b/Lib/packaging/pypi/errors.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/pypi/errors.py @@ -0,0 +1,39 @@ +"""Exceptions raised by packaging.pypi code.""" + +from packaging.errors import PackagingPyPIError + + +class ProjectNotFound(PackagingPyPIError): + """Project has not been found""" + + +class DistributionNotFound(PackagingPyPIError): + """The release has not been found""" + + +class ReleaseNotFound(PackagingPyPIError): + """The release has not been found""" + + +class CantParseArchiveName(PackagingPyPIError): + """An archive name can't be parsed to find distribution name and version""" + + +class DownloadError(PackagingPyPIError): + """An error has occurs while downloading""" + + +class HashDoesNotMatch(DownloadError): + """Compared hashes does not match""" + + +class UnsupportedHashName(PackagingPyPIError): + """A unsupported hashname has been used""" + + +class UnableToDownload(PackagingPyPIError): + """All mirrors have been tried, without success""" + + +class InvalidSearchField(PackagingPyPIError): + """An invalid search field has been used""" diff --git a/Lib/packaging/pypi/mirrors.py b/Lib/packaging/pypi/mirrors.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/pypi/mirrors.py @@ -0,0 +1,52 @@ +"""Utilities related to the mirror infrastructure defined in PEP 381.""" + +from string import ascii_lowercase +import socket + +DEFAULT_MIRROR_URL = "last.pypi.python.org" + + +def get_mirrors(hostname=None): + """Return the list of mirrors from the last record found on the DNS + entry:: + + >>> from packaging.pypi.mirrors import get_mirrors + >>> get_mirrors() + ['a.pypi.python.org', 'b.pypi.python.org', 'c.pypi.python.org', + 'd.pypi.python.org'] + + """ + if hostname is None: + hostname = DEFAULT_MIRROR_URL + + # return the last mirror registered on PyPI. + try: + hostname = socket.gethostbyname_ex(hostname)[0] + except socket.gaierror: + return [] + end_letter = hostname.split(".", 1) + + # determine the list from the last one. + return ["%s.%s" % (s, end_letter[1]) for s in string_range(end_letter[0])] + + +def string_range(last): + """Compute the range of string between "a" and last. + + This works for simple "a to z" lists, but also for "a to zz" lists. + """ + for k in range(len(last)): + for x in product(ascii_lowercase, repeat=(k + 1)): + result = ''.join(x) + yield result + if result == last: + return + + +def product(*args, **kwds): + pools = [tuple(arg) for arg in args] * kwds.get('repeat', 1) + result = [[]] + for pool in pools: + result = [x + [y] for x in result for y in pool] + for prod in result: + yield tuple(prod) diff --git a/Lib/packaging/pypi/simple.py b/Lib/packaging/pypi/simple.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/pypi/simple.py @@ -0,0 +1,452 @@ +"""Spider using the screen-scraping "simple" PyPI API. + +This module contains the class SimpleIndexCrawler, a simple spider that +can be used to find and retrieve distributions from a project index +(like the Python Package Index), using its so-called simple API (see +reference implementation available at http://pypi.python.org/simple/). +""" + +import http.client +import re +import socket +import sys +import urllib.request +import urllib.parse +import urllib.error +import os + + +from fnmatch import translate +from packaging import logger +from packaging.metadata import Metadata +from packaging.version import get_version_predicate +from packaging import __version__ as packaging_version +from packaging.pypi.base import BaseClient +from packaging.pypi.dist import (ReleasesList, EXTENSIONS, + get_infos_from_url, MD5_HASH) +from packaging.pypi.errors import (PackagingPyPIError, DownloadError, + UnableToDownload, CantParseArchiveName, + ReleaseNotFound, ProjectNotFound) +from packaging.pypi.mirrors import get_mirrors +from packaging.metadata import Metadata + +__all__ = ['Crawler', 'DEFAULT_SIMPLE_INDEX_URL'] + +# -- Constants ----------------------------------------------- +DEFAULT_SIMPLE_INDEX_URL = "http://a.pypi.python.org/simple/" +DEFAULT_HOSTS = ("*",) +SOCKET_TIMEOUT = 15 +USER_AGENT = "Python-urllib/%s packaging/%s" % ( + sys.version[:3], packaging_version) + +# -- Regexps ------------------------------------------------- +EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$') +HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I) +URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):', re.I).match + +# This pattern matches a character entity reference (a decimal numeric +# references, a hexadecimal numeric reference, or a named reference). +ENTITY_SUB = re.compile(r'&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?').sub +REL = re.compile("""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I) + + +def socket_timeout(timeout=SOCKET_TIMEOUT): + """Decorator to add a socket timeout when requesting pages on PyPI. + """ + def _socket_timeout(func): + def _socket_timeout(self, *args, **kwargs): + old_timeout = socket.getdefaulttimeout() + if hasattr(self, "_timeout"): + timeout = self._timeout + socket.setdefaulttimeout(timeout) + try: + return func(self, *args, **kwargs) + finally: + socket.setdefaulttimeout(old_timeout) + return _socket_timeout + return _socket_timeout + + +def with_mirror_support(): + """Decorator that makes the mirroring support easier""" + def wrapper(func): + def wrapped(self, *args, **kwargs): + try: + return func(self, *args, **kwargs) + except DownloadError: + # if an error occurs, try with the next index_url + if self._mirrors_tries >= self._mirrors_max_tries: + try: + self._switch_to_next_mirror() + except KeyError: + raise UnableToDownload("Tried all mirrors") + else: + self._mirrors_tries += 1 + self._projects.clear() + return wrapped(self, *args, **kwargs) + return wrapped + return wrapper + + +class Crawler(BaseClient): + """Provides useful tools to request the Python Package Index simple API. + + You can specify both mirrors and mirrors_url, but mirrors_url will only be + used if mirrors is set to None. + + :param index_url: the url of the simple index to search on. + :param prefer_final: if the version is not mentioned, and the last + version is not a "final" one (alpha, beta, etc.), + pick up the last final version. + :param prefer_source: if the distribution type is not mentioned, pick up + the source one if available. + :param follow_externals: tell if following external links is needed or + not. Default is False. + :param hosts: a list of hosts allowed to be processed while using + follow_externals=True. Default behavior is to follow all + hosts. + :param follow_externals: tell if following external links is needed or + not. Default is False. + :param mirrors_url: the url to look on for DNS records giving mirror + adresses. + :param mirrors: a list of mirrors (see PEP 381). + :param timeout: time in seconds to consider a url has timeouted. + :param mirrors_max_tries": number of times to try requesting informations + on mirrors before switching. + """ + + def __init__(self, index_url=DEFAULT_SIMPLE_INDEX_URL, prefer_final=False, + prefer_source=True, hosts=DEFAULT_HOSTS, + follow_externals=False, mirrors_url=None, mirrors=None, + timeout=SOCKET_TIMEOUT, mirrors_max_tries=0): + super(Crawler, self).__init__(prefer_final, prefer_source) + self.follow_externals = follow_externals + + # mirroring attributes. + if not index_url.endswith("/"): + index_url += "/" + # if no mirrors are defined, use the method described in PEP 381. + if mirrors is None: + mirrors = get_mirrors(mirrors_url) + self._mirrors = set(mirrors) + self._mirrors_used = set() + self.index_url = index_url + self._mirrors_max_tries = mirrors_max_tries + self._mirrors_tries = 0 + self._timeout = timeout + + # create a regexp to match all given hosts + self._allowed_hosts = re.compile('|'.join(map(translate, hosts))).match + + # we keep an index of pages we have processed, in order to avoid + # scanning them multple time (eg. if there is multiple pages pointing + # on one) + self._processed_urls = [] + self._projects = {} + + @with_mirror_support() + def search_projects(self, name=None, **kwargs): + """Search the index for projects containing the given name. + + Return a list of names. + """ + with self._open_url(self.index_url) as index: + if '*' in name: + name.replace('*', '.*') + else: + name = "%s%s%s" % ('*.?', name, '*.?') + name = name.replace('*', '[^<]*') # avoid matching end tag + projectname = re.compile(']*>(%s)' % name, re.I) + matching_projects = [] + + index_content = index.read() + + # FIXME should use bytes I/O and regexes instead of decoding + index_content = index_content.decode() + + for match in projectname.finditer(index_content): + project_name = match.group(1) + matching_projects.append(self._get_project(project_name)) + return matching_projects + + def get_releases(self, requirements, prefer_final=None, + force_update=False): + """Search for releases and return a ReleaseList object containing + the results. + """ + predicate = get_version_predicate(requirements) + 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: + raise ProjectNotFound() + + releases = self._projects.get(predicate.name.lower()) + releases.sort_releases(prefer_final=prefer_final) + return releases + + def get_release(self, requirements, prefer_final=None): + """Return only one release that fulfill the given requirements""" + predicate = get_version_predicate(requirements) + release = self.get_releases(predicate, prefer_final)\ + .get_last(predicate) + if not release: + raise ReleaseNotFound("No release matches the given criterias") + return release + + def get_distributions(self, project_name, version): + """Return the distributions found on the index for the specific given + release""" + # as the default behavior of get_release is to return a release + # containing the distributions, just alias it. + return self.get_release("%s (%s)" % (project_name, version)) + + def get_metadata(self, project_name, version): + """Return the metadatas from the simple index. + + Currently, download one archive, extract it and use the PKG-INFO file. + """ + release = self.get_distributions(project_name, version) + if not release.metadata: + location = release.get_distribution().unpack() + pkg_info = os.path.join(location, 'PKG-INFO') + release.metadata = Metadata(pkg_info) + return release + + def _switch_to_next_mirror(self): + """Switch to the next mirror (eg. point self.index_url to the next + mirror url. + + Raise a KeyError if all mirrors have been tried. + """ + self._mirrors_used.add(self.index_url) + index_url = self._mirrors.pop() + if not ("http://" or "https://" or "file://") in index_url: + index_url = "http://%s" % index_url + + if not index_url.endswith("/simple"): + index_url = "%s/simple/" % index_url + + self.index_url = index_url + + def _is_browsable(self, url): + """Tell if the given URL can be browsed or not. + + It uses the follow_externals and the hosts list to tell if the given + url is browsable or not. + """ + # if _index_url is contained in the given URL, we are browsing the + # index, and it's always "browsable". + # local files are always considered browable resources + if self.index_url in url or urllib.parse.urlparse(url)[0] == "file": + return True + elif self.follow_externals: + if self._allowed_hosts(urllib.parse.urlparse(url)[1]): # 1 is netloc + return True + else: + return False + return False + + def _is_distribution(self, link): + """Tell if the given URL matches to a distribution name or not. + """ + #XXX find a better way to check that links are distributions + # Using a regexp ? + for ext in EXTENSIONS: + if ext in link: + return True + return False + + def _register_release(self, release=None, release_info={}): + """Register a new release. + + Both a release or a dict of release_info can be provided, the prefered + way (eg. the quicker) is the dict one. + + Return the list of existing releases for the given project. + """ + # Check if the project already has a list of releases (refering to + # the project name). If not, create a new release list. + # Then, add the release to the list. + if release: + name = release.name + else: + name = release_info['name'] + if not name.lower() in self._projects: + self._projects[name.lower()] = ReleasesList(name, index=self._index) + + if release: + self._projects[name.lower()].add_release(release=release) + else: + name = release_info.pop('name') + version = release_info.pop('version') + dist_type = release_info.pop('dist_type') + self._projects[name.lower()].add_release(version, dist_type, + **release_info) + return self._projects[name.lower()] + + def _process_url(self, url, project_name=None, follow_links=True): + """Process an url and search for distributions packages. + + For each URL found, if it's a download, creates a PyPIdistribution + object. If it's a homepage and we can follow links, process it too. + + :param url: the url to process + :param project_name: the project name we are searching for. + :param follow_links: Do not want to follow links more than from one + level. This parameter tells if we want to follow + the links we find (eg. run recursively this + method on it) + """ + with self._open_url(url) as f: + base_url = f.url + if url not in self._processed_urls: + self._processed_urls.append(url) + link_matcher = self._get_link_matcher(url) + for link, is_download in link_matcher(f.read().decode(), base_url): + if link not in self._processed_urls: + if self._is_distribution(link) or is_download: + self._processed_urls.append(link) + # it's a distribution, so create a dist object + try: + infos = get_infos_from_url(link, project_name, + is_external=not self.index_url in url) + except CantParseArchiveName as e: + logger.warning( + "version has not been parsed: %s", e) + else: + self._register_release(release_info=infos) + else: + if self._is_browsable(link) and follow_links: + self._process_url(link, project_name, + follow_links=False) + + def _get_link_matcher(self, url): + """Returns the right link matcher function of the given url + """ + if self.index_url in url: + return self._simple_link_matcher + else: + return self._default_link_matcher + + def _get_full_url(self, url, base_url): + return urllib.parse.urljoin(base_url, self._htmldecode(url)) + + def _simple_link_matcher(self, content, base_url): + """Yield all links with a rel="download" or rel="homepage". + + This matches the simple index requirements for matching links. + If follow_externals is set to False, dont yeld the external + urls. + + :param content: the content of the page we want to parse + :param base_url: the url of this page. + """ + for match in HREF.finditer(content): + url = self._get_full_url(match.group(1), base_url) + if MD5_HASH.match(url): + yield (url, True) + + for match in REL.finditer(content): + # search for rel links. + tag, rel = match.groups() + rels = [s.strip() for s in rel.lower().split(',')] + if 'homepage' in rels or 'download' in rels: + for match in HREF.finditer(tag): + url = self._get_full_url(match.group(1), base_url) + if 'download' in rels or self._is_browsable(url): + # yield a list of (url, is_download) + yield (url, 'download' in rels) + + def _default_link_matcher(self, content, base_url): + """Yield all links found on the page. + """ + for match in HREF.finditer(content): + url = self._get_full_url(match.group(1), base_url) + if self._is_browsable(url): + yield (url, False) + + @with_mirror_support() + def _process_index_page(self, name): + """Find and process a PyPI page for the given project name. + + :param name: the name of the project to find the page + """ + # Browse and index the content of the given PyPI page. + url = self.index_url + name + "/" + self._process_url(url, name) + + @socket_timeout() + def _open_url(self, url): + """Open a urllib2 request, handling HTTP authentication, and local + files support. + + """ + scheme, netloc, path, params, query, frag = urllib.parse.urlparse(url) + + # authentication stuff + if scheme in ('http', 'https'): + auth, host = urllib.parse.splituser(netloc) + else: + auth = None + + # add index.html automatically for filesystem paths + if scheme == 'file': + if url.endswith('/'): + url += "index.html" + + # add authorization headers if auth is provided + if auth: + auth = "Basic " + \ + urllib.parse.unquote(auth).encode('base64').strip() + new_url = urllib.parse.urlunparse(( + scheme, host, path, params, query, frag)) + request = urllib.request.Request(new_url) + request.add_header("Authorization", auth) + else: + request = urllib.request.Request(url) + request.add_header('User-Agent', USER_AGENT) + try: + fp = urllib.request.urlopen(request) + except (ValueError, http.client.InvalidURL) as v: + msg = ' '.join([str(arg) for arg in v.args]) + raise PackagingPyPIError('%s %s' % (url, msg)) + except urllib.error.HTTPError as v: + return v + except urllib.error.URLError as v: + raise DownloadError("Download error for %s: %s" % (url, v.reason)) + except http.client.BadStatusLine as v: + raise DownloadError('%s returned a bad status line. ' + 'The server might be down, %s' % (url, v.line)) + except http.client.HTTPException as v: + raise DownloadError("Download error for %s: %s" % (url, v)) + except socket.timeout: + raise DownloadError("The server timeouted") + + if auth: + # Put authentication info back into request URL if same host, + # so that links found on the page will work + s2, h2, path2, param2, query2, frag2 = \ + urllib.parse.urlparse(fp.url) + if s2 == scheme and h2 == host: + fp.url = urllib.parse.urlunparse( + (s2, netloc, path2, param2, query2, frag2)) + return fp + + def _decode_entity(self, match): + what = match.group(1) + if what.startswith('#x'): + what = int(what[2:], 16) + elif what.startswith('#'): + what = int(what[1:]) + else: + from html.entities import name2codepoint + what = name2codepoint.get(what, match.group(0)) + return chr(what) + + def _htmldecode(self, text): + """Decode HTML entities in the given text.""" + return ENTITY_SUB(self._decode_entity, text) diff --git a/Lib/packaging/pypi/wrapper.py b/Lib/packaging/pypi/wrapper.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/pypi/wrapper.py @@ -0,0 +1,99 @@ +"""Convenient client for all PyPI APIs. + +This module provides a ClientWrapper class which will use the "simple" +or XML-RPC API to request information or files from an index. +""" + +from packaging.pypi import simple, xmlrpc + +_WRAPPER_MAPPINGS = {'get_release': 'simple', + 'get_releases': 'simple', + 'search_projects': 'simple', + 'get_metadata': 'xmlrpc', + 'get_distributions': 'simple'} + +_WRAPPER_INDEXES = {'xmlrpc': xmlrpc.Client, + 'simple': simple.Crawler} + + +def switch_index_if_fails(func, wrapper): + """Decorator that switch of index (for instance from xmlrpc to simple) + if the first mirror return an empty list or raises an exception. + """ + def decorator(*args, **kwargs): + retry = True + exception = None + methods = [func] + for f in wrapper._indexes.values(): + if f != func.__self__ and hasattr(f, func.__name__): + methods.append(getattr(f, func.__name__)) + for method in methods: + try: + response = method(*args, **kwargs) + retry = False + except Exception as e: + exception = e + if not retry: + break + if retry and exception: + raise exception + else: + return response + return decorator + + +class ClientWrapper: + """Wrapper around simple and xmlrpc clients, + + Choose the best implementation to use depending the needs, using the given + mappings. + If one of the indexes returns an error, tries to use others indexes. + + :param index: tell which index to rely on by default. + :param index_classes: a dict of name:class to use as indexes. + :param indexes: a dict of name:index already instantiated + :param mappings: the mappings to use for this wrapper + """ + + def __init__(self, default_index='simple', index_classes=_WRAPPER_INDEXES, + indexes={}, mappings=_WRAPPER_MAPPINGS): + self._projects = {} + self._mappings = mappings + self._indexes = indexes + self._default_index = default_index + + # instantiate the classes and set their _project attribute to the one + # of the wrapper. + for name, cls in index_classes.items(): + obj = self._indexes.setdefault(name, cls()) + obj._projects = self._projects + obj._index = self + + def __getattr__(self, method_name): + """When asking for methods of the wrapper, return the implementation of + the wrapped classes, depending the mapping. + + Decorate the methods to switch of implementation if an error occurs + """ + real_method = None + if method_name in _WRAPPER_MAPPINGS: + obj = self._indexes[_WRAPPER_MAPPINGS[method_name]] + real_method = getattr(obj, method_name) + else: + # the method is not defined in the mappings, so we try first to get + # it via the default index, and rely on others if needed. + try: + real_method = getattr(self._indexes[self._default_index], + method_name) + except AttributeError: + other_indexes = [i for i in self._indexes + if i != self._default_index] + for index in other_indexes: + real_method = getattr(self._indexes[index], method_name, + None) + if real_method: + break + if real_method: + return switch_index_if_fails(real_method, self) + else: + raise AttributeError("No index have attribute '%s'" % method_name) diff --git a/Lib/packaging/pypi/xmlrpc.py b/Lib/packaging/pypi/xmlrpc.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/pypi/xmlrpc.py @@ -0,0 +1,200 @@ +"""Spider using the XML-RPC PyPI API. + +This module contains the class Client, a spider that can be used to find +and retrieve distributions from a project index (like the Python Package +Index), using its XML-RPC API (see documentation of the reference +implementation at http://wiki.python.org/moin/PyPiXmlRpc). +""" + +import xmlrpc.client + +from packaging import logger +from packaging.errors import IrrationalVersionError +from packaging.version import get_version_predicate +from packaging.pypi.base import BaseClient +from packaging.pypi.errors import (ProjectNotFound, InvalidSearchField, + ReleaseNotFound) +from packaging.pypi.dist import ReleaseInfo + +__all__ = ['Client', 'DEFAULT_XMLRPC_INDEX_URL'] + +DEFAULT_XMLRPC_INDEX_URL = 'http://python.org/pypi' + +_SEARCH_FIELDS = ['name', 'version', 'author', 'author_email', 'maintainer', + 'maintainer_email', 'home_page', 'license', 'summary', + 'description', 'keywords', 'platform', 'download_url'] + + +class Client(BaseClient): + """Client to query indexes using XML-RPC method calls. + + If no server_url is specified, use the default PyPI XML-RPC URL, + defined in the DEFAULT_XMLRPC_INDEX_URL constant:: + + >>> client = XMLRPCClient() + >>> client.server_url == DEFAULT_XMLRPC_INDEX_URL + True + + >>> client = XMLRPCClient("http://someurl/") + >>> client.server_url + 'http://someurl/' + """ + + def __init__(self, server_url=DEFAULT_XMLRPC_INDEX_URL, prefer_final=False, + prefer_source=True): + super(Client, self).__init__(prefer_final, prefer_source) + self.server_url = server_url + self._projects = {} + + def get_release(self, requirements, prefer_final=False): + """Return a release with all complete metadata and distribution + related informations. + """ + prefer_final = self._get_prefer_final(prefer_final) + predicate = get_version_predicate(requirements) + releases = self.get_releases(predicate.name) + release = releases.get_last(predicate, prefer_final) + self.get_metadata(release.name, str(release.version)) + self.get_distributions(release.name, str(release.version)) + return release + + def get_releases(self, requirements, prefer_final=None, show_hidden=True, + force_update=False): + """Return the list of existing releases for a specific project. + + Cache the results from one call to another. + + If show_hidden is True, return the hidden releases too. + If force_update is True, reprocess the index to update the + informations (eg. make a new XML-RPC call). + :: + + >>> client = XMLRPCClient() + >>> client.get_releases('Foo') + ['1.1', '1.2', '1.3'] + + If no such project exists, raise a ProjectNotFound exception:: + + >>> client.get_project_versions('UnexistingProject') + ProjectNotFound: UnexistingProject + + """ + def get_versions(project_name, show_hidden): + return self.proxy.package_releases(project_name, show_hidden) + + predicate = get_version_predicate(requirements) + prefer_final = self._get_prefer_final(prefer_final) + project_name = predicate.name + if not force_update and (project_name.lower() in self._projects): + project = self._projects[project_name.lower()] + if not project.contains_hidden and show_hidden: + # if hidden releases are requested, and have an existing + # list of releases that does not contains hidden ones + all_versions = get_versions(project_name, show_hidden) + existing_versions = project.get_versions() + hidden_versions = set(all_versions) - set(existing_versions) + for version in hidden_versions: + project.add_release(release=ReleaseInfo(project_name, + version, index=self._index)) + else: + versions = get_versions(project_name, show_hidden) + if not versions: + raise ProjectNotFound(project_name) + project = self._get_project(project_name) + project.add_releases([ReleaseInfo(project_name, version, + index=self._index) + for version in versions]) + project = project.filter(predicate) + if len(project) == 0: + raise ReleaseNotFound("%s" % predicate) + project.sort_releases(prefer_final) + return project + + + def get_distributions(self, project_name, version): + """Grab informations about distributions from XML-RPC. + + Return a ReleaseInfo object, with distribution-related informations + filled in. + """ + url_infos = self.proxy.release_urls(project_name, version) + project = self._get_project(project_name) + if version not in project.get_versions(): + project.add_release(release=ReleaseInfo(project_name, version, + index=self._index)) + release = project.get_release(version) + for info in url_infos: + packagetype = info['packagetype'] + dist_infos = {'url': info['url'], + 'hashval': info['md5_digest'], + 'hashname': 'md5', + 'is_external': False, + 'python_version': info['python_version']} + release.add_distribution(packagetype, **dist_infos) + return release + + def get_metadata(self, project_name, version): + """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(): + project.add_release(release=ReleaseInfo(project_name, version, + index=self._index)) + release = project.get_release(version) + release.set_metadata(metadata) + return release + + def search_projects(self, name=None, operator="or", **kwargs): + """Find using the keys provided in kwargs. + + You can set operator to "and" or "or". + """ + for key in kwargs: + if key not in _SEARCH_FIELDS: + raise InvalidSearchField(key) + if name: + kwargs["name"] = name + projects = self.proxy.search(kwargs, operator) + for p in projects: + project = self._get_project(p['name']) + try: + project.add_release(release=ReleaseInfo(p['name'], + p['version'], metadata={'summary': p['summary']}, + index=self._index)) + except IrrationalVersionError as e: + logger.warning("Irrational version error found: %s", e) + return [self._projects[p['name'].lower()] for p in projects] + + def get_all_projects(self): + """Return the list of all projects registered in the package index""" + projects = self.proxy.list_packages() + for name in projects: + self.get_releases(name, show_hidden=True) + + return [self._projects[name.lower()] for name in set(projects)] + + @property + def proxy(self): + """Property used to return the XMLRPC server proxy. + + If no server proxy is defined yet, creates a new one:: + + >>> client = XmlRpcClient() + >>> client.proxy() + + + """ + if not hasattr(self, '_server_proxy'): + self._server_proxy = xmlrpc.client.ServerProxy(self.server_url) + + return self._server_proxy diff --git a/Lib/packaging/resources.py b/Lib/packaging/resources.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/resources.py @@ -0,0 +1,25 @@ +"""Data file path abstraction. + +Functions in this module use sysconfig to find the paths to the resource +files registered in project's setup.cfg file. See the documentation for +more information. +""" +# TODO write that documentation + +from packaging.database import get_distribution + +__all__ = ['get_file_path', 'get_file'] + + +def get_file_path(distribution_name, relative_path): + """Return the path to a resource file.""" + dist = get_distribution(distribution_name) + if dist != None: + return dist.get_resource_path(relative_path) + raise LookupError('no distribution named %r found' % distribution_name) + + +def get_file(distribution_name, relative_path, *args, **kwargs): + """Open and return a resource file.""" + return open(get_file_path(distribution_name, relative_path), + *args, **kwargs) diff --git a/Lib/packaging/run.py b/Lib/packaging/run.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/run.py @@ -0,0 +1,645 @@ +"""Main command line parser. Implements the pysetup script.""" + +import os +import re +import sys +import getopt +import logging + +from packaging import logger +from packaging.dist import Distribution +from packaging.util import _is_archive_file +from packaging.command import get_command_class, STANDARD_COMMANDS +from packaging.install import install, install_local_project, remove +from packaging.database import get_distribution, get_distributions +from packaging.depgraph import generate_graph +from packaging.fancy_getopt import FancyGetopt +from packaging.errors import (PackagingArgError, PackagingError, + PackagingModuleError, PackagingClassError, + CCompilerError) + + +command_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$') + +common_usage = """\ +Actions: +%(actions)s + +To get more help on an action, use: + + pysetup action --help +""" + +create_usage = """\ +Usage: pysetup create + or: pysetup create --help + +Create a new Python package. +""" + +graph_usage = """\ +Usage: pysetup graph dist + or: pysetup graph --help + +Print dependency graph for the distribution. + +positional arguments: + dist installed distribution name +""" + +install_usage = """\ +Usage: pysetup install [dist] + or: pysetup install [archive] + or: pysetup install [src_dir] + or: pysetup install --help + +Install a Python distribution from the indexes, source directory, or sdist. + +positional arguments: + archive path to source distribution (zip, tar.gz) + dist distribution name to install from the indexes + scr_dir path to source directory + +""" + +metadata_usage = """\ +Usage: pysetup metadata [dist] [-f field ...] + or: pysetup metadata [dist] [--all] + or: pysetup metadata --help + +Print metadata for the distribution. + +positional arguments: + dist installed distribution name + +optional arguments: + -f metadata field to print + --all print all metadata fields +""" + +remove_usage = """\ +Usage: pysetup remove dist [-y] + or: pysetup remove --help + +Uninstall a Python distribution. + +positional arguments: + dist installed distribution name + +optional arguments: + -y auto confirm package removal +""" + +run_usage = """\ +Usage: pysetup run [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] + or: pysetup run --help + or: pysetup run --list-commands + or: pysetup run cmd --help +""" + +list_usage = """\ +Usage: pysetup list dist [dist ...] + or: pysetup list --help + or: pysetup list --all + +Print name, version and location for the matching installed distributions. + +positional arguments: + dist installed distribution name + +optional arguments: + --all list all installed distributions +""" + +search_usage = """\ +Usage: pysetup search [project] [--simple [url]] [--xmlrpc [url] [--fieldname value ...] --operator or|and] + or: pysetup search --help + +Search the indexes for the matching projects. + +positional arguments: + project the project pattern to search for + +optional arguments: + --xmlrpc [url] wether to use the xmlrpc index or not. If an url is + specified, it will be used rather than the default one. + + --simple [url] wether to use the simple index or not. If an url is + specified, it will be used rather than the default one. + + --fieldname value Make a search on this field. Can only be used if + --xmlrpc has been selected or is the default index. + + --operator or|and Defines what is the operator to use when doing xmlrpc + searchs with multiple fieldnames. Can only be used if + --xmlrpc has been selected or is the default index. +""" + +global_options = [ + # The fourth entry for verbose means that it can be repeated. + ('verbose', 'v', "run verbosely (default)", True), + ('quiet', 'q', "run quietly (turns verbosity off)"), + ('dry-run', 'n', "don't actually do anything"), + ('help', 'h', "show detailed help message"), + ('no-user-cfg', None, 'ignore pydistutils.cfg in your home directory'), + ('version', None, 'Display the version'), +] + +negative_opt = {'quiet': 'verbose'} + +display_options = [ + ('help-commands', None, "list all available commands"), +] + +display_option_names = [x[0].replace('-', '_') for x in display_options] + + +def _parse_args(args, options, long_options): + """Transform sys.argv input into a dict. + + :param args: the args to parse (i.e sys.argv) + :param options: the list of options to pass to getopt + :param long_options: the list of string with the names of the long options + to be passed to getopt. + + The function returns a dict with options/long_options as keys and matching + values as values. + """ + optlist, args = getopt.gnu_getopt(args, options, long_options) + optdict = {} + optdict['args'] = args + for k, v in optlist: + k = k.lstrip('-') + if k not in optdict: + optdict[k] = [] + if v: + optdict[k].append(v) + else: + optdict[k].append(v) + return optdict + + +class action_help: + """Prints a help message when the standard help flags: -h and --help + are used on the commandline. + """ + + def __init__(self, help_msg): + self.help_msg = help_msg + + def __call__(self, f): + def wrapper(*args, **kwargs): + f_args = args[1] + if '--help' in f_args or '-h' in f_args: + print(self.help_msg) + return + return f(*args, **kwargs) + return wrapper + + + at action_help(create_usage) +def _create(distpatcher, args, **kw): + from packaging.create import main + return main() + + + at action_help(graph_usage) +def _graph(dispatcher, args, **kw): + name = args[1] + dist = get_distribution(name, use_egg_info=True) + if dist is None: + print('Distribution not found.') + else: + dists = get_distributions(use_egg_info=True) + graph = generate_graph(dists) + print(graph.repr_node(dist)) + + + at action_help(install_usage) +def _install(dispatcher, args, **kw): + # first check if we are in a source directory + if len(args) < 2: + # are we inside a project dir? + listing = os.listdir(os.getcwd()) + if 'setup.py' in listing or 'setup.cfg' in listing: + args.insert(1, os.getcwd()) + else: + logger.warning('no project to install') + return + + # installing from a source dir or archive file? + if os.path.isdir(args[1]) or _is_archive_file(args[1]): + install_local_project(args[1]) + else: + # download from PyPI + install(args[1]) + + + at action_help(metadata_usage) +def _metadata(dispatcher, args, **kw): + opts = _parse_args(args[1:], 'f:', ['all']) + if opts['args']: + name = opts['args'][0] + dist = get_distribution(name, use_egg_info=True) + if dist is None: + logger.warning('%s not installed', name) + return + else: + logger.info('searching local dir for metadata') + dist = Distribution() + dist.parse_config_files() + + metadata = dist.metadata + + if 'all' in opts: + keys = metadata.keys() + else: + if 'f' in opts: + keys = (k for k in opts['f'] if k in metadata) + else: + keys = () + + 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 ')) + + + at action_help(remove_usage) +def _remove(distpatcher, args, **kw): + opts = _parse_args(args[1:], 'y', []) + if 'y' in opts: + auto_confirm = True + else: + auto_confirm = False + + for dist in set(opts['args']): + try: + remove(dist, auto_confirm=auto_confirm) + except PackagingError: + logger.warning('%s not installed', dist) + + + at action_help(run_usage) +def _run(dispatcher, args, **kw): + parser = dispatcher.parser + args = args[1:] + + commands = STANDARD_COMMANDS # + extra commands + + if args == ['--list-commands']: + print('List of available commands:') + cmds = sorted(commands) + + for cmd in cmds: + cls = dispatcher.cmdclass.get(cmd) or get_command_class(cmd) + desc = getattr(cls, 'description', + '(no description available)') + print(' %s: %s' % (cmd, desc)) + return + + while args: + args = dispatcher._parse_command_opts(parser, args) + if args is None: + return + + # create the Distribution class + # need to feed setup.cfg here ! + dist = Distribution() + + # Find and parse the config file(s): they will override options from + # the setup script, but be overridden by the command line. + + # XXX still need to be extracted from Distribution + dist.parse_config_files() + + try: + for cmd in dispatcher.commands: + dist.run_command(cmd, dispatcher.command_options[cmd]) + + except KeyboardInterrupt: + raise SystemExit("interrupted") + except (IOError, os.error, PackagingError, CCompilerError) as msg: + raise SystemExit("error: " + str(msg)) + + # XXX this is crappy + return dist + + + at action_help(list_usage) +def _list(dispatcher, args, **kw): + opts = _parse_args(args[1:], '', ['all']) + dists = get_distributions(use_egg_info=True) + if 'all' in opts: + results = dists + else: + results = [d for d in dists if d.name.lower() in opts['args']] + + for dist in results: + print('%s %s at %s' % (dist.name, dist.metadata['version'], dist.path)) + + + at action_help(search_usage) +def _search(dispatcher, args, **kw): + """The search action. + + It is able to search for a specific index (specified with --index), using + the simple or xmlrpc index types (with --type xmlrpc / --type simple) + """ + opts = _parse_args(args[1:], '', ['simple', 'xmlrpc']) + # 1. what kind of index is requested ? (xmlrpc / simple) + + +actions = [ + ('run', 'Run one or several commands', _run), + ('metadata', 'Display the metadata of a project', _metadata), + ('install', 'Install a project', _install), + ('remove', 'Remove a project', _remove), + ('search', 'Search for a project in the indexes', _search), + ('list', 'Search for local projects', _list), + ('graph', 'Display a graph', _graph), + ('create', 'Create a Project', _create), +] + + +class Dispatcher: + """Reads the command-line options + """ + def __init__(self, args=None): + self.verbose = 1 + self.dry_run = False + self.help = False + self.script_name = 'pysetup' + self.cmdclass = {} + self.commands = [] + self.command_options = {} + + for attr in display_option_names: + setattr(self, attr, False) + + self.parser = FancyGetopt(global_options + display_options) + self.parser.set_negative_aliases(negative_opt) + # FIXME this parses everything, including command options (e.g. "run + # build -i" errors with "option -i not recognized") + args = self.parser.getopt(args=args, object=self) + + # if first arg is "run", we have some commands + if len(args) == 0: + self.action = None + else: + self.action = args[0] + + allowed = [action[0] for action in actions] + [None] + if self.action not in allowed: + msg = 'Unrecognized action "%s"' % self.action + raise PackagingArgError(msg) + + # setting up the logging level from the command-line options + # -q gets warning, error and critical + if self.verbose == 0: + level = logging.WARNING + # default level or -v gets info too + # XXX there's a bug somewhere: the help text says that -v is default + # (and verbose is set to 1 above), but when the user explicitly gives + # -v on the command line, self.verbose is incremented to 2! Here we + # compensate for that (I tested manually). On a related note, I think + # it's a good thing to use -q/nothing/-v/-vv on the command line + # instead of logging constants; it will be easy to add support for + # logging configuration in setup.cfg for advanced users. --merwok + elif self.verbose in (1, 2): + level = logging.INFO + else: # -vv and more for debug + level = logging.DEBUG + + # for display options we return immediately + option_order = self.parser.get_option_order() + + self.args = args + + if self.help or self.action is None: + self._show_help(self.parser, display_options_=False) + + def _parse_command_opts(self, parser, args): + # Pull the current command from the head of the command line + command = args[0] + if not command_re.match(command): + raise SystemExit("invalid command name %r" % (command,)) + self.commands.append(command) + + # Dig up the command class that implements this command, so we + # 1) know that it's a valid command, and 2) know which options + # it takes. + try: + cmd_class = get_command_class(command) + except PackagingModuleError as msg: + raise PackagingArgError(msg) + + # XXX We want to push this in packaging.command + # + # Require that the command class be derived from Command -- want + # to be sure that the basic "command" interface is implemented. + for meth in ('initialize_options', 'finalize_options', 'run'): + if hasattr(cmd_class, meth): + continue + raise PackagingClassError( + 'command %r must implement %r' % (cmd_class, meth)) + + # Also make sure that the command object provides a list of its + # known options. + if not (hasattr(cmd_class, 'user_options') and + isinstance(cmd_class.user_options, list)): + raise PackagingClassError( + "command class %s must provide " + "'user_options' attribute (a list of tuples)" % cmd_class) + + # If the command class has a list of negative alias options, + # merge it in with the global negative aliases. + _negative_opt = negative_opt.copy() + + if hasattr(cmd_class, 'negative_opt'): + _negative_opt.update(cmd_class.negative_opt) + + # Check for help_options in command class. They have a different + # format (tuple of four) so we need to preprocess them here. + if (hasattr(cmd_class, 'help_options') and + isinstance(cmd_class.help_options, list)): + help_options = cmd_class.help_options[:] + else: + help_options = [] + + # All commands support the global options too, just by adding + # in 'global_options'. + parser.set_option_table(global_options + + cmd_class.user_options + + help_options) + parser.set_negative_aliases(_negative_opt) + args, opts = parser.getopt(args[1:]) + + if hasattr(opts, 'help') and opts.help: + self._show_command_help(cmd_class) + return + + if (hasattr(cmd_class, 'help_options') and + isinstance(cmd_class.help_options, list)): + help_option_found = False + for help_option, short, desc, func in cmd_class.help_options: + if hasattr(opts, help_option.replace('-', '_')): + help_option_found = True + if hasattr(func, '__call__'): + func() + else: + raise PackagingClassError( + "invalid help function %r for help option %r: " + "must be a callable object (function, etc.)" + % (func, help_option)) + + if help_option_found: + return + + # Put the options from the command line into their official + # holding pen, the 'command_options' dictionary. + opt_dict = self.get_option_dict(command) + for name, value in vars(opts).items(): + opt_dict[name] = ("command line", value) + + return args + + def get_option_dict(self, command): + """Get the option dictionary for a given command. If that + command's option dictionary hasn't been created yet, then create it + and return the new dictionary; otherwise, return the existing + option dictionary. + """ + d = self.command_options.get(command) + if d is None: + d = self.command_options[command] = {} + return d + + def show_help(self): + self._show_help(self.parser) + + def print_usage(self, parser): + parser.set_option_table(global_options) + + actions_ = [' %s: %s' % (name, desc) for name, desc, __ in actions] + usage = common_usage % {'actions': '\n'.join(actions_)} + + parser.print_help(usage + "\nGlobal options:") + + def _show_help(self, parser, global_options_=True, display_options_=True, + commands=[]): + # late import because of mutual dependence between these modules + from packaging.command.cmd import Command + + print('Usage: pysetup [options] action [action_options]') + print('') + if global_options_: + self.print_usage(self.parser) + print('') + + if display_options_: + parser.set_option_table(display_options) + parser.print_help( + "Information display options (just display " + + "information, ignore any commands)") + print('') + + for command in commands: + if isinstance(command, type) and issubclass(command, Command): + cls = command + else: + cls = get_command_class(command) + if (hasattr(cls, 'help_options') and + isinstance(cls.help_options, list)): + parser.set_option_table(cls.user_options + cls.help_options) + else: + parser.set_option_table(cls.user_options) + + parser.print_help("Options for %r command:" % cls.__name__) + print('') + + def _show_command_help(self, command): + if isinstance(command, str): + command = get_command_class(command) + + name = command.get_command_name() + + desc = getattr(command, 'description', '(no description available)') + print('Description: %s' % desc) + print('') + + if (hasattr(command, 'help_options') and + isinstance(command.help_options, list)): + self.parser.set_option_table(command.user_options + + command.help_options) + else: + self.parser.set_option_table(command.user_options) + + self.parser.print_help("Options:") + print('') + + def _get_command_groups(self): + """Helper function to retrieve all the command class names divided + into standard commands (listed in + packaging.command.STANDARD_COMMANDS) and extra commands (given in + self.cmdclass and not standard commands). + """ + extra_commands = [cmd for cmd in self.cmdclass + if cmd not in STANDARD_COMMANDS] + return STANDARD_COMMANDS, extra_commands + + def print_commands(self): + """Print out a help message listing all available commands with a + description of each. The list is divided into standard commands + (listed in packaging.command.STANDARD_COMMANDS) and extra commands + (given in self.cmdclass and not standard commands). The + descriptions come from the command class attribute + 'description'. + """ + std_commands, extra_commands = self._get_command_groups() + max_length = max(len(command) + for commands in (std_commands, extra_commands) + for command in commands) + + self.print_command_list(std_commands, "Standard commands", max_length) + if extra_commands: + print() + self.print_command_list(extra_commands, "Extra commands", + max_length) + + def print_command_list(self, commands, header, max_length): + """Print a subset of the list of all commands -- used by + 'print_commands()'. + """ + print(header + ":") + + for cmd in commands: + cls = self.cmdclass.get(cmd) or get_command_class(cmd) + description = getattr(cls, 'description', + '(no description available)') + + print(" %-*s %s" % (max_length, cmd, description)) + + def __call__(self): + if self.action is None: + return + for action, desc, func in actions: + if action == self.action: + return func(self, self.args) + return -1 + + +def main(args=None): + dispatcher = Dispatcher(args) + if dispatcher.action is None: + return + + return dispatcher() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/Lib/packaging/tests/LONG_DESC.txt b/Lib/packaging/tests/LONG_DESC.txt new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/LONG_DESC.txt @@ -0,0 +1,44 @@ +CLVault +======= + +CLVault uses Keyring to provide a command-line utility to safely store +and retrieve passwords. + +Install it using pip or the setup.py script:: + + $ python setup.py install + + $ pip install clvault + +Once it's installed, you will have three scripts installed in your +Python scripts folder, you can use to list, store and retrieve passwords:: + + $ clvault-set blog + Set your password: + Set the associated username (can be blank): tarek + Set a description (can be blank): My blog password + Password set. + + $ clvault-get blog + The username is "tarek" + The password has been copied in your clipboard + + $ clvault-list + Registered services: + blog My blog password + + +*clvault-set* takes a service name then prompt you for a password, and some +optional information about your service. The password is safely stored in +a keyring while the description is saved in a ``.clvault`` file in your +home directory. This file is created automatically the first time the command +is used. + +*clvault-get* copies the password for a given service in your clipboard, and +displays the associated user if any. + +*clvault-list* lists all registered services, with their description when +given. + + +Project page: http://bitbucket.org/tarek/clvault diff --git a/Lib/packaging/tests/PKG-INFO b/Lib/packaging/tests/PKG-INFO new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/PKG-INFO @@ -0,0 +1,57 @@ +Metadata-Version: 1.2 +Name: CLVault +Version: 0.5 +Summary: Command-Line utility to store and retrieve passwords +Home-page: http://bitbucket.org/tarek/clvault +Author: Tarek Ziade +Author-email: tarek at ziade.org +License: PSF +Keywords: keyring,password,crypt +Requires-Dist: foo; sys.platform == 'okook' +Requires-Dist: bar; sys.platform == '%s' +Platform: UNKNOWN +Description: CLVault + |======= + | + |CLVault uses Keyring to provide a command-line utility to safely store + |and retrieve passwords. + | + |Install it using pip or the setup.py script:: + | + | $ python setup.py install + | + | $ pip install clvault + | + |Once it's installed, you will have three scripts installed in your + |Python scripts folder, you can use to list, store and retrieve passwords:: + | + | $ clvault-set blog + | Set your password: + | Set the associated username (can be blank): tarek + | Set a description (can be blank): My blog password + | Password set. + | + | $ clvault-get blog + | The username is "tarek" + | The password has been copied in your clipboard + | + | $ clvault-list + | Registered services: + | blog My blog password + | + | + |*clvault-set* takes a service name then prompt you for a password, and some + |optional information about your service. The password is safely stored in + |a keyring while the description is saved in a ``.clvault`` file in your + |home directory. This file is created automatically the first time the command + |is used. + | + |*clvault-get* copies the password for a given service in your clipboard, and + |displays the associated user if any. + | + |*clvault-list* lists all registered services, with their description when + |given. + | + | + |Project page: http://bitbucket.org/tarek/clvault + | diff --git a/Lib/packaging/tests/SETUPTOOLS-PKG-INFO b/Lib/packaging/tests/SETUPTOOLS-PKG-INFO new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/SETUPTOOLS-PKG-INFO @@ -0,0 +1,182 @@ +Metadata-Version: 1.0 +Name: setuptools +Version: 0.6c9 +Summary: Download, build, install, upgrade, and uninstall Python packages -- easily! +Home-page: http://pypi.python.org/pypi/setuptools +Author: Phillip J. Eby +Author-email: distutils-sig at python.org +License: PSF or ZPL +Description: =============================== + Installing and Using Setuptools + =============================== + + .. contents:: **Table of Contents** + + + ------------------------- + Installation Instructions + ------------------------- + + Windows + ======= + + Install setuptools using the provided ``.exe`` installer. If you've previously + installed older versions of setuptools, please delete all ``setuptools*.egg`` + and ``setuptools.pth`` files from your system's ``site-packages`` directory + (and any other ``sys.path`` directories) FIRST. + + If you are upgrading a previous version of setuptools that was installed using + an ``.exe`` installer, please be sure to also *uninstall that older version* + via your system's "Add/Remove Programs" feature, BEFORE installing the newer + version. + + Once installation is complete, you will find an ``easy_install.exe`` program in + your Python ``Scripts`` subdirectory. Be sure to add this directory to your + ``PATH`` environment variable, if you haven't already done so. + + + RPM-Based Systems + ================= + + Install setuptools using the provided source RPM. The included ``.spec`` file + assumes you are installing using the default ``python`` executable, and is not + specific to a particular Python version. The ``easy_install`` executable will + be installed to a system ``bin`` directory such as ``/usr/bin``. + + If you wish to install to a location other than the default Python + installation's default ``site-packages`` directory (and ``$prefix/bin`` for + scripts), please use the ``.egg``-based installation approach described in the + following section. + + + Cygwin, Mac OS X, Linux, Other + ============================== + + 1. Download the appropriate egg for your version of Python (e.g. + ``setuptools-0.6c9-py2.4.egg``). Do NOT rename it. + + 2. Run it as if it were a shell script, e.g. ``sh setuptools-0.6c9-py2.4.egg``. + Setuptools will install itself using the matching version of Python (e.g. + ``python2.4``), and will place the ``easy_install`` executable in the + default location for installing Python scripts (as determined by the + standard distutils configuration files, or by the Python installation). + + If you want to install setuptools to somewhere other than ``site-packages`` or + your default distutils installation locations for libraries and scripts, you + may include EasyInstall command-line options such as ``--prefix``, + ``--install-dir``, and so on, following the ``.egg`` filename on the same + command line. For example:: + + sh setuptools-0.6c9-py2.4.egg --prefix=~ + + You can use ``--help`` to get a full options list, but we recommend consulting + the `EasyInstall manual`_ for detailed instructions, especially `the section + on custom installation locations`_. + + .. _EasyInstall manual: http://peak.telecommunity.com/DevCenter/EasyInstall + .. _the section on custom installation locations: http://peak.telecommunity.com/DevCenter/EasyInstall#custom-installation-locations + + + Cygwin Note + ----------- + + If you are trying to install setuptools for the **Windows** version of Python + (as opposed to the Cygwin version that lives in ``/usr/bin``), you must make + sure that an appropriate executable (``python2.3``, ``python2.4``, or + ``python2.5``) is on your **Cygwin** ``PATH`` when invoking the egg. For + example, doing the following at a Cygwin bash prompt will install setuptools + for the **Windows** Python found at ``C:\\Python24``:: + + ln -s /cygdrive/c/Python24/python.exe python2.4 + PATH=.:$PATH sh setuptools-0.6c9-py2.4.egg + rm python2.4 + + + Downloads + ========= + + All setuptools downloads can be found at `the project's home page in the Python + Package Index`_. Scroll to the very bottom of the page to find the links. + + .. _the project's home page in the Python Package Index: http://pypi.python.org/pypi/setuptools + + In addition to the PyPI downloads, the development version of ``setuptools`` + is available from the `Python SVN sandbox`_, and in-development versions of the + `0.6 branch`_ are available as well. + + .. _0.6 branch: http://svn.python.org/projects/sandbox/branches/setuptools-0.6/#egg=setuptools-dev06 + + .. _Python SVN sandbox: http://svn.python.org/projects/sandbox/trunk/setuptools/#egg=setuptools-dev + + -------------------------------- + Using Setuptools and EasyInstall + -------------------------------- + + Here are some of the available manuals, tutorials, and other resources for + learning about Setuptools, Python Eggs, and EasyInstall: + + * `The EasyInstall user's guide and reference manual`_ + * `The setuptools Developer's Guide`_ + * `The pkg_resources API reference`_ + * `Package Compatibility Notes`_ (user-maintained) + * `The Internal Structure of Python Eggs`_ + + Questions, comments, and bug reports should be directed to the `distutils-sig + mailing list`_. If you have written (or know of) any tutorials, documentation, + plug-ins, or other resources for setuptools users, please let us know about + them there, so this reference list can be updated. If you have working, + *tested* patches to correct problems or add features, you may submit them to + the `setuptools bug tracker`_. + + .. _setuptools bug tracker: http://bugs.python.org/setuptools/ + .. _Package Compatibility Notes: http://peak.telecommunity.com/DevCenter/PackageNotes + .. _The Internal Structure of Python Eggs: http://peak.telecommunity.com/DevCenter/EggFormats + .. _The setuptools Developer's Guide: http://peak.telecommunity.com/DevCenter/setuptools + .. _The pkg_resources API reference: http://peak.telecommunity.com/DevCenter/PkgResources + .. _The EasyInstall user's guide and reference manual: http://peak.telecommunity.com/DevCenter/EasyInstall + .. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ + + + ------- + Credits + ------- + + * The original design for the ``.egg`` format and the ``pkg_resources`` API was + co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first + version of ``pkg_resources``, and supplied the OS X operating system version + compatibility algorithm. + + * Ian Bicking implemented many early "creature comfort" features of + easy_install, including support for downloading via Sourceforge and + Subversion repositories. Ian's comments on the Web-SIG about WSGI + application deployment also inspired the concept of "entry points" in eggs, + and he has given talks at PyCon and elsewhere to inform and educate the + community about eggs and setuptools. + + * Jim Fulton contributed time and effort to build automated tests of various + aspects of ``easy_install``, and supplied the doctests for the command-line + ``.exe`` wrappers on Windows. + + * Phillip J. Eby is the principal author and maintainer of setuptools, and + first proposed the idea of an importable binary distribution format for + Python application plug-ins. + + * Significant parts of the implementation of setuptools were funded by the Open + Source Applications Foundation, to provide a plug-in infrastructure for the + Chandler PIM application. In addition, many OSAF staffers (such as Mike + "Code Bear" Taylor) contributed their time and stress as guinea pigs for the + use of eggs and setuptools, even before eggs were "cool". (Thanks, guys!) + + +Keywords: CPAN PyPI distutils eggs package management +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Python Software Foundation License +Classifier: License :: OSI Approved :: Zope Public License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Archiving :: Packaging +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities diff --git a/Lib/packaging/tests/SETUPTOOLS-PKG-INFO2 b/Lib/packaging/tests/SETUPTOOLS-PKG-INFO2 new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/SETUPTOOLS-PKG-INFO2 @@ -0,0 +1,183 @@ +Metadata-Version: 1.1 +Name: setuptools +Version: 0.6c9 +Summary: Download, build, install, upgrade, and uninstall Python packages -- easily! +Home-page: http://pypi.python.org/pypi/setuptools +Author: Phillip J. Eby +Author-email: distutils-sig at python.org +License: PSF or ZPL +Description: =============================== + Installing and Using Setuptools + =============================== + + .. contents:: **Table of Contents** + + + ------------------------- + Installation Instructions + ------------------------- + + Windows + ======= + + Install setuptools using the provided ``.exe`` installer. If you've previously + installed older versions of setuptools, please delete all ``setuptools*.egg`` + and ``setuptools.pth`` files from your system's ``site-packages`` directory + (and any other ``sys.path`` directories) FIRST. + + If you are upgrading a previous version of setuptools that was installed using + an ``.exe`` installer, please be sure to also *uninstall that older version* + via your system's "Add/Remove Programs" feature, BEFORE installing the newer + version. + + Once installation is complete, you will find an ``easy_install.exe`` program in + your Python ``Scripts`` subdirectory. Be sure to add this directory to your + ``PATH`` environment variable, if you haven't already done so. + + + RPM-Based Systems + ================= + + Install setuptools using the provided source RPM. The included ``.spec`` file + assumes you are installing using the default ``python`` executable, and is not + specific to a particular Python version. The ``easy_install`` executable will + be installed to a system ``bin`` directory such as ``/usr/bin``. + + If you wish to install to a location other than the default Python + installation's default ``site-packages`` directory (and ``$prefix/bin`` for + scripts), please use the ``.egg``-based installation approach described in the + following section. + + + Cygwin, Mac OS X, Linux, Other + ============================== + + 1. Download the appropriate egg for your version of Python (e.g. + ``setuptools-0.6c9-py2.4.egg``). Do NOT rename it. + + 2. Run it as if it were a shell script, e.g. ``sh setuptools-0.6c9-py2.4.egg``. + Setuptools will install itself using the matching version of Python (e.g. + ``python2.4``), and will place the ``easy_install`` executable in the + default location for installing Python scripts (as determined by the + standard distutils configuration files, or by the Python installation). + + If you want to install setuptools to somewhere other than ``site-packages`` or + your default distutils installation locations for libraries and scripts, you + may include EasyInstall command-line options such as ``--prefix``, + ``--install-dir``, and so on, following the ``.egg`` filename on the same + command line. For example:: + + sh setuptools-0.6c9-py2.4.egg --prefix=~ + + You can use ``--help`` to get a full options list, but we recommend consulting + the `EasyInstall manual`_ for detailed instructions, especially `the section + on custom installation locations`_. + + .. _EasyInstall manual: http://peak.telecommunity.com/DevCenter/EasyInstall + .. _the section on custom installation locations: http://peak.telecommunity.com/DevCenter/EasyInstall#custom-installation-locations + + + Cygwin Note + ----------- + + If you are trying to install setuptools for the **Windows** version of Python + (as opposed to the Cygwin version that lives in ``/usr/bin``), you must make + sure that an appropriate executable (``python2.3``, ``python2.4``, or + ``python2.5``) is on your **Cygwin** ``PATH`` when invoking the egg. For + example, doing the following at a Cygwin bash prompt will install setuptools + for the **Windows** Python found at ``C:\\Python24``:: + + ln -s /cygdrive/c/Python24/python.exe python2.4 + PATH=.:$PATH sh setuptools-0.6c9-py2.4.egg + rm python2.4 + + + Downloads + ========= + + All setuptools downloads can be found at `the project's home page in the Python + Package Index`_. Scroll to the very bottom of the page to find the links. + + .. _the project's home page in the Python Package Index: http://pypi.python.org/pypi/setuptools + + In addition to the PyPI downloads, the development version of ``setuptools`` + is available from the `Python SVN sandbox`_, and in-development versions of the + `0.6 branch`_ are available as well. + + .. _0.6 branch: http://svn.python.org/projects/sandbox/branches/setuptools-0.6/#egg=setuptools-dev06 + + .. _Python SVN sandbox: http://svn.python.org/projects/sandbox/trunk/setuptools/#egg=setuptools-dev + + -------------------------------- + Using Setuptools and EasyInstall + -------------------------------- + + Here are some of the available manuals, tutorials, and other resources for + learning about Setuptools, Python Eggs, and EasyInstall: + + * `The EasyInstall user's guide and reference manual`_ + * `The setuptools Developer's Guide`_ + * `The pkg_resources API reference`_ + * `Package Compatibility Notes`_ (user-maintained) + * `The Internal Structure of Python Eggs`_ + + Questions, comments, and bug reports should be directed to the `distutils-sig + mailing list`_. If you have written (or know of) any tutorials, documentation, + plug-ins, or other resources for setuptools users, please let us know about + them there, so this reference list can be updated. If you have working, + *tested* patches to correct problems or add features, you may submit them to + the `setuptools bug tracker`_. + + .. _setuptools bug tracker: http://bugs.python.org/setuptools/ + .. _Package Compatibility Notes: http://peak.telecommunity.com/DevCenter/PackageNotes + .. _The Internal Structure of Python Eggs: http://peak.telecommunity.com/DevCenter/EggFormats + .. _The setuptools Developer's Guide: http://peak.telecommunity.com/DevCenter/setuptools + .. _The pkg_resources API reference: http://peak.telecommunity.com/DevCenter/PkgResources + .. _The EasyInstall user's guide and reference manual: http://peak.telecommunity.com/DevCenter/EasyInstall + .. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ + + + ------- + Credits + ------- + + * The original design for the ``.egg`` format and the ``pkg_resources`` API was + co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first + version of ``pkg_resources``, and supplied the OS X operating system version + compatibility algorithm. + + * Ian Bicking implemented many early "creature comfort" features of + easy_install, including support for downloading via Sourceforge and + Subversion repositories. Ian's comments on the Web-SIG about WSGI + application deployment also inspired the concept of "entry points" in eggs, + and he has given talks at PyCon and elsewhere to inform and educate the + community about eggs and setuptools. + + * Jim Fulton contributed time and effort to build automated tests of various + aspects of ``easy_install``, and supplied the doctests for the command-line + ``.exe`` wrappers on Windows. + + * Phillip J. Eby is the principal author and maintainer of setuptools, and + first proposed the idea of an importable binary distribution format for + Python application plug-ins. + + * Significant parts of the implementation of setuptools were funded by the Open + Source Applications Foundation, to provide a plug-in infrastructure for the + Chandler PIM application. In addition, many OSAF staffers (such as Mike + "Code Bear" Taylor) contributed their time and stress as guinea pigs for the + use of eggs and setuptools, even before eggs were "cool". (Thanks, guys!) + + +Keywords: CPAN PyPI distutils eggs package management +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Python Software Foundation License +Classifier: License :: OSI Approved :: Zope Public License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Archiving :: Packaging +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities +Requires: Foo diff --git a/Lib/packaging/tests/__init__.py b/Lib/packaging/tests/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/__init__.py @@ -0,0 +1,133 @@ +"""Test suite for packaging. + +This test suite consists of a collection of test modules in the +packaging.tests package. Each test module has a name starting with +'test' and contains a function test_suite(). The function is expected +to return an initialized unittest.TestSuite instance. + +Utility code is included in packaging.tests.support. +""" + +# Put this text back for the backport +#Always import unittest from this module, it will be the right version +#(standard library unittest for 3.2 and higher, third-party unittest2 +#elease for older versions). + +import os +import sys +import unittest +from test.support import TESTFN + +# XXX move helpers to support, add tests for them, remove things that +# duplicate test.support (or keep them for the backport; needs thinking) + +here = os.path.dirname(__file__) or os.curdir +verbose = 1 + +def test_suite(): + suite = unittest.TestSuite() + for fn in os.listdir(here): + if fn.startswith("test") and fn.endswith(".py"): + modname = "packaging.tests." + fn[:-3] + __import__(modname) + module = sys.modules[modname] + suite.addTest(module.test_suite()) + return suite + + +class Error(Exception): + """Base class for regression test exceptions.""" + + +class TestFailed(Error): + """Test failed.""" + + +class BasicTestRunner: + def run(self, test): + result = unittest.TestResult() + test(result) + return result + + +def _run_suite(suite, verbose_=1): + """Run tests from a unittest.TestSuite-derived class.""" + global verbose + verbose = verbose_ + if verbose_: + runner = unittest.TextTestRunner(sys.stdout, verbosity=2) + else: + runner = BasicTestRunner() + + result = runner.run(suite) + if not result.wasSuccessful(): + if len(result.errors) == 1 and not result.failures: + err = result.errors[0][1] + elif len(result.failures) == 1 and not result.errors: + err = result.failures[0][1] + else: + err = "errors occurred; run in verbose mode for details" + raise TestFailed(err) + + +def run_unittest(classes, verbose_=1): + """Run tests from unittest.TestCase-derived classes. + + Originally extracted from stdlib test.test_support and modified to + support unittest2. + """ + valid_types = (unittest.TestSuite, unittest.TestCase) + suite = unittest.TestSuite() + for cls in classes: + if isinstance(cls, str): + if cls in sys.modules: + suite.addTest(unittest.findTestCases(sys.modules[cls])) + else: + raise ValueError("str arguments must be keys in sys.modules") + elif isinstance(cls, valid_types): + suite.addTest(cls) + else: + suite.addTest(unittest.makeSuite(cls)) + _run_suite(suite, verbose_) + + +def reap_children(): + """Use this function at the end of test_main() whenever sub-processes + are started. This will help ensure that no extra children (zombies) + stick around to hog resources and create problems when looking + for refleaks. + + Extracted from stdlib test.support. + """ + + # Reap all our dead child processes so we don't leave zombies around. + # These hog resources and might be causing some of the buildbots to die. + if hasattr(os, 'waitpid'): + any_process = -1 + while True: + try: + # This will raise an exception on Windows. That's ok. + pid, status = os.waitpid(any_process, os.WNOHANG) + if pid == 0: + break + except: + break + + +def captured_stdout(func, *args, **kw): + import io + orig_stdout = getattr(sys, 'stdout') + setattr(sys, 'stdout', io.StringIO()) + try: + res = func(*args, **kw) + sys.stdout.seek(0) + return res, sys.stdout.read() + finally: + setattr(sys, 'stdout', orig_stdout) + + +def unload(name): + try: + del sys.modules[name] + except KeyError: + pass diff --git a/Lib/packaging/tests/__main__.py b/Lib/packaging/tests/__main__.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/__main__.py @@ -0,0 +1,20 @@ +"""Packaging test suite runner.""" + +# Ripped from importlib tests, thanks Brett! + +import os +import sys +import unittest +from test.support import run_unittest, reap_children + + +def test_main(): + start_dir = os.path.dirname(__file__) + top_dir = os.path.dirname(os.path.dirname(start_dir)) + test_loader = unittest.TestLoader() + run_unittest(test_loader.discover(start_dir, top_level_dir=top_dir)) + reap_children() + + +if __name__ == '__main__': + test_main() diff --git a/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/INSTALLER b/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/INSTALLER new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/METADATA b/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/METADATA new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/METADATA @@ -0,0 +1,4 @@ +Metadata-version: 1.2 +Name: babar +Version: 0.1 +Author: FELD Boris \ No newline at end of file diff --git a/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/RECORD b/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/RECORD new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/REQUESTED b/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/REQUESTED new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/RESOURCES b/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/RESOURCES new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/babar-0.1.dist-info/RESOURCES @@ -0,0 +1,2 @@ +babar.png,babar.png +babar.cfg,babar.cfg \ No newline at end of file diff --git a/Lib/packaging/tests/fake_dists/babar.cfg b/Lib/packaging/tests/fake_dists/babar.cfg new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/babar.cfg @@ -0,0 +1,1 @@ +Config \ No newline at end of file diff --git a/Lib/packaging/tests/fake_dists/babar.png b/Lib/packaging/tests/fake_dists/babar.png new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO b/Lib/packaging/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO @@ -0,0 +1,6 @@ +Metadata-Version: 1.2 +Name: bacon +Version: 0.1 +Provides-Dist: truffles (2.0) +Provides-Dist: bacon (0.1) +Obsoletes-Dist: truffles (>=0.9,<=1.5) diff --git a/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/PKG-INFO b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/PKG-INFO new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/PKG-INFO @@ -0,0 +1,18 @@ +Metadata-Version: 1.0 +Name: banana +Version: 0.4 +Summary: A yellow fruit +Home-page: http://en.wikipedia.org/wiki/Banana +Author: Josip Djolonga +Author-email: foo at nbar.com +License: BSD +Description: A fruit +Keywords: foo bar +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Science/Research +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Scientific/Engineering :: GIS diff --git a/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/SOURCES.txt b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/SOURCES.txt new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/dependency_links.txt b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/dependency_links.txt new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/dependency_links.txt @@ -0,0 +1,1 @@ + diff --git a/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/entry_points.txt b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/entry_points.txt new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/entry_points.txt @@ -0,0 +1,3 @@ + + # -*- Entry points: -*- + \ No newline at end of file diff --git a/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/not-zip-safe b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/not-zip-safe new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/not-zip-safe @@ -0,0 +1,1 @@ + diff --git a/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/requires.txt b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/requires.txt new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/requires.txt @@ -0,0 +1,6 @@ +# this should be ignored + +strawberry >=0.5 + +[section ignored] +foo ==0.5 diff --git a/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/top_level.txt b/Lib/packaging/tests/fake_dists/banana-0.4.egg/EGG-INFO/top_level.txt new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/cheese-2.0.2.egg-info b/Lib/packaging/tests/fake_dists/cheese-2.0.2.egg-info new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/cheese-2.0.2.egg-info @@ -0,0 +1,5 @@ +Metadata-Version: 1.2 +Name: cheese +Version: 2.0.2 +Provides-Dist: truffles (1.0.2) +Obsoletes-Dist: truffles (!=1.2,<=2.0) diff --git a/Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA @@ -0,0 +1,9 @@ +Metadata-Version: 1.2 +Name: choxie +Version: 2.0.0.9 +Summary: Chocolate with a kick! +Requires-Dist: towel-stuff (0.1) +Requires-Dist: nut +Provides-Dist: truffles (1.0) +Obsoletes-Dist: truffles (<=0.8,>=0.5) +Obsoletes-Dist: truffles (<=0.9,>=0.6) diff --git a/Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py @@ -0,0 +1,1 @@ +# -*- coding: utf-8 -*- diff --git a/Lib/packaging/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +from towel_stuff import Towel + +class Chocolate(object): + """A piece of chocolate.""" + + def wrap_with_towel(self): + towel = Towel() + towel.wrap(self) + return towel diff --git a/Lib/packaging/tests/fake_dists/choxie-2.0.0.9/truffles.py b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9/truffles.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/choxie-2.0.0.9/truffles.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +from choxie.chocolate import Chocolate + +class Truffle(Chocolate): + """A truffle.""" diff --git a/Lib/packaging/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO b/Lib/packaging/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO new file mode 100644 --- /dev/null +++ b/Lib/packaging/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/Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/INSTALLER b/Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/INSTALLER new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/METADATA b/Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/METADATA new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/METADATA @@ -0,0 +1,5 @@ +Metadata-Version: 1.2 +Name: grammar +Version: 1.0a4 +Requires-Dist: truffles (>=1.2) +Author: Sherlock Holmes diff --git a/Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/RECORD b/Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/RECORD new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/REQUESTED b/Lib/packaging/tests/fake_dists/grammar-1.0a4.dist-info/REQUESTED new file mode 100644 diff --git a/Lib/packaging/tests/fake_dists/grammar-1.0a4/grammar/__init__.py b/Lib/packaging/tests/fake_dists/grammar-1.0a4/grammar/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/grammar-1.0a4/grammar/__init__.py @@ -0,0 +1,1 @@ +# -*- coding: utf-8 -*- diff --git a/Lib/packaging/tests/fake_dists/grammar-1.0a4/grammar/utils.py b/Lib/packaging/tests/fake_dists/grammar-1.0a4/grammar/utils.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/grammar-1.0a4/grammar/utils.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from random import randint + +def is_valid_grammar(sentence): + if randint(0, 10) < 2: + return False + else: + return True diff --git a/Lib/packaging/tests/fake_dists/nut-funkyversion.egg-info b/Lib/packaging/tests/fake_dists/nut-funkyversion.egg-info new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/fake_dists/nut-funkyversion.egg-info @@ -0,0 +1,3 @@ +Metadata-Version: 1.2 +Name: nut +Version: funkyversion diff --git a/Lib/packaging/tests/fake_dists/strawberry-0.6.egg b/Lib/packaging/tests/fake_dists/strawberry-0.6.egg new file mode 100644 index 0000000000000000000000000000000000000000..6d160e8b161031ae52638514843592187925b757 GIT binary patch literal 1402 zc$`yK)KALH(=X28%1l#;R!B%nEKbc!%uQ8LF-TCbRZuEUEh#N1$r9UQWv|0ty0Ufu2)H%gjmDgJ}xL0otCbPy`8 at OrXVy z$=M1e`3iV~M*-+)g_5F5g~as4%sjABpm0h{1UV)xlPkcRnT3l11j?rGw_!j6Vhl12 zuI}!-o_=or`X%`V at j0nwsX2Nj6(yk|oD9qiubF*7xU_i9RnLxBqqeU~_GC)B*8Q%^m+PITr6Z&8t31F+o4>xK^{d-p7?^ zx~J#&ZkWuS9 isinstance(x, T) + type(x) is T -> isinstance(x, T) + type(x) != T -> not isinstance(x, T) + type(x) is not T -> not isinstance(x, T) + +* Change "while 1:" into "while True:". + +* Change both + + v = list(EXPR) + v.sort() + foo(v) + +and the more general + + v = EXPR + v.sort() + foo(v) + +into + + v = sorted(EXPR) + foo(v) +""" +# Author: Jacques Frechet, Collin Winter + +# Local imports +from lib2to3 import fixer_base +from lib2to3.fixer_util import Call, Comma, Name, Node, syms + +CMP = "(n='!=' | '==' | 'is' | n=comp_op< 'is' 'not' >)" +TYPE = "power< 'type' trailer< '(' x=any ')' > >" + +class FixIdioms(fixer_base.BaseFix): + + explicit = False # The user must ask for this fixer + + PATTERN = r""" + isinstance=comparison< %s %s T=any > + | + isinstance=comparison< T=any %s %s > + | + while_stmt< 'while' while='1' ':' any+ > + | + sorted=any< + any* + simple_stmt< + expr_stmt< id1=any '=' + power< list='list' trailer< '(' (not arglist) any ')' > > + > + '\n' + > + sort= + simple_stmt< + power< id2=any + trailer< '.' 'sort' > trailer< '(' ')' > + > + '\n' + > + next=any* + > + | + sorted=any< + any* + simple_stmt< expr_stmt< id1=any '=' expr=any > '\n' > + sort= + simple_stmt< + power< id2=any + trailer< '.' 'sort' > trailer< '(' ')' > + > + '\n' + > + next=any* + > + """ % (TYPE, CMP, CMP, TYPE) + + def match(self, node): + r = super(FixIdioms, self).match(node) + # If we've matched one of the sort/sorted subpatterns above, we + # want to reject matches where the initial assignment and the + # subsequent .sort() call involve different identifiers. + if r and "sorted" in r: + if r["id1"] == r["id2"]: + return r + return None + return r + + def transform(self, node, results): + if "isinstance" in results: + return self.transform_isinstance(node, results) + elif "while" in results: + return self.transform_while(node, results) + elif "sorted" in results: + return self.transform_sort(node, results) + else: + raise RuntimeError("Invalid match") + + def transform_isinstance(self, node, results): + x = results["x"].clone() # The thing inside of type() + T = results["T"].clone() # The type being compared against + x.prefix = "" + T.prefix = " " + test = Call(Name("isinstance"), [x, Comma(), T]) + if "n" in results: + test.prefix = " " + test = Node(syms.not_test, [Name("not"), test]) + test.prefix = node.prefix + return test + + def transform_while(self, node, results): + one = results["while"] + one.replace(Name("True", prefix=one.prefix)) + + def transform_sort(self, node, results): + sort_stmt = results["sort"] + next_stmt = results["next"] + list_call = results.get("list") + simple_expr = results.get("expr") + + if list_call: + list_call.replace(Name("sorted", prefix=list_call.prefix)) + elif simple_expr: + new = simple_expr.clone() + new.prefix = "" + simple_expr.replace(Call(Name("sorted"), [new], + prefix=simple_expr.prefix)) + else: + raise RuntimeError("should not have reached here") + sort_stmt.remove() + if next_stmt: + next_stmt[0].prefix = sort_stmt._prefix diff --git a/Lib/packaging/tests/pypi_server.py b/Lib/packaging/tests/pypi_server.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypi_server.py @@ -0,0 +1,444 @@ +"""Mock PyPI Server implementation, to use in tests. + +This module also provides a simple test case to extend if you need to use +the PyPIServer all along your test case. Be sure to read the documentation +before any use. + +XXX TODO: + +The mock server can handle simple HTTP request (to simulate a simple index) or +XMLRPC requests, over HTTP. Both does not have the same intergface to deal +with, and I think it's a pain. + +A good idea could be to re-think a bit the way dstributions are handled in the +mock server. As it should return malformed HTML pages, we need to keep the +static behavior. + +I think of something like that: + + >>> server = PyPIMockServer() + >>> server.startHTTP() + >>> server.startXMLRPC() + +Then, the server must have only one port to rely on, eg. + + >>> server.fulladress() + "http://ip:port/" + +It could be simple to have one HTTP server, relaying the requests to the two +implementations (static HTTP and XMLRPC over HTTP). +""" + +import os +import queue +import select +import socket +import threading +import socketserver +from functools import wraps +from http.server import HTTPServer, SimpleHTTPRequestHandler +from xmlrpc.server import SimpleXMLRPCServer + +from packaging.tests import unittest + +PYPI_DEFAULT_STATIC_PATH = os.path.join( + os.path.dirname(os.path.abspath(__file__)), 'pypiserver') + + +def use_xmlrpc_server(*server_args, **server_kwargs): + server_kwargs['serve_xmlrpc'] = True + return use_pypi_server(*server_args, **server_kwargs) + + +def use_http_server(*server_args, **server_kwargs): + server_kwargs['serve_xmlrpc'] = False + return use_pypi_server(*server_args, **server_kwargs) + + +def use_pypi_server(*server_args, **server_kwargs): + """Decorator to make use of the PyPIServer for test methods, + just when needed, and not for the entire duration of the testcase. + """ + def wrapper(func): + @wraps(func) + def wrapped(*args, **kwargs): + server = PyPIServer(*server_args, **server_kwargs) + server.start() + try: + func(server=server, *args, **kwargs) + finally: + server.stop() + return wrapped + return wrapper + + +class PyPIServerTestCase(unittest.TestCase): + + def setUp(self): + super(PyPIServerTestCase, self).setUp() + self.pypi = PyPIServer() + self.pypi.start() + self.addCleanup(self.pypi.stop) + + +class PyPIServer(threading.Thread): + """PyPI Mocked server. + Provides a mocked version of the PyPI API's, to ease tests. + + Support serving static content and serving previously given text. + """ + + def __init__(self, test_static_path=None, + static_filesystem_paths=["default"], + static_uri_paths=["simple", "packages"], serve_xmlrpc=False): + """Initialize the server. + + Default behavior is to start the HTTP server. You can either start the + xmlrpc server by setting xmlrpc to True. Caution: Only one server will + be started. + + static_uri_paths and static_base_path are parameters used to provides + respectively the http_paths to serve statically, and where to find the + matching files on the filesystem. + """ + # we want to launch the server in a new dedicated thread, to not freeze + # tests. + threading.Thread.__init__(self) + self._run = True + self._serve_xmlrpc = serve_xmlrpc + + #TODO allow to serve XMLRPC and HTTP static files at the same time. + if not self._serve_xmlrpc: + self.server = HTTPServer(('127.0.0.1', 0), PyPIRequestHandler) + self.server.RequestHandlerClass.pypi_server = self + + self.request_queue = queue.Queue() + self._requests = [] + self.default_response_status = 404 + self.default_response_headers = [('Content-type', 'text/plain')] + self.default_response_data = "The page does not exists" + + # initialize static paths / filesystems + self.static_uri_paths = static_uri_paths + + # append the static paths defined locally + if test_static_path is not None: + static_filesystem_paths.append(test_static_path) + self.static_filesystem_paths = [ + PYPI_DEFAULT_STATIC_PATH + "/" + path + for path in static_filesystem_paths] + else: + # XMLRPC server + self.server = PyPIXMLRPCServer(('127.0.0.1', 0)) + self.xmlrpc = XMLRPCMockIndex() + # register the xmlrpc methods + self.server.register_introspection_functions() + self.server.register_instance(self.xmlrpc) + + self.address = (self.server.server_name, self.server.server_port) + # to not have unwanted outputs. + self.server.RequestHandlerClass.log_request = lambda *_: None + + def run(self): + # loop because we can't stop it otherwise, for python < 2.6 + while self._run: + r, w, e = select.select([self.server], [], [], 0.5) + if r: + self.server.handle_request() + + def stop(self): + """self shutdown is not supported for python < 2.6""" + self._run = False + + def get_next_response(self): + return (self.default_response_status, + self.default_response_headers, + self.default_response_data) + + @property + def requests(self): + """Use this property to get all requests that have been made + to the server + """ + while True: + try: + self._requests.append(self.request_queue.get_nowait()) + except queue.Empty: + break + return self._requests + + @property + def full_address(self): + return "http://%s:%s" % self.address + + +class PyPIRequestHandler(SimpleHTTPRequestHandler): + # we need to access the pypi server while serving the content + pypi_server = None + + def serve_request(self): + """Serve the content. + + Also record the requests to be accessed later. If trying to access an + url matching a static uri, serve static content, otherwise serve + what is provided by the `get_next_response` method. + + If nothing is defined there, return a 404 header. + """ + # record the request. Read the input only on PUT or POST requests + if self.command in ("PUT", "POST"): + if 'content-length' in self.headers: + request_data = self.rfile.read( + int(self.headers['content-length'])) + else: + request_data = self.rfile.read() + + elif self.command in ("GET", "DELETE"): + request_data = '' + + self.pypi_server.request_queue.put((self, request_data)) + + # serve the content from local disc if we request an URL beginning + # by a pattern defined in `static_paths` + url_parts = self.path.split("/") + if (len(url_parts) > 1 and + url_parts[1] in self.pypi_server.static_uri_paths): + data = None + # always take the last first. + fs_paths = [] + fs_paths.extend(self.pypi_server.static_filesystem_paths) + fs_paths.reverse() + relative_path = self.path + for fs_path in fs_paths: + try: + if self.path.endswith("/"): + relative_path += "index.html" + + if relative_path.endswith('.tar.gz'): + with open(fs_path + relative_path, 'br') as file: + data = file.read() + headers = [('Content-type', 'application/x-gtar')] + else: + with open(fs_path + relative_path) as file: + data = file.read().encode() + headers = [('Content-type', 'text/html')] + + self.make_response(data, headers=headers) + + except IOError: + pass + + if data is None: + self.make_response("Not found", 404) + + # otherwise serve the content from get_next_response + else: + # send back a response + status, headers, data = self.pypi_server.get_next_response() + self.make_response(data, status, headers) + + do_POST = do_GET = do_DELETE = do_PUT = serve_request + + def make_response(self, data, status=200, + headers=[('Content-type', 'text/html')]): + """Send the response to the HTTP client""" + if not isinstance(status, int): + try: + status = int(status) + except ValueError: + # we probably got something like YYY Codename. + # Just get the first 3 digits + status = int(status[:3]) + + self.send_response(status) + for header, value in headers: + self.send_header(header, value) + self.end_headers() + + if type(data) is str: + data = data.encode() + + self.wfile.write(data) + + +class PyPIXMLRPCServer(SimpleXMLRPCServer): + def server_bind(self): + """Override server_bind to store the server name.""" + socketserver.TCPServer.server_bind(self) + host, port = self.socket.getsockname()[:2] + self.server_name = socket.getfqdn(host) + self.server_port = port + + +class MockDist: + """Fake distribution, used in the Mock PyPI Server""" + + def __init__(self, name, version="1.0", hidden=False, url="http://url/", + type="sdist", filename="", size=10000, + digest="123456", downloads=7, has_sig=False, + python_version="source", comment="comment", + author="John Doe", author_email="john at doe.name", + maintainer="Main Tayner", maintainer_email="maintainer_mail", + project_url="http://project_url/", homepage="http://homepage/", + keywords="", platform="UNKNOWN", classifiers=[], licence="", + description="Description", summary="Summary", stable_version="", + ordering="", documentation_id="", code_kwalitee_id="", + installability_id="", obsoletes=[], obsoletes_dist=[], + provides=[], provides_dist=[], requires=[], requires_dist=[], + requires_external=[], requires_python=""): + + # basic fields + self.name = name + self.version = version + self.hidden = hidden + + # URL infos + self.url = url + self.digest = digest + self.downloads = downloads + self.has_sig = has_sig + self.python_version = python_version + self.comment = comment + self.type = type + + # metadata + self.author = author + self.author_email = author_email + self.maintainer = maintainer + self.maintainer_email = maintainer_email + self.project_url = project_url + self.homepage = homepage + self.keywords = keywords + self.platform = platform + self.classifiers = classifiers + self.licence = licence + self.description = description + self.summary = summary + self.stable_version = stable_version + self.ordering = ordering + self.cheesecake_documentation_id = documentation_id + self.cheesecake_code_kwalitee_id = code_kwalitee_id + self.cheesecake_installability_id = installability_id + + self.obsoletes = obsoletes + self.obsoletes_dist = obsoletes_dist + self.provides = provides + self.provides_dist = provides_dist + self.requires = requires + self.requires_dist = requires_dist + self.requires_external = requires_external + self.requires_python = requires_python + + def url_infos(self): + return { + 'url': self.url, + 'packagetype': self.type, + 'filename': 'filename.tar.gz', + 'size': '6000', + 'md5_digest': self.digest, + 'downloads': self.downloads, + 'has_sig': self.has_sig, + 'python_version': self.python_version, + 'comment_text': self.comment, + } + + def metadata(self): + return { + 'maintainer': self.maintainer, + 'project_url': [self.project_url], + 'maintainer_email': self.maintainer_email, + 'cheesecake_code_kwalitee_id': self.cheesecake_code_kwalitee_id, + 'keywords': self.keywords, + 'obsoletes_dist': self.obsoletes_dist, + 'requires_external': self.requires_external, + 'author': self.author, + 'author_email': self.author_email, + 'download_url': self.url, + 'platform': self.platform, + 'version': self.version, + 'obsoletes': self.obsoletes, + 'provides': self.provides, + 'cheesecake_documentation_id': self.cheesecake_documentation_id, + '_pypi_hidden': self.hidden, + 'description': self.description, + '_pypi_ordering': 19, + 'requires_dist': self.requires_dist, + 'requires_python': self.requires_python, + 'classifiers': [], + 'name': self.name, + 'licence': self.licence, + 'summary': self.summary, + 'home_page': self.homepage, + 'stable_version': self.stable_version, + 'provides_dist': self.provides_dist or "%s (%s)" % (self.name, + self.version), + 'requires': self.requires, + 'cheesecake_installability_id': self.cheesecake_installability_id, + } + + def search_result(self): + return { + '_pypi_ordering': 0, + 'version': self.version, + 'name': self.name, + 'summary': self.summary, + } + + +class XMLRPCMockIndex: + """Mock XMLRPC server""" + + def __init__(self, dists=[]): + self._dists = dists + self._search_result = [] + + def add_distributions(self, dists): + for dist in dists: + self._dists.append(MockDist(**dist)) + + def set_distributions(self, dists): + self._dists = [] + self.add_distributions(dists) + + def set_search_result(self, result): + """set a predefined search result""" + self._search_result = result + + def _get_search_results(self): + results = [] + for name in self._search_result: + found_dist = [d for d in self._dists if d.name == name] + if found_dist: + results.append(found_dist[0]) + else: + dist = MockDist(name) + results.append(dist) + self._dists.append(dist) + return [r.search_result() for r in results] + + def list_packages(self): + return [d.name for d in self._dists] + + def package_releases(self, package_name, show_hidden=False): + if show_hidden: + # return all + return [d.version for d in self._dists if d.name == package_name] + else: + # return only un-hidden + return [d.version for d in self._dists if d.name == package_name + and not d.hidden] + + def release_urls(self, package_name, version): + return [d.url_infos() for d in self._dists + if d.name == package_name and d.version == version] + + def release_data(self, package_name, version): + release = [d for d in self._dists + if d.name == package_name and d.version == version] + if release: + return release[0].metadata() + else: + return {} + + def search(self, spec, operator="and"): + return self._get_search_results() diff --git a/Lib/packaging/tests/pypi_test_server.py b/Lib/packaging/tests/pypi_test_server.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypi_test_server.py @@ -0,0 +1,59 @@ +"""Test PyPI Server implementation at testpypi.python.org, to use in tests. + +This is a drop-in replacement for the mock pypi server for testing against a +real pypi server hosted by python.org especially for testing against. +""" + +import unittest + +PYPI_DEFAULT_STATIC_PATH = None + + +def use_xmlrpc_server(*server_args, **server_kwargs): + server_kwargs['serve_xmlrpc'] = True + return use_pypi_server(*server_args, **server_kwargs) + + +def use_http_server(*server_args, **server_kwargs): + server_kwargs['serve_xmlrpc'] = False + return use_pypi_server(*server_args, **server_kwargs) + + +def use_pypi_server(*server_args, **server_kwargs): + """Decorator to make use of the PyPIServer for test methods, + just when needed, and not for the entire duration of the testcase. + """ + def wrapper(func): + def wrapped(*args, **kwargs): + server = PyPIServer(*server_args, **server_kwargs) + func(server=server, *args, **kwargs) + return wrapped + return wrapper + + +class PyPIServerTestCase(unittest.TestCase): + + def setUp(self): + super(PyPIServerTestCase, self).setUp() + self.pypi = PyPIServer() + self.pypi.start() + self.addCleanup(self.pypi.stop) + + +class PyPIServer: + """Shim to access testpypi.python.org, for testing a real server.""" + + def __init__(self, test_static_path=None, + static_filesystem_paths=["default"], + static_uri_paths=["simple"], serve_xmlrpc=False): + self.address = ('testpypi.python.org', '80') + + def start(self): + pass + + def stop(self): + pass + + @property + def full_address(self): + return "http://%s:%s" % self.address diff --git a/Lib/packaging/tests/pypiserver/downloads_with_md5/packages/source/f/foobar/foobar-0.1.tar.gz b/Lib/packaging/tests/pypiserver/downloads_with_md5/packages/source/f/foobar/foobar-0.1.tar.gz new file mode 100644 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/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/badmd5/badmd5-0.1.tar.gz b/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/badmd5/badmd5-0.1.tar.gz new file mode 100644 diff --git a/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/badmd5/index.html b/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/badmd5/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/badmd5/index.html @@ -0,0 +1,3 @@ + +badmd5-0.1.tar.gz
    + diff --git a/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/foobar/index.html b/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/foobar/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/foobar/index.html @@ -0,0 +1,3 @@ + +foobar-0.1.tar.gz
    + diff --git a/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/index.html b/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/downloads_with_md5/simple/index.html @@ -0,0 +1,2 @@ +foobar/ +badmd5/ diff --git a/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/bar/index.html b/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/bar/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/bar/index.html @@ -0,0 +1,6 @@ +Links for bar

    Links for bar

    +bar-1.0.tar.gz
    +bar-1.0.1.tar.gz
    +bar-2.0.tar.gz
    +bar-2.0.1.tar.gz
    + diff --git a/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/baz/index.html b/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/baz/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/baz/index.html @@ -0,0 +1,6 @@ +Links for baz

    Links for baz

    +baz-1.0.tar.gz
    +baz-1.0.1.tar.gz
    +baz-2.0.tar.gz
    +baz-2.0.1.tar.gz
    + diff --git a/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/foo/index.html b/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/foo/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/foo/index.html @@ -0,0 +1,6 @@ +Links for foo

    Links for foo

    +foo-1.0.tar.gz
    +foo-1.0.1.tar.gz
    +foo-2.0.tar.gz
    +foo-2.0.1.tar.gz
    + diff --git a/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/index.html b/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/foo_bar_baz/simple/index.html @@ -0,0 +1,3 @@ +foo/ +bar/ +baz/ diff --git a/Lib/packaging/tests/pypiserver/project_list/simple/index.html b/Lib/packaging/tests/pypiserver/project_list/simple/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/project_list/simple/index.html @@ -0,0 +1,5 @@ +FooBar-bar +Foobar-baz +Baz-FooBar +Baz +Foo diff --git a/Lib/packaging/tests/pypiserver/test_found_links/simple/foobar/index.html b/Lib/packaging/tests/pypiserver/test_found_links/simple/foobar/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/test_found_links/simple/foobar/index.html @@ -0,0 +1,6 @@ +Links for Foobar

    Links for Foobar

    +Foobar-1.0.tar.gz
    +Foobar-1.0.1.tar.gz
    +Foobar-2.0.tar.gz
    +Foobar-2.0.1.tar.gz
    + diff --git a/Lib/packaging/tests/pypiserver/test_found_links/simple/index.html b/Lib/packaging/tests/pypiserver/test_found_links/simple/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/test_found_links/simple/index.html @@ -0,0 +1,1 @@ +foobar/ diff --git a/Lib/packaging/tests/pypiserver/test_pypi_server/external/index.html b/Lib/packaging/tests/pypiserver/test_pypi_server/external/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/test_pypi_server/external/index.html @@ -0,0 +1,1 @@ +index.html from external server diff --git a/Lib/packaging/tests/pypiserver/test_pypi_server/simple/index.html b/Lib/packaging/tests/pypiserver/test_pypi_server/simple/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/test_pypi_server/simple/index.html @@ -0,0 +1,1 @@ +Yeah diff --git a/Lib/packaging/tests/pypiserver/with_externals/external/external.html b/Lib/packaging/tests/pypiserver/with_externals/external/external.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/with_externals/external/external.html @@ -0,0 +1,3 @@ + +bad old link + diff --git a/Lib/packaging/tests/pypiserver/with_externals/simple/foobar/index.html b/Lib/packaging/tests/pypiserver/with_externals/simple/foobar/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/with_externals/simple/foobar/index.html @@ -0,0 +1,4 @@ + +foobar-0.1.tar.gz
    +external homepage
    + diff --git a/Lib/packaging/tests/pypiserver/with_externals/simple/index.html b/Lib/packaging/tests/pypiserver/with_externals/simple/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/with_externals/simple/index.html @@ -0,0 +1,1 @@ +foobar/ diff --git a/Lib/packaging/tests/pypiserver/with_norel_links/external/homepage.html b/Lib/packaging/tests/pypiserver/with_norel_links/external/homepage.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/with_norel_links/external/homepage.html @@ -0,0 +1,7 @@ + + +

    a rel=homepage HTML page

    +foobar 2.0 + + + diff --git a/Lib/packaging/tests/pypiserver/with_norel_links/external/nonrel.html b/Lib/packaging/tests/pypiserver/with_norel_links/external/nonrel.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/with_norel_links/external/nonrel.html @@ -0,0 +1,1 @@ +A page linked without rel="download" or rel="homepage" link. diff --git a/Lib/packaging/tests/pypiserver/with_norel_links/simple/foobar/index.html b/Lib/packaging/tests/pypiserver/with_norel_links/simple/foobar/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/with_norel_links/simple/foobar/index.html @@ -0,0 +1,6 @@ + +foobar-0.1.tar.gz
    +external homepage
    +unrelated link
    +unrelated download
    + diff --git a/Lib/packaging/tests/pypiserver/with_norel_links/simple/index.html b/Lib/packaging/tests/pypiserver/with_norel_links/simple/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/with_norel_links/simple/index.html @@ -0,0 +1,1 @@ +foobar/ diff --git a/Lib/packaging/tests/pypiserver/with_real_externals/simple/foobar/index.html b/Lib/packaging/tests/pypiserver/with_real_externals/simple/foobar/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/with_real_externals/simple/foobar/index.html @@ -0,0 +1,4 @@ + +foobar-0.1.tar.gz
    +external homepage
    + diff --git a/Lib/packaging/tests/pypiserver/with_real_externals/simple/index.html b/Lib/packaging/tests/pypiserver/with_real_externals/simple/index.html new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/pypiserver/with_real_externals/simple/index.html @@ -0,0 +1,1 @@ +foobar/ diff --git a/Lib/packaging/tests/support.py b/Lib/packaging/tests/support.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/support.py @@ -0,0 +1,259 @@ +"""Support code for packaging test cases. + +A few helper classes are provided: LoggingCatcher, TempdirManager and +EnvironRestorer. They are written to be used as mixins:: + + from packaging.tests import unittest + from packaging.tests.support import LoggingCatcher + + class SomeTestCase(LoggingCatcher, unittest.TestCase): + +If you need to define a setUp method on your test class, you have to +call the mixin class' setUp method or it won't work (same thing for +tearDown): + + def setUp(self): + super(SomeTestCase, self).setUp() + ... # other setup code + +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, a create_distribution function +and a skip_unless_symlink decorator. + +Each class or function has a docstring to explain its purpose and usage. +""" + +import os +import errno +import shutil +import logging +import weakref +import tempfile + +from packaging import logger +from packaging.dist import Distribution +from packaging.tests import unittest + +__all__ = ['LoggingCatcher', 'TempdirManager', 'EnvironRestorer', + 'DummyCommand', 'unittest', 'create_distribution', + 'skip_unless_symlink'] + + +class _TestHandler(logging.handlers.BufferingHandler): + # stolen and adapted from test.support + + def __init__(self): + logging.handlers.BufferingHandler.__init__(self, 0) + self.setLevel(logging.DEBUG) + + def shouldFlush(self): + return False + + def emit(self, record): + self.buffer.append(record) + + +class LoggingCatcher: + """TestCase-compatible mixin to receive logging calls. + + Upon setUp, instances of this classes get a BufferingHandler that's + configured to record all messages logged to the 'packaging' logger. + + Use get_logs to retrieve messages and self.loghandler.flush to discard + them. + """ + + def setUp(self): + super(LoggingCatcher, self).setUp() + self.loghandler = handler = _TestHandler() + logger.addHandler(handler) + self.addCleanup(logger.setLevel, logger.level) + logger.setLevel(logging.DEBUG) # we want all messages + + def tearDown(self): + handler = self.loghandler + # All this is necessary to properly shut down the logging system and + # avoid a regrtest complaint. Thanks to Vinay Sajip for the help. + handler.close() + logger.removeHandler(handler) + for ref in weakref.getweakrefs(handler): + logging._removeHandlerRef(ref) + del self.loghandler + super(LoggingCatcher, self).tearDown() + + def get_logs(self, *levels): + """Return all log messages with level in *levels*. + + Without explicit levels given, returns all messages. + *levels* defaults to all levels. For log calls with arguments (i.e. + logger.info('bla bla %s', arg)), the messages + Returns a list. + + Example: self.get_logs(logging.WARN, logging.DEBUG). + """ + if not levels: + return [log.getMessage() for log in self.loghandler.buffer] + return [log.getMessage() for log in self.loghandler.buffer + if log.levelno in levels] + + +class TempdirManager: + """TestCase-compatible mixin to create temporary directories and files. + + Directories and files created in a test_* method will be removed after it + has run. + """ + + def setUp(self): + super(TempdirManager, self).setUp() + self._basetempdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self._basetempdir, os.name in ('nt', 'cygwin')) + super(TempdirManager, self).tearDown() + + def mktempfile(self): + """Create a read-write temporary file and return it.""" + + def _delete_file(filename): + try: + os.remove(filename) + except OSError as exc: + if exc.errno != errno.ENOENT: + raise + + fd, fn = tempfile.mkstemp(dir=self._basetempdir) + os.close(fd) + fp = open(fn, 'w+') + self.addCleanup(fp.close) + self.addCleanup(_delete_file, fn) + return fp + + def mkdtemp(self): + """Create a temporary directory and return its path.""" + d = tempfile.mkdtemp(dir=self._basetempdir) + return d + + def write_file(self, path, content='xxx'): + """Write a file at the given path. + + path can be a string, a tuple or a list; if it's a tuple or list, + os.path.join will be used to produce a path. + """ + if isinstance(path, (list, tuple)): + path = os.path.join(*path) + f = open(path, 'w') + try: + f.write(content) + finally: + f.close() + + def create_dist(self, **kw): + """Create a stub distribution object and files. + + This function creates a Distribution instance (use keyword arguments + to customize it) and a temporary directory with a project structure + (currently an empty directory). + + It returns the path to the directory and the Distribution instance. + You can use self.write_file to write any file in that + directory, e.g. setup scripts or Python modules. + """ + if 'name' not in kw: + kw['name'] = 'foo' + tmp_dir = self.mkdtemp() + project_dir = os.path.join(tmp_dir, kw['name']) + os.mkdir(project_dir) + 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) + self.assertFalse(os.path.isfile(path), "%r exists" % path) + + +class EnvironRestorer: + """TestCase-compatible mixin to restore or delete environment variables. + + The variables to restore (or delete if they were not originally present) + must be explicitly listed in self.restore_environ. It's better to be + aware of what we're modifying instead of saving and restoring the whole + environment. + """ + + def setUp(self): + super(EnvironRestorer, self).setUp() + self._saved = [] + self._added = [] + for key in self.restore_environ: + if key in os.environ: + self._saved.append((key, os.environ[key])) + else: + self._added.append(key) + + def tearDown(self): + for key, value in self._saved: + os.environ[key] = value + for key in self._added: + os.environ.pop(key, None) + super(EnvironRestorer, self).tearDown() + + +class DummyCommand: + """Class to store options for retrieval via set_undefined_options(). + + Useful for mocking one dependency command in the tests for another + command, see e.g. the dummy build command in test_build_scripts. + """ + + def __init__(self, **kwargs): + for kw, val in kwargs.items(): + setattr(self, kw, val) + + def ensure_finalized(self): + pass + + +class TestDistribution(Distribution): + """Distribution subclasses that avoids the default search for + configuration files. + + The ._config_files attribute must be set before + .parse_config_files() is called. + """ + + def find_config_files(self): + return self._config_files + + +def create_distribution(configfiles=()): + """Prepares a distribution with given config files parsed.""" + d = TestDistribution() + d.config.find_config_files = d.find_config_files + d._config_files = configfiles + d.parse_config_files() + d.parse_command_line() + return d + + +try: + from test.support import skip_unless_symlink +except ImportError: + skip_unless_symlink = unittest.skip( + 'requires test.support.skip_unless_symlink') diff --git a/Lib/packaging/tests/test_ccompiler.py b/Lib/packaging/tests/test_ccompiler.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_ccompiler.py @@ -0,0 +1,15 @@ +"""Tests for distutils.compiler.ccompiler.""" + +from packaging.compiler import ccompiler +from packaging.tests import unittest, support + + +class CCompilerTestCase(unittest.TestCase): + pass # XXX need some tests on CCompiler + + +def test_suite(): + return unittest.makeSuite(CCompilerTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_bdist.py b/Lib/packaging/tests/test_command_bdist.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_bdist.py @@ -0,0 +1,77 @@ +"""Tests for distutils.command.bdist.""" + +from packaging import util +from packaging.command.bdist import bdist, show_formats + +from packaging.tests import unittest, support, captured_stdout + + +class BuildTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def _mock_get_platform(self): + self._get_platform_called = True + return self._get_platform() + + def setUp(self): + super(BuildTestCase, self).setUp() + + # mock util.get_platform + self._get_platform_called = False + self._get_platform = util.get_platform + util.get_platform = self._mock_get_platform + + def tearDown(self): + super(BuildTestCase, self).tearDown() + util.get_platform = self._get_platform + + def test_formats(self): + + # let's create a command and make sure + # we can fix the format + pkg_pth, dist = self.create_dist() + cmd = bdist(dist) + cmd.formats = ['msi'] + cmd.ensure_finalized() + self.assertEqual(cmd.formats, ['msi']) + + # what format bdist offers ? + # XXX an explicit list in bdist is + # not the best way to bdist_* commands + # we should add a registry + formats = sorted(('zip', 'gztar', 'bztar', 'ztar', + 'tar', 'wininst', 'msi')) + found = sorted(cmd.format_command) + self.assertEqual(found, formats) + + def test_skip_build(self): + pkg_pth, dist = self.create_dist() + cmd = bdist(dist) + cmd.skip_build = False + cmd.formats = ['ztar'] + cmd.ensure_finalized() + self.assertFalse(self._get_platform_called) + + pkg_pth, dist = self.create_dist() + cmd = bdist(dist) + cmd.skip_build = True + cmd.formats = ['ztar'] + cmd.ensure_finalized() + self.assertTrue(self._get_platform_called) + + def test_show_formats(self): + __, stdout = captured_stdout(show_formats) + + # the output should be a header line + one line per format + num_formats = len(bdist.format_commands) + output = [line for line in stdout.split('\n') + if line.strip().startswith('--formats=')] + self.assertEqual(len(output), num_formats) + + +def test_suite(): + return unittest.makeSuite(BuildTestCase) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_command_bdist_dumb.py b/Lib/packaging/tests/test_command_bdist_dumb.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_bdist_dumb.py @@ -0,0 +1,103 @@ +"""Tests for distutils.command.bdist_dumb.""" + +import sys +import os + +# zlib is not used here, but if it's not available +# test_simple_built will fail +try: + import zlib +except ImportError: + zlib = None + +from packaging.dist import Distribution +from packaging.command.bdist_dumb import bdist_dumb +from packaging.tests import unittest, support + + +SETUP_PY = """\ +from distutils.run import setup +import foo + +setup(name='foo', version='0.1', py_modules=['foo'], + url='xxx', author='xxx', author_email='xxx') +""" + + +class BuildDumbTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def setUp(self): + super(BuildDumbTestCase, self).setUp() + self.old_location = os.getcwd() + self.old_sys_argv = sys.argv, sys.argv[:] + + def tearDown(self): + os.chdir(self.old_location) + sys.argv = self.old_sys_argv[0] + sys.argv[:] = self.old_sys_argv[1] + super(BuildDumbTestCase, self).tearDown() + + @unittest.skipUnless(zlib, "requires zlib") + def test_simple_built(self): + + # let's create a simple package + tmp_dir = self.mkdtemp() + pkg_dir = os.path.join(tmp_dir, 'foo') + os.mkdir(pkg_dir) + self.write_file((pkg_dir, 'setup.py'), SETUP_PY) + self.write_file((pkg_dir, 'foo.py'), '#') + self.write_file((pkg_dir, 'MANIFEST.in'), 'include foo.py') + self.write_file((pkg_dir, 'README'), '') + + dist = Distribution({'name': 'foo', 'version': '0.1', + 'py_modules': ['foo'], + 'url': 'xxx', 'author': 'xxx', + 'author_email': 'xxx'}) + dist.script_name = 'setup.py' + os.chdir(pkg_dir) + + sys.argv[:] = ['setup.py'] + cmd = bdist_dumb(dist) + + # so the output is the same no matter + # what is the platform + cmd.format = 'zip' + + cmd.ensure_finalized() + cmd.run() + + # see what we have + dist_created = os.listdir(os.path.join(pkg_dir, 'dist')) + base = "%s.%s" % (dist.get_fullname(), cmd.plat_name) + if os.name == 'os2': + base = base.replace(':', '-') + + wanted = ['%s.zip' % base] + self.assertEqual(dist_created, wanted) + + # now let's check what we have in the zip file + # XXX to be done + + def test_finalize_options(self): + pkg_dir, dist = self.create_dist() + os.chdir(pkg_dir) + cmd = bdist_dumb(dist) + self.assertEqual(cmd.bdist_dir, None) + cmd.finalize_options() + + # bdist_dir is initialized to bdist_base/dumb if not set + base = cmd.get_finalized_command('bdist').bdist_base + self.assertEqual(cmd.bdist_dir, os.path.join(base, 'dumb')) + + # the format is set to a default value depending on the os.name + default = cmd.default_format[os.name] + self.assertEqual(cmd.format, default) + + +def test_suite(): + return unittest.makeSuite(BuildDumbTestCase) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_command_bdist_msi.py b/Lib/packaging/tests/test_command_bdist_msi.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_bdist_msi.py @@ -0,0 +1,25 @@ +"""Tests for distutils.command.bdist_msi.""" +import sys + +from packaging.tests import unittest, support + + +class BDistMSITestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + @unittest.skipUnless(sys.platform == "win32", "runs only on win32") + def test_minimal(self): + # minimal test XXX need more tests + from packaging.command.bdist_msi import bdist_msi + pkg_pth, dist = self.create_dist() + cmd = bdist_msi(dist) + cmd.ensure_finalized() + + +def test_suite(): + return unittest.makeSuite(BDistMSITestCase) + + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_command_bdist_wininst.py b/Lib/packaging/tests/test_command_bdist_wininst.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_bdist_wininst.py @@ -0,0 +1,32 @@ +"""Tests for distutils.command.bdist_wininst.""" + +from packaging.command.bdist_wininst import bdist_wininst +from packaging.tests import unittest, support + + +class BuildWinInstTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def test_get_exe_bytes(self): + + # issue5731: command was broken on non-windows platforms + # this test makes sure it works now for every platform + # let's create a command + pkg_pth, dist = self.create_dist() + cmd = bdist_wininst(dist) + cmd.ensure_finalized() + + # let's run the code that finds the right wininst*.exe file + # and make sure it finds it and returns its content + # no matter what platform we have + exe_file = cmd.get_exe_bytes() + self.assertGreater(len(exe_file), 10) + + +def test_suite(): + return unittest.makeSuite(BuildWinInstTestCase) + + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_command_build.py b/Lib/packaging/tests/test_command_build.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_build.py @@ -0,0 +1,55 @@ +"""Tests for distutils.command.build.""" +import os +import sys + +from packaging.command.build import build +from sysconfig import get_platform +from packaging.tests import unittest, support + + +class BuildTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def test_finalize_options(self): + pkg_dir, dist = self.create_dist() + cmd = build(dist) + cmd.finalize_options() + + # if not specified, plat_name gets the current platform + self.assertEqual(cmd.plat_name, get_platform()) + + # build_purelib is build + lib + wanted = os.path.join(cmd.build_base, 'lib') + self.assertEqual(cmd.build_purelib, wanted) + + # build_platlib is 'build/lib.platform-x.x[-pydebug]' + # examples: + # build/lib.macosx-10.3-i386-2.7 + plat_spec = '.%s-%s' % (cmd.plat_name, sys.version[0:3]) + if hasattr(sys, 'gettotalrefcount'): + self.assertTrue(cmd.build_platlib.endswith('-pydebug')) + plat_spec += '-pydebug' + wanted = os.path.join(cmd.build_base, 'lib' + plat_spec) + self.assertEqual(cmd.build_platlib, wanted) + + # by default, build_lib = build_purelib + self.assertEqual(cmd.build_lib, cmd.build_purelib) + + # build_temp is build/temp. + wanted = os.path.join(cmd.build_base, 'temp' + plat_spec) + self.assertEqual(cmd.build_temp, wanted) + + # build_scripts is build/scripts-x.x + wanted = os.path.join(cmd.build_base, 'scripts-' + sys.version[0:3]) + self.assertEqual(cmd.build_scripts, wanted) + + # executable is os.path.normpath(sys.executable) + self.assertEqual(cmd.executable, os.path.normpath(sys.executable)) + + +def test_suite(): + return unittest.makeSuite(BuildTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_build_clib.py b/Lib/packaging/tests/test_command_build_clib.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_build_clib.py @@ -0,0 +1,141 @@ +"""Tests for distutils.command.build_clib.""" +import os +import sys + +from packaging.util import find_executable +from packaging.command.build_clib import build_clib +from packaging.errors import PackagingSetupError +from packaging.tests import unittest, support + + +class BuildCLibTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def test_check_library_dist(self): + pkg_dir, dist = self.create_dist() + cmd = build_clib(dist) + + # 'libraries' option must be a list + self.assertRaises(PackagingSetupError, cmd.check_library_list, 'foo') + + # each element of 'libraries' must a 2-tuple + self.assertRaises(PackagingSetupError, cmd.check_library_list, + ['foo1', 'foo2']) + + # first element of each tuple in 'libraries' + # must be a string (the library name) + self.assertRaises(PackagingSetupError, cmd.check_library_list, + [(1, 'foo1'), ('name', 'foo2')]) + + # library name may not contain directory separators + self.assertRaises(PackagingSetupError, cmd.check_library_list, + [('name', 'foo1'), + ('another/name', 'foo2')]) + + # second element of each tuple must be a dictionary (build info) + self.assertRaises(PackagingSetupError, cmd.check_library_list, + [('name', {}), + ('another', 'foo2')]) + + # those work + libs = [('name', {}), ('name', {'ok': 'good'})] + cmd.check_library_list(libs) + + def test_get_source_files(self): + pkg_dir, dist = self.create_dist() + cmd = build_clib(dist) + + # "in 'libraries' option 'sources' must be present and must be + # a list of source filenames + cmd.libraries = [('name', {})] + self.assertRaises(PackagingSetupError, cmd.get_source_files) + + cmd.libraries = [('name', {'sources': 1})] + self.assertRaises(PackagingSetupError, cmd.get_source_files) + + cmd.libraries = [('name', {'sources': ['a', 'b']})] + self.assertEqual(cmd.get_source_files(), ['a', 'b']) + + cmd.libraries = [('name', {'sources': ('a', 'b')})] + self.assertEqual(cmd.get_source_files(), ['a', 'b']) + + cmd.libraries = [('name', {'sources': ('a', 'b')}), + ('name2', {'sources': ['c', 'd']})] + self.assertEqual(cmd.get_source_files(), ['a', 'b', 'c', 'd']) + + def test_build_libraries(self): + pkg_dir, dist = self.create_dist() + cmd = build_clib(dist) + + class FakeCompiler: + def compile(*args, **kw): + pass + create_static_lib = compile + + cmd.compiler = FakeCompiler() + + # build_libraries is also doing a bit of type checking + lib = [('name', {'sources': 'notvalid'})] + self.assertRaises(PackagingSetupError, cmd.build_libraries, lib) + + lib = [('name', {'sources': []})] + cmd.build_libraries(lib) + + lib = [('name', {'sources': ()})] + cmd.build_libraries(lib) + + def test_finalize_options(self): + pkg_dir, dist = self.create_dist() + cmd = build_clib(dist) + + cmd.include_dirs = 'one-dir' + cmd.finalize_options() + self.assertEqual(cmd.include_dirs, ['one-dir']) + + cmd.include_dirs = None + cmd.finalize_options() + self.assertEqual(cmd.include_dirs, []) + + cmd.distribution.libraries = 'WONTWORK' + self.assertRaises(PackagingSetupError, cmd.finalize_options) + + @unittest.skipIf(sys.platform == 'win32', 'disabled on win32') + def test_run(self): + pkg_dir, dist = self.create_dist() + cmd = build_clib(dist) + + foo_c = os.path.join(pkg_dir, 'foo.c') + self.write_file(foo_c, 'int main(void) { return 1;}\n') + cmd.libraries = [('foo', {'sources': [foo_c]})] + + build_temp = os.path.join(pkg_dir, 'build') + os.mkdir(build_temp) + cmd.build_temp = build_temp + cmd.build_clib = build_temp + + # before we run the command, we want to make sure + # all commands are present on the system + # by creating a compiler and checking its executables + from packaging.compiler import new_compiler, customize_compiler + + compiler = new_compiler() + customize_compiler(compiler) + for ccmd in compiler.executables.values(): + if ccmd is None: + continue + if find_executable(ccmd[0]) is None: + raise unittest.SkipTest("can't test") + + # this should work + cmd.run() + + # let's check the result + self.assertIn('libfoo.a', os.listdir(build_temp)) + + +def test_suite(): + return unittest.makeSuite(BuildCLibTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_build_ext.py b/Lib/packaging/tests/test_command_build_ext.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_build_ext.py @@ -0,0 +1,353 @@ +import os +import sys +import site +import shutil +import sysconfig +from io import StringIO +from packaging.dist import Distribution +from packaging.errors import UnknownFileError, CompileError +from packaging.command.build_ext import build_ext +from packaging.compiler.extension import Extension + +from packaging.tests import support, unittest, verbose, unload + +# http://bugs.python.org/issue4373 +# Don't load the xx module more than once. +ALREADY_TESTED = False + + +def _get_source_filename(): + srcdir = sysconfig.get_config_var('srcdir') + return os.path.join(srcdir, 'Modules', 'xxmodule.c') + + +class BuildExtTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + def setUp(self): + # Create a simple test environment + # Note that we're making changes to sys.path + super(BuildExtTestCase, self).setUp() + self.tmp_dir = self.mkdtemp() + self.sys_path = sys.path, sys.path[:] + sys.path.append(self.tmp_dir) + shutil.copy(_get_source_filename(), self.tmp_dir) + self.old_user_base = site.USER_BASE + site.USER_BASE = self.mkdtemp() + build_ext.USER_BASE = site.USER_BASE + + def test_build_ext(self): + global ALREADY_TESTED + xx_c = os.path.join(self.tmp_dir, 'xxmodule.c') + xx_ext = Extension('xx', [xx_c]) + dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]}) + dist.package_dir = self.tmp_dir + cmd = build_ext(dist) + if os.name == "nt": + # On Windows, we must build a debug version iff running + # a debug build of Python + cmd.debug = sys.executable.endswith("_d.exe") + cmd.build_lib = self.tmp_dir + cmd.build_temp = self.tmp_dir + + old_stdout = sys.stdout + if not verbose: + # silence compiler output + sys.stdout = StringIO() + try: + cmd.ensure_finalized() + cmd.run() + finally: + sys.stdout = old_stdout + + if ALREADY_TESTED: + return + else: + ALREADY_TESTED = True + + import xx + + for attr in ('error', 'foo', 'new', 'roj'): + self.assertTrue(hasattr(xx, attr)) + + self.assertEqual(xx.foo(2, 5), 7) + self.assertEqual(xx.foo(13, 15), 28) + self.assertEqual(xx.new().demo(), None) + doc = 'This is a template module just for instruction.' + self.assertEqual(xx.__doc__, doc) + self.assertTrue(isinstance(xx.Null(), xx.Null)) + self.assertTrue(isinstance(xx.Str(), xx.Str)) + + def tearDown(self): + # Get everything back to normal + unload('xx') + sys.path = self.sys_path[0] + sys.path[:] = self.sys_path[1] + if sys.version > "2.6": + site.USER_BASE = self.old_user_base + build_ext.USER_BASE = self.old_user_base + + super(BuildExtTestCase, self).tearDown() + + def test_solaris_enable_shared(self): + dist = Distribution({'name': 'xx'}) + cmd = build_ext(dist) + old = sys.platform + + sys.platform = 'sunos' # fooling finalize_options + from sysconfig import _CONFIG_VARS + + old_var = _CONFIG_VARS.get('Py_ENABLE_SHARED') + _CONFIG_VARS['Py_ENABLE_SHARED'] = 1 + try: + cmd.ensure_finalized() + finally: + sys.platform = old + if old_var is None: + del _CONFIG_VARS['Py_ENABLE_SHARED'] + else: + _CONFIG_VARS['Py_ENABLE_SHARED'] = old_var + + # make sure we get some library dirs under solaris + self.assertGreater(len(cmd.library_dirs), 0) + + @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') + def test_user_site(self): + dist = Distribution({'name': 'xx'}) + cmd = build_ext(dist) + + # making sure the user option is there + options = [name for name, short, label in + cmd.user_options] + self.assertIn('user', options) + + # setting a value + cmd.user = True + + # setting user based lib and include + lib = os.path.join(site.USER_BASE, 'lib') + incl = os.path.join(site.USER_BASE, 'include') + os.mkdir(lib) + os.mkdir(incl) + + # let's run finalize + cmd.ensure_finalized() + + # see if include_dirs and library_dirs + # were set + self.assertIn(lib, cmd.library_dirs) + self.assertIn(lib, cmd.rpath) + self.assertIn(incl, cmd.include_dirs) + + def test_optional_extension(self): + + # this extension will fail, but let's ignore this failure + # with the optional argument. + modules = [Extension('foo', ['xxx'], optional=False)] + dist = Distribution({'name': 'xx', 'ext_modules': modules}) + cmd = build_ext(dist) + cmd.ensure_finalized() + self.assertRaises((UnknownFileError, CompileError), + cmd.run) # should raise an error + + modules = [Extension('foo', ['xxx'], optional=True)] + dist = Distribution({'name': 'xx', 'ext_modules': modules}) + cmd = build_ext(dist) + cmd.ensure_finalized() + cmd.run() # should pass + + def test_finalize_options(self): + # Make sure Python's include directories (for Python.h, pyconfig.h, + # etc.) are in the include search path. + modules = [Extension('foo', ['xxx'], optional=False)] + dist = Distribution({'name': 'xx', 'ext_modules': modules}) + cmd = build_ext(dist) + cmd.finalize_options() + + py_include = sysconfig.get_path('include') + self.assertIn(py_include, cmd.include_dirs) + + plat_py_include = sysconfig.get_path('platinclude') + self.assertIn(plat_py_include, cmd.include_dirs) + + # make sure cmd.libraries is turned into a list + # if it's a string + cmd = build_ext(dist) + cmd.libraries = 'my_lib' + cmd.finalize_options() + self.assertEqual(cmd.libraries, ['my_lib']) + + # make sure cmd.library_dirs is turned into a list + # if it's a string + cmd = build_ext(dist) + cmd.library_dirs = 'my_lib_dir' + cmd.finalize_options() + self.assertIn('my_lib_dir', cmd.library_dirs) + + # make sure rpath is turned into a list + # if it's a list of os.pathsep's paths + cmd = build_ext(dist) + cmd.rpath = os.pathsep.join(['one', 'two']) + cmd.finalize_options() + self.assertEqual(cmd.rpath, ['one', 'two']) + + # XXX more tests to perform for win32 + + # make sure define is turned into 2-tuples + # strings if they are ','-separated strings + cmd = build_ext(dist) + cmd.define = 'one,two' + cmd.finalize_options() + self.assertEqual(cmd.define, [('one', '1'), ('two', '1')]) + + # make sure undef is turned into a list of + # strings if they are ','-separated strings + cmd = build_ext(dist) + cmd.undef = 'one,two' + cmd.finalize_options() + self.assertEqual(cmd.undef, ['one', 'two']) + + # make sure swig_opts is turned into a list + cmd = build_ext(dist) + cmd.swig_opts = None + cmd.finalize_options() + self.assertEqual(cmd.swig_opts, []) + + cmd = build_ext(dist) + cmd.swig_opts = '1 2' + cmd.finalize_options() + self.assertEqual(cmd.swig_opts, ['1', '2']) + + def test_get_source_files(self): + modules = [Extension('foo', ['xxx'], optional=False)] + dist = Distribution({'name': 'xx', 'ext_modules': modules}) + cmd = build_ext(dist) + cmd.ensure_finalized() + self.assertEqual(cmd.get_source_files(), ['xxx']) + + def test_compiler_option(self): + # cmd.compiler is an option and + # should not be overriden by a compiler instance + # when the command is run + dist = Distribution() + cmd = build_ext(dist) + cmd.compiler = 'unix' + cmd.ensure_finalized() + cmd.run() + self.assertEqual(cmd.compiler, 'unix') + + def test_get_outputs(self): + tmp_dir = self.mkdtemp() + c_file = os.path.join(tmp_dir, 'foo.c') + self.write_file(c_file, 'void initfoo(void) {};\n') + ext = Extension('foo', [c_file], optional=False) + dist = Distribution({'name': 'xx', + 'ext_modules': [ext]}) + cmd = build_ext(dist) + cmd.ensure_finalized() + self.assertEqual(len(cmd.get_outputs()), 1) + + if os.name == "nt": + cmd.debug = sys.executable.endswith("_d.exe") + + cmd.build_lib = os.path.join(self.tmp_dir, 'build') + cmd.build_temp = os.path.join(self.tmp_dir, 'tempt') + + # issue #5977 : distutils build_ext.get_outputs + # returns wrong result with --inplace + other_tmp_dir = os.path.realpath(self.mkdtemp()) + old_wd = os.getcwd() + os.chdir(other_tmp_dir) + try: + cmd.inplace = True + cmd.run() + so_file = cmd.get_outputs()[0] + finally: + os.chdir(old_wd) + self.assertTrue(os.path.exists(so_file)) + so_ext = sysconfig.get_config_var('SO') + self.assertTrue(so_file.endswith(so_ext)) + so_dir = os.path.dirname(so_file) + self.assertEqual(so_dir, other_tmp_dir) + + cmd.inplace = False + cmd.run() + so_file = cmd.get_outputs()[0] + self.assertTrue(os.path.exists(so_file)) + self.assertTrue(so_file.endswith(so_ext)) + so_dir = os.path.dirname(so_file) + self.assertEqual(so_dir, cmd.build_lib) + + # inplace = False, cmd.package = 'bar' + build_py = cmd.get_finalized_command('build_py') + 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] + self.assertEqual(path, cmd.build_lib) + + # inplace = True, cmd.package = 'bar' + cmd.inplace = True + other_tmp_dir = os.path.realpath(self.mkdtemp()) + old_wd = os.getcwd() + os.chdir(other_tmp_dir) + try: + path = cmd.get_ext_fullpath('foo') + finally: + os.chdir(old_wd) + # checking that the last directory is bar + path = os.path.split(path)[0] + lastdir = os.path.split(path)[-1] + self.assertEqual(lastdir, 'bar') + + def test_ext_fullpath(self): + ext = sysconfig.get_config_vars()['SO'] + # building lxml.etree inplace + #etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c') + #etree_ext = Extension('lxml.etree', [etree_c]) + #dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]}) + dist = Distribution() + cmd = build_ext(dist) + cmd.inplace = True + cmd.distribution.package_dir = 'src' + cmd.distribution.packages = ['lxml', 'lxml.html'] + curdir = os.getcwd() + wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext) + path = cmd.get_ext_fullpath('lxml.etree') + self.assertEqual(wanted, path) + + # building lxml.etree not inplace + cmd.inplace = False + cmd.build_lib = os.path.join(curdir, 'tmpdir') + wanted = os.path.join(curdir, 'tmpdir', 'lxml', 'etree' + ext) + path = cmd.get_ext_fullpath('lxml.etree') + self.assertEqual(wanted, path) + + # building twisted.runner.portmap not inplace + build_py = cmd.get_finalized_command('build_py') + 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', + 'portmap' + ext) + self.assertEqual(wanted, path) + + # building twisted.runner.portmap inplace + cmd.inplace = True + path = cmd.get_ext_fullpath('twisted.runner.portmap') + wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext) + self.assertEqual(wanted, path) + + +def test_suite(): + src = _get_source_filename() + if not os.path.exists(src): + if verbose: + print ('test_build_ext: Cannot find source code (test' + ' must run in python build dir)') + return unittest.TestSuite() + else: + return unittest.makeSuite(BuildExtTestCase) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_command_build_py.py b/Lib/packaging/tests/test_command_build_py.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_build_py.py @@ -0,0 +1,124 @@ +"""Tests for distutils.command.build_py.""" + +import os +import sys + +from packaging.command.build_py import build_py +from packaging.dist import Distribution +from packaging.errors import PackagingFileError + +from packaging.tests import unittest, support + + +class BuildPyTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def test_package_data(self): + sources = self.mkdtemp() + 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(pkg_dir, "README.txt"), "w") + try: + f.write("Info about this package") + finally: + f.close() + + destination = self.mkdtemp() + + dist = Distribution({"packages": ["pkg"], + "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=False, + build_lib=destination, + use_2to3_fixers=None, + convert_2to3_doctests=None, + use_2to3=False) + dist.packages = ["pkg"] + dist.package_data = {"pkg": ["README.txt"]} + dist.package_dir = sources + + cmd = build_py(dist) + cmd.compile = True + cmd.ensure_finalized() + self.assertEqual(cmd.package_data, dist.package_data) + + cmd.run() + + # This makes sure the list of outputs includes byte-compiled + # files for Python modules but not for package data files + # (there shouldn't *be* byte-code files for those!). + # + self.assertEqual(len(cmd.get_outputs()), 3) + pkgdest = os.path.join(destination, "pkg") + files = os.listdir(pkgdest) + self.assertIn("__init__.py", files) + self.assertIn("__init__.pyc", files) + self.assertIn("README.txt", files) + + def test_empty_package_dir(self): + # See SF 1668596/1720897. + cwd = os.getcwd() + + # create the distribution files. + sources = self.mkdtemp() + 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() + + try: + dist = Distribution({"packages": ["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") + dist.script_args = ["build"] + dist.parse_command_line() + + try: + dist.run_commands() + except PackagingFileError as e: + self.fail("failed package_data test when package_dir is ''") + finally: + # Restore state. + os.chdir(cwd) + sys.stdout = old_stdout + + @unittest.skipUnless(hasattr(sys, 'dont_write_bytecode'), + 'sys.dont_write_bytecode not supported') + def test_dont_write_bytecode(self): + # makes sure byte_compile is not used + pkg_dir, dist = self.create_dist() + cmd = build_py(dist) + cmd.compile = True + cmd.optimize = 1 + + old_dont_write_bytecode = sys.dont_write_bytecode + sys.dont_write_bytecode = True + try: + cmd.byte_compile([]) + finally: + sys.dont_write_bytecode = old_dont_write_bytecode + + self.assertIn('byte-compiling is disabled', self.get_logs()[0]) + +def test_suite(): + return unittest.makeSuite(BuildPyTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_build_scripts.py b/Lib/packaging/tests/test_command_build_scripts.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_build_scripts.py @@ -0,0 +1,112 @@ +"""Tests for distutils.command.build_scripts.""" + +import os +import sys +import sysconfig +from packaging.dist import Distribution +from packaging.command.build_scripts import build_scripts + +from packaging.tests import unittest, support + + +class BuildScriptsTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def test_default_settings(self): + cmd = self.get_build_scripts_cmd("/foo/bar", []) + self.assertFalse(cmd.force) + self.assertIs(cmd.build_dir, None) + + cmd.finalize_options() + + self.assertTrue(cmd.force) + self.assertEqual(cmd.build_dir, "/foo/bar") + + def test_build(self): + source = self.mkdtemp() + target = self.mkdtemp() + expected = self.write_sample_scripts(source) + + cmd = self.get_build_scripts_cmd(target, + [os.path.join(source, fn) + for fn in expected]) + cmd.finalize_options() + cmd.run() + + built = os.listdir(target) + for name in expected: + self.assertIn(name, built) + + def get_build_scripts_cmd(self, target, scripts): + dist = Distribution() + dist.scripts = scripts + dist.command_obj["build"] = support.DummyCommand( + build_scripts=target, + force=True, + executable=sys.executable, + use_2to3=False, + use_2to3_fixers=None, + convert_2to3_doctests=None + ) + return build_scripts(dist) + + def write_sample_scripts(self, dir): + expected = [] + expected.append("script1.py") + self.write_script(dir, "script1.py", + ("#! /usr/bin/env python2.3\n" + "# bogus script w/ Python sh-bang\n" + "pass\n")) + expected.append("script2.py") + self.write_script(dir, "script2.py", + ("#!/usr/bin/python\n" + "# bogus script w/ Python sh-bang\n" + "pass\n")) + expected.append("shell.sh") + self.write_script(dir, "shell.sh", + ("#!/bin/sh\n" + "# bogus shell script w/ sh-bang\n" + "exit 0\n")) + return expected + + def write_script(self, dir, name, text): + f = open(os.path.join(dir, name), "w") + try: + f.write(text) + finally: + f.close() + + def test_version_int(self): + source = self.mkdtemp() + target = self.mkdtemp() + expected = self.write_sample_scripts(source) + + + cmd = self.get_build_scripts_cmd(target, + [os.path.join(source, fn) + for fn in expected]) + cmd.finalize_options() + + # http://bugs.python.org/issue4524 + # + # On linux-g++-32 with command line `./configure --enable-ipv6 + # --with-suffix=3`, python is compiled okay but the build scripts + # failed when writing the name of the executable + old = sysconfig.get_config_vars().get('VERSION') + sysconfig._CONFIG_VARS['VERSION'] = 4 + try: + cmd.run() + finally: + if old is not None: + sysconfig._CONFIG_VARS['VERSION'] = old + + built = os.listdir(target) + for name in expected: + self.assertIn(name, built) + +def test_suite(): + return unittest.makeSuite(BuildScriptsTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_check.py b/Lib/packaging/tests/test_command_check.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_check.py @@ -0,0 +1,131 @@ +"""Tests for distutils.command.check.""" + +import logging +from packaging.command.check import check +from packaging.metadata import _HAS_DOCUTILS +from packaging.errors import PackagingSetupError, MetadataMissingError +from packaging.tests import unittest, support + + +class CheckTestCase(support.LoggingCatcher, + support.TempdirManager, + unittest.TestCase): + + def _run(self, metadata=None, **options): + if metadata is None: + metadata = {'name': 'xxx', 'version': '1.2'} + pkg_info, dist = self.create_dist(**metadata) + cmd = check(dist) + cmd.initialize_options() + for name, value in options.items(): + setattr(cmd, name, value) + cmd.ensure_finalized() + cmd.run() + return cmd + + def test_check_metadata(self): + # let's run the command with no metadata at all + # by default, check is checking the metadata + # should have some warnings + cmd = self._run() + # trick: using assertNotEqual with an empty list will give us a more + # useful error message than assertGreater(.., 0) when the code change + # and the test fails + self.assertNotEqual([], self.get_logs(logging.WARNING)) + + # now let's add the required fields + # and run it again, to make sure we don't get + # any warning anymore + self.loghandler.flush() + metadata = {'home_page': 'xxx', 'author': 'xxx', + 'author_email': 'xxx', + 'name': 'xxx', 'version': '4.2', + } + cmd = self._run(metadata) + self.assertEqual([], self.get_logs(logging.WARNING)) + + # now with the strict mode, we should + # get an error if there are missing metadata + self.assertRaises(MetadataMissingError, self._run, {}, **{'strict': 1}) + self.assertRaises(PackagingSetupError, self._run, + {'name': 'xxx', 'version': 'xxx'}, **{'strict': 1}) + + # and of course, no error when all metadata fields are present + self.loghandler.flush() + cmd = self._run(metadata, strict=True) + self.assertEqual([], self.get_logs(logging.WARNING)) + + def test_check_metadata_1_2(self): + # let's run the command with no metadata at all + # by default, check is checking the metadata + # should have some warnings + cmd = self._run() + self.assertNotEqual([], self.get_logs(logging.WARNING)) + + # now let's add the required fields and run it again, to make sure we + # don't get any warning anymore let's use requires_python as a marker + # to enforce Metadata-Version 1.2 + metadata = {'home_page': 'xxx', 'author': 'xxx', + 'author_email': 'xxx', + 'name': 'xxx', 'version': '4.2', + 'requires_python': '2.4', + } + self.loghandler.flush() + cmd = self._run(metadata) + self.assertEqual([], self.get_logs(logging.WARNING)) + + # now with the strict mode, we should + # get an error if there are missing metadata + self.assertRaises(MetadataMissingError, self._run, {}, **{'strict': 1}) + self.assertRaises(PackagingSetupError, self._run, + {'name': 'xxx', 'version': 'xxx'}, **{'strict': 1}) + + # complain about version format + metadata['version'] = 'xxx' + self.assertRaises(PackagingSetupError, self._run, metadata, + **{'strict': 1}) + + # now with correct version format again + metadata['version'] = '4.2' + self.loghandler.flush() + cmd = self._run(metadata, strict=True) + self.assertEqual([], self.get_logs(logging.WARNING)) + + @unittest.skipUnless(_HAS_DOCUTILS, "requires docutils") + def test_check_restructuredtext(self): + # let's see if it detects broken rest in long_description + broken_rest = 'title\n===\n\ntest' + pkg_info, dist = self.create_dist(description=broken_rest) + cmd = check(dist) + cmd.check_restructuredtext() + self.assertEqual(len(self.get_logs(logging.WARNING)), 1) + + self.loghandler.flush() + pkg_info, dist = self.create_dist(description='title\n=====\n\ntest') + cmd = check(dist) + cmd.check_restructuredtext() + self.assertEqual([], self.get_logs(logging.WARNING)) + + def test_check_all(self): + self.assertRaises(PackagingSetupError, self._run, + {'name': 'xxx', 'version': 'xxx'}, **{'strict': 1, + 'all': 1}) + self.assertRaises(MetadataMissingError, self._run, + {}, **{'strict': 1, + 'all': 1}) + + def test_check_hooks(self): + pkg_info, dist = self.create_dist() + dist.command_options['install_dist'] = { + 'pre_hook': ('file', {"a": 'some.nonextistant.hook.ghrrraarrhll'}), + } + cmd = check(dist) + cmd.check_hooks_resolvable() + self.assertEqual(len(self.get_logs(logging.WARNING)), 1) + + +def test_suite(): + return unittest.makeSuite(CheckTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_clean.py b/Lib/packaging/tests/test_command_clean.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_clean.py @@ -0,0 +1,48 @@ +"""Tests for distutils.command.clean.""" +import os + +from packaging.command.clean import clean +from packaging.tests import unittest, support + + +class cleanTestCase(support.TempdirManager, support.LoggingCatcher, + unittest.TestCase): + + def test_simple_run(self): + pkg_dir, dist = self.create_dist() + cmd = clean(dist) + + # let's add some elements clean should remove + dirs = [(d, os.path.join(pkg_dir, d)) + for d in ('build_temp', 'build_lib', 'bdist_base', + 'build_scripts', 'build_base')] + + for name, path in dirs: + os.mkdir(path) + setattr(cmd, name, path) + if name == 'build_base': + continue + for f in ('one', 'two', 'three'): + self.write_file(os.path.join(path, f)) + + # let's run the command + cmd.all = True + cmd.ensure_finalized() + cmd.run() + + # make sure the files where removed + for name, path in dirs: + self.assertFalse(os.path.exists(path), + '%r was not removed' % path) + + # let's run the command again (should spit warnings but succeed) + cmd.all = True + cmd.ensure_finalized() + cmd.run() + + +def test_suite(): + return unittest.makeSuite(cleanTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_cmd.py b/Lib/packaging/tests/test_command_cmd.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_cmd.py @@ -0,0 +1,101 @@ +"""Tests for distutils.cmd.""" +import os + +from packaging.command.cmd import Command +from packaging.dist import Distribution +from packaging.errors import PackagingOptionError +from packaging.tests import support, unittest + + +class MyCmd(Command): + def initialize_options(self): + pass + + +class CommandTestCase(support.LoggingCatcher, + unittest.TestCase): + + def setUp(self): + super(CommandTestCase, self).setUp() + dist = Distribution() + self.cmd = MyCmd(dist) + + def test_make_file(self): + cmd = self.cmd + + # making sure it raises when infiles is not a string or a list/tuple + self.assertRaises(TypeError, cmd.make_file, + infiles=1, outfile='', func='func', args=()) + + # making sure execute gets called properly + def _execute(func, args, exec_msg, level): + self.assertEqual(exec_msg, 'generating out from in') + cmd.force = True + cmd.execute = _execute + cmd.make_file(infiles='in', outfile='out', func='func', args=()) + + def test_dump_options(self): + cmd = self.cmd + cmd.option1 = 1 + cmd.option2 = 1 + cmd.user_options = [('option1', '', ''), ('option2', '', '')] + cmd.dump_options() + + wanted = ["command options for 'MyCmd':", ' option1 = 1', + ' option2 = 1'] + msgs = self.get_logs() + self.assertEqual(msgs, wanted) + + def test_ensure_string(self): + cmd = self.cmd + cmd.option1 = 'ok' + cmd.ensure_string('option1') + + cmd.option2 = None + cmd.ensure_string('option2', 'xxx') + self.assertTrue(hasattr(cmd, 'option2')) + + cmd.option3 = 1 + self.assertRaises(PackagingOptionError, cmd.ensure_string, 'option3') + + def test_ensure_string_list(self): + cmd = self.cmd + cmd.option1 = 'ok,dok' + cmd.ensure_string_list('option1') + self.assertEqual(cmd.option1, ['ok', 'dok']) + + cmd.yes_string_list = ['one', 'two', 'three'] + cmd.yes_string_list2 = 'ok' + cmd.ensure_string_list('yes_string_list') + cmd.ensure_string_list('yes_string_list2') + self.assertEqual(cmd.yes_string_list, ['one', 'two', 'three']) + self.assertEqual(cmd.yes_string_list2, ['ok']) + + cmd.not_string_list = ['one', 2, 'three'] + cmd.not_string_list2 = object() + self.assertRaises(PackagingOptionError, + cmd.ensure_string_list, 'not_string_list') + + self.assertRaises(PackagingOptionError, + cmd.ensure_string_list, 'not_string_list2') + + def test_ensure_filename(self): + cmd = self.cmd + cmd.option1 = __file__ + cmd.ensure_filename('option1') + cmd.option2 = 'xxx' + self.assertRaises(PackagingOptionError, cmd.ensure_filename, 'option2') + + def test_ensure_dirname(self): + cmd = self.cmd + cmd.option1 = os.path.dirname(__file__) or os.curdir + cmd.ensure_dirname('option1') + cmd.option2 = 'xxx' + self.assertRaises(PackagingOptionError, cmd.ensure_dirname, 'option2') + + +def test_suite(): + return unittest.makeSuite(CommandTestCase) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_command_config.py b/Lib/packaging/tests/test_command_config.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_config.py @@ -0,0 +1,76 @@ +"""Tests for distutils.command.config.""" +import os +import sys +import logging + +from packaging.command.config import dump_file, config +from packaging.tests import unittest, support + + +class ConfigTestCase(support.LoggingCatcher, + support.TempdirManager, + unittest.TestCase): + + def test_dump_file(self): + this_file = __file__.rstrip('co') + with open(this_file) as f: + numlines = len(f.readlines()) + + dump_file(this_file, 'I am the header') + + logs = [] + for log in self.get_logs(logging.INFO): + logs.extend(line for line in log.split('\n')) + self.assertEqual(len(logs), numlines + 2) + + @unittest.skipIf(sys.platform == 'win32', 'disabled on win32') + def test_search_cpp(self): + pkg_dir, dist = self.create_dist() + cmd = config(dist) + + # simple pattern searches + match = cmd.search_cpp(pattern='xxx', body='// xxx') + self.assertEqual(match, 0) + + match = cmd.search_cpp(pattern='_configtest', body='// xxx') + self.assertEqual(match, 1) + + def test_finalize_options(self): + # finalize_options does a bit of transformation + # on options + pkg_dir, dist = self.create_dist() + cmd = config(dist) + cmd.include_dirs = 'one%stwo' % os.pathsep + cmd.libraries = 'one' + cmd.library_dirs = 'three%sfour' % os.pathsep + cmd.ensure_finalized() + + self.assertEqual(cmd.include_dirs, ['one', 'two']) + self.assertEqual(cmd.libraries, ['one']) + self.assertEqual(cmd.library_dirs, ['three', 'four']) + + def test_clean(self): + # _clean removes files + tmp_dir = self.mkdtemp() + f1 = os.path.join(tmp_dir, 'one') + f2 = os.path.join(tmp_dir, 'two') + + self.write_file(f1, 'xxx') + self.write_file(f2, 'xxx') + + for f in (f1, f2): + self.assertTrue(os.path.exists(f)) + + pkg_dir, dist = self.create_dist() + cmd = config(dist) + cmd._clean(f1, f2) + + for f in (f1, f2): + self.assertFalse(os.path.exists(f)) + + +def test_suite(): + return unittest.makeSuite(ConfigTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_install_data.py b/Lib/packaging/tests/test_command_install_data.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_install_data.py @@ -0,0 +1,80 @@ +"""Tests for packaging.command.install_data.""" +import os +import sysconfig +from sysconfig import _get_default_scheme +from packaging.tests import unittest, support +from packaging.command.install_data import install_data + + +class InstallDataTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def test_simple_run(self): + self.addCleanup(setattr, sysconfig, '_SCHEMES', sysconfig._SCHEMES) + + pkg_dir, dist = self.create_dist() + cmd = install_data(dist) + cmd.install_dir = inst = os.path.join(pkg_dir, 'inst') + + sysconfig._SCHEMES.set(_get_default_scheme(), 'inst', + os.path.join(pkg_dir, 'inst')) + sysconfig._SCHEMES.set(_get_default_scheme(), 'inst2', + os.path.join(pkg_dir, 'inst2')) + + one = os.path.join(pkg_dir, 'one') + self.write_file(one, 'xxx') + inst2 = os.path.join(pkg_dir, 'inst2') + two = os.path.join(pkg_dir, 'two') + self.write_file(two, 'xxx') + + cmd.data_files = {one: '{inst}/one', two: '{inst2}/two'} + self.assertCountEqual(cmd.get_inputs(), [one, two]) + + # let's run the command + cmd.ensure_finalized() + cmd.run() + + # let's check the result + self.assertEqual(len(cmd.get_outputs()), 2) + rtwo = os.path.split(two)[-1] + self.assertTrue(os.path.exists(os.path.join(inst2, rtwo))) + rone = os.path.split(one)[-1] + self.assertTrue(os.path.exists(os.path.join(inst, rone))) + cmd.outfiles = [] + + # let's try with warn_dir one + cmd.warn_dir = True + cmd.ensure_finalized() + cmd.run() + + # let's check the result + self.assertEqual(len(cmd.get_outputs()), 2) + self.assertTrue(os.path.exists(os.path.join(inst2, rtwo))) + self.assertTrue(os.path.exists(os.path.join(inst, rone))) + cmd.outfiles = [] + + # now using root and empty dir + cmd.root = os.path.join(pkg_dir, 'root') + three = os.path.join(cmd.install_dir, 'three') + self.write_file(three, 'xx') + + sysconfig._SCHEMES.set(_get_default_scheme(), 'inst3', + cmd.install_dir) + + cmd.data_files = {one: '{inst}/one', two: '{inst2}/two', + three: '{inst3}/three'} + cmd.ensure_finalized() + cmd.run() + + # let's check the result + self.assertEqual(len(cmd.get_outputs()), 3) + self.assertTrue(os.path.exists(os.path.join(inst2, rtwo))) + self.assertTrue(os.path.exists(os.path.join(inst, rone))) + + +def test_suite(): + return unittest.makeSuite(InstallDataTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_install_dist.py b/Lib/packaging/tests/test_command_install_dist.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_install_dist.py @@ -0,0 +1,210 @@ +"""Tests for packaging.command.install.""" + +import os +import sys + +from sysconfig import (get_scheme_names, get_config_vars, + _SCHEMES, get_config_var, get_path) + +_CONFIG_VARS = get_config_vars() + +from packaging.tests import captured_stdout + +from packaging.command.install_dist import install_dist +from packaging.command import install_dist as install_module +from packaging.dist import Distribution +from packaging.errors import PackagingOptionError + +from packaging.tests import unittest, support + + +class InstallTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def test_home_installation_scheme(self): + # This ensure two things: + # - that --home generates the desired set of directory names + # - test --home is supported on all platforms + builddir = self.mkdtemp() + destination = os.path.join(builddir, "installation") + + dist = Distribution({"name": "foopkg"}) + # script_name need not exist, it just need to be initialized + dist.script_name = os.path.join(builddir, "setup.py") + dist.command_obj["build"] = support.DummyCommand( + build_base=builddir, + build_lib=os.path.join(builddir, "lib"), + ) + + old_posix_prefix = _SCHEMES.get('posix_prefix', 'platinclude') + old_posix_home = _SCHEMES.get('posix_home', 'platinclude') + + new_path = '{platbase}/include/python{py_version_short}' + _SCHEMES.set('posix_prefix', 'platinclude', new_path) + _SCHEMES.set('posix_home', 'platinclude', '{platbase}/include/python') + + try: + cmd = install_dist(dist) + cmd.home = destination + cmd.ensure_finalized() + finally: + _SCHEMES.set('posix_prefix', 'platinclude', old_posix_prefix) + _SCHEMES.set('posix_home', 'platinclude', old_posix_home) + + self.assertEqual(cmd.install_base, destination) + self.assertEqual(cmd.install_platbase, destination) + + def check_path(got, expected): + got = os.path.normpath(got) + expected = os.path.normpath(expected) + self.assertEqual(got, expected) + + libdir = os.path.join(destination, "lib", "python") + check_path(cmd.install_lib, libdir) + check_path(cmd.install_platlib, libdir) + check_path(cmd.install_purelib, libdir) + check_path(cmd.install_headers, + os.path.join(destination, "include", "python", "foopkg")) + check_path(cmd.install_scripts, os.path.join(destination, "bin")) + check_path(cmd.install_data, destination) + + @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') + def test_user_site(self): + # test install with --user + # preparing the environment for the test + self.old_user_base = get_config_var('userbase') + self.old_user_site = get_path('purelib', '%s_user' % os.name) + self.tmpdir = self.mkdtemp() + self.user_base = os.path.join(self.tmpdir, 'B') + self.user_site = os.path.join(self.tmpdir, 'S') + _CONFIG_VARS['userbase'] = self.user_base + scheme = '%s_user' % os.name + _SCHEMES.set(scheme, 'purelib', self.user_site) + + def _expanduser(path): + if path[0] == '~': + path = os.path.normpath(self.tmpdir) + path[1:] + return path + + self.old_expand = os.path.expanduser + os.path.expanduser = _expanduser + + try: + # this is the actual test + self._test_user_site() + finally: + _CONFIG_VARS['userbase'] = self.old_user_base + _SCHEMES.set(scheme, 'purelib', self.old_user_site) + os.path.expanduser = self.old_expand + + def _test_user_site(self): + schemes = get_scheme_names() + for key in ('nt_user', 'posix_user', 'os2_home'): + self.assertIn(key, schemes) + + dist = Distribution({'name': 'xx'}) + cmd = install_dist(dist) + # making sure the user option is there + options = [name for name, short, lable in + cmd.user_options] + self.assertIn('user', options) + + # setting a value + cmd.user = True + + # user base and site shouldn't be created yet + self.assertFalse(os.path.exists(self.user_base)) + self.assertFalse(os.path.exists(self.user_site)) + + # let's run finalize + cmd.ensure_finalized() + + # now they should + self.assertTrue(os.path.exists(self.user_base)) + self.assertTrue(os.path.exists(self.user_site)) + + self.assertIn('userbase', cmd.config_vars) + self.assertIn('usersite', cmd.config_vars) + + def test_handle_extra_path(self): + dist = Distribution({'name': 'xx', 'extra_path': 'path,dirs'}) + cmd = install_dist(dist) + + # two elements + cmd.handle_extra_path() + self.assertEqual(cmd.extra_path, ['path', 'dirs']) + self.assertEqual(cmd.extra_dirs, 'dirs') + self.assertEqual(cmd.path_file, 'path') + + # one element + cmd.extra_path = ['path'] + cmd.handle_extra_path() + self.assertEqual(cmd.extra_path, ['path']) + self.assertEqual(cmd.extra_dirs, 'path') + self.assertEqual(cmd.path_file, 'path') + + # none + dist.extra_path = cmd.extra_path = None + cmd.handle_extra_path() + self.assertEqual(cmd.extra_path, None) + self.assertEqual(cmd.extra_dirs, '') + self.assertEqual(cmd.path_file, None) + + # three elements (no way !) + cmd.extra_path = 'path,dirs,again' + self.assertRaises(PackagingOptionError, cmd.handle_extra_path) + + def test_finalize_options(self): + dist = Distribution({'name': 'xx'}) + cmd = install_dist(dist) + + # must supply either prefix/exec-prefix/home or + # install-base/install-platbase -- not both + cmd.prefix = 'prefix' + cmd.install_base = 'base' + self.assertRaises(PackagingOptionError, cmd.finalize_options) + + # must supply either home or prefix/exec-prefix -- not both + cmd.install_base = None + cmd.home = 'home' + self.assertRaises(PackagingOptionError, cmd.finalize_options) + + if sys.version >= '2.6': + # can't combine user with with prefix/exec_prefix/home or + # install_(plat)base + cmd.prefix = None + cmd.user = 'user' + self.assertRaises(PackagingOptionError, cmd.finalize_options) + + def test_old_record(self): + # test pre-PEP 376 --record option (outside dist-info dir) + install_dir = self.mkdtemp() + pkgdir, dist = self.create_dist() + + dist = Distribution() + cmd = install_dist(dist) + dist.command_obj['install_dist'] = cmd + cmd.root = install_dir + cmd.record = os.path.join(pkgdir, 'filelist') + cmd.ensure_finalized() + cmd.run() + + # 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) + try: + self.assertEqual(len(f.readlines()), 4) + finally: + f.close() + + # XXX test that fancy_getopt is okay with options named + # record and no-record but unrelated + + +def test_suite(): + return unittest.makeSuite(InstallTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_install_distinfo.py b/Lib/packaging/tests/test_command_install_distinfo.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_install_distinfo.py @@ -0,0 +1,192 @@ +"""Tests for ``packaging.command.install_distinfo``. """ + +import os +import csv +import hashlib +import sys + +from packaging.command.install_distinfo import install_distinfo +from packaging.command.cmd import Command +from packaging.metadata import Metadata +from packaging.tests import unittest, support + + +class DummyInstallCmd(Command): + + def __init__(self, dist=None): + self.outputs = [] + self.distribution = dist + + def __getattr__(self, name): + return None + + def ensure_finalized(self): + pass + + def get_outputs(self): + return (self.outputs + + self.get_finalized_command('install_distinfo').get_outputs()) + + +class InstallDistinfoTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + checkLists = lambda self, x, y: self.assertListEqual(sorted(x), sorted(y)) + + def test_empty_install(self): + pkg_dir, dist = self.create_dist(name='foo', + version='1.0') + install_dir = self.mkdtemp() + + install = DummyInstallCmd(dist) + dist.command_obj['install_dist'] = install + + cmd = install_distinfo(dist) + dist.command_obj['install_distinfo'] = cmd + + cmd.initialize_options() + cmd.distinfo_dir = install_dir + cmd.ensure_finalized() + cmd.run() + + self.checkLists(os.listdir(install_dir), ['foo-1.0.dist-info']) + + dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') + self.checkLists(os.listdir(dist_info), + ['METADATA', 'RECORD', 'REQUESTED', 'INSTALLER']) + with open(os.path.join(dist_info, 'INSTALLER')) as fp: + self.assertEqual(fp.read(), 'distutils') + with open(os.path.join(dist_info, 'REQUESTED')) as fp: + self.assertEqual(fp.read(), '') + meta_path = os.path.join(dist_info, 'METADATA') + self.assertTrue(Metadata(path=meta_path).check()) + + def test_installer(self): + pkg_dir, dist = self.create_dist(name='foo', + version='1.0') + install_dir = self.mkdtemp() + + install = DummyInstallCmd(dist) + dist.command_obj['install_dist'] = install + + cmd = install_distinfo(dist) + dist.command_obj['install_distinfo'] = cmd + + cmd.initialize_options() + cmd.distinfo_dir = install_dir + cmd.installer = 'bacon-python' + cmd.ensure_finalized() + cmd.run() + + dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') + with open(os.path.join(dist_info, 'INSTALLER')) as fp: + self.assertEqual(fp.read(), 'bacon-python') + + def test_requested(self): + pkg_dir, dist = self.create_dist(name='foo', + version='1.0') + install_dir = self.mkdtemp() + + install = DummyInstallCmd(dist) + dist.command_obj['install_dist'] = install + + cmd = install_distinfo(dist) + dist.command_obj['install_distinfo'] = cmd + + cmd.initialize_options() + cmd.distinfo_dir = install_dir + cmd.requested = False + cmd.ensure_finalized() + cmd.run() + + dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') + self.checkLists(os.listdir(dist_info), + ['METADATA', 'RECORD', 'INSTALLER']) + + def test_no_record(self): + pkg_dir, dist = self.create_dist(name='foo', + version='1.0') + install_dir = self.mkdtemp() + + install = DummyInstallCmd(dist) + dist.command_obj['install_dist'] = install + + cmd = install_distinfo(dist) + dist.command_obj['install_distinfo'] = cmd + + cmd.initialize_options() + cmd.distinfo_dir = install_dir + cmd.no_record = True + cmd.ensure_finalized() + cmd.run() + + dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') + self.checkLists(os.listdir(dist_info), + ['METADATA', 'REQUESTED', 'INSTALLER']) + + def test_record(self): + pkg_dir, dist = self.create_dist(name='foo', + version='1.0') + install_dir = self.mkdtemp() + + install = DummyInstallCmd(dist) + dist.command_obj['install_dist'] = install + + fake_dists = os.path.join(os.path.dirname(__file__), 'fake_dists') + fake_dists = os.path.realpath(fake_dists) + + # for testing, we simply add all files from _backport's fake_dists + dirs = [] + for dir in os.listdir(fake_dists): + full_path = os.path.join(fake_dists, dir) + if (not dir.endswith('.egg') or dir.endswith('.egg-info') or + dir.endswith('.dist-info')) and os.path.isdir(full_path): + dirs.append(full_path) + + for dir in dirs: + for path, subdirs, files in os.walk(dir): + install.outputs += [os.path.join(path, f) for f in files] + install.outputs += [os.path.join('path', f + 'c') + for f in files if f.endswith('.py')] + + cmd = install_distinfo(dist) + dist.command_obj['install_distinfo'] = cmd + + cmd.initialize_options() + cmd.distinfo_dir = install_dir + cmd.ensure_finalized() + cmd.run() + + dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') + + expected = [] + for f in install.get_outputs(): + if (f.endswith('.pyc') or f == os.path.join( + install_dir, 'foo-1.0.dist-info', 'RECORD')): + expected.append([f, '', '']) + else: + size = os.path.getsize(f) + md5 = hashlib.md5() + with open(f) as fp: + md5.update(fp.read().encode()) + hash = md5.hexdigest() + expected.append([f, hash, str(size)]) + + parsed = [] + with open(os.path.join(dist_info, 'RECORD'), 'r') as f: + reader = csv.reader(f, delimiter=',', + lineterminator=os.linesep, + quotechar='"') + parsed = list(reader) + + self.maxDiff = None + self.checkLists(parsed, expected) + + +def test_suite(): + return unittest.makeSuite(InstallDistinfoTestCase) + + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_install_headers.py b/Lib/packaging/tests/test_command_install_headers.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_install_headers.py @@ -0,0 +1,38 @@ +"""Tests for packaging.command.install_headers.""" +import os + +from packaging.command.install_headers import install_headers +from packaging.tests import unittest, support + + +class InstallHeadersTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def test_simple_run(self): + # we have two headers + header_list = self.mkdtemp() + header1 = os.path.join(header_list, 'header1') + header2 = os.path.join(header_list, 'header2') + self.write_file(header1) + self.write_file(header2) + headers = [header1, header2] + + pkg_dir, dist = self.create_dist(headers=headers) + cmd = install_headers(dist) + self.assertEqual(cmd.get_inputs(), headers) + + # let's run the command + cmd.install_dir = os.path.join(pkg_dir, 'inst') + cmd.ensure_finalized() + cmd.run() + + # let's check the results + self.assertEqual(len(cmd.get_outputs()), 2) + + +def test_suite(): + return unittest.makeSuite(InstallHeadersTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_install_lib.py b/Lib/packaging/tests/test_command_install_lib.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_install_lib.py @@ -0,0 +1,111 @@ +"""Tests for packaging.command.install_data.""" +import sys +import os + +from packaging.tests import unittest, support +from packaging.command.install_lib import install_lib +from packaging.compiler.extension import Extension +from packaging.errors import PackagingOptionError + +try: + no_bytecode = sys.dont_write_bytecode + bytecode_support = True +except AttributeError: + no_bytecode = False + bytecode_support = False + + +class InstallLibTestCase(support.TempdirManager, + support.LoggingCatcher, + support.EnvironRestorer, + unittest.TestCase): + + restore_environ = ['PYTHONPATH'] + + def test_finalize_options(self): + pkg_dir, dist = self.create_dist() + cmd = install_lib(dist) + + cmd.finalize_options() + self.assertTrue(cmd.compile) + self.assertEqual(cmd.optimize, 0) + + # optimize must be 0, 1, or 2 + cmd.optimize = 'foo' + self.assertRaises(PackagingOptionError, cmd.finalize_options) + cmd.optimize = '4' + self.assertRaises(PackagingOptionError, cmd.finalize_options) + + cmd.optimize = '2' + cmd.finalize_options() + self.assertEqual(cmd.optimize, 2) + + @unittest.skipIf(no_bytecode, 'byte-compile not supported') + def test_byte_compile(self): + pkg_dir, dist = self.create_dist() + cmd = install_lib(dist) + cmd.compile = True + cmd.optimize = 1 + + f = os.path.join(pkg_dir, 'foo.py') + self.write_file(f, '# python file') + cmd.byte_compile([f]) + self.assertTrue(os.path.exists(os.path.join(pkg_dir, 'foo.pyc'))) + self.assertTrue(os.path.exists(os.path.join(pkg_dir, 'foo.pyo'))) + + def test_get_outputs(self): + pkg_dir, dist = self.create_dist() + cmd = install_lib(dist) + + # setting up a dist environment + cmd.compile = True + cmd.optimize = 1 + cmd.install_dir = pkg_dir + f = os.path.join(pkg_dir, '__init__.py') + self.write_file(f, '# python package') + cmd.distribution.ext_modules = [Extension('foo', ['xxx'])] + cmd.distribution.packages = [pkg_dir] + cmd.distribution.script_name = 'setup.py' + + # get_output should return 4 elements + self.assertEqual(len(cmd.get_outputs()), 4) + + def test_get_inputs(self): + pkg_dir, dist = self.create_dist() + cmd = install_lib(dist) + + # setting up a dist environment + cmd.compile = True + cmd.optimize = 1 + cmd.install_dir = pkg_dir + f = os.path.join(pkg_dir, '__init__.py') + self.write_file(f, '# python package') + cmd.distribution.ext_modules = [Extension('foo', ['xxx'])] + cmd.distribution.packages = [pkg_dir] + cmd.distribution.script_name = 'setup.py' + + # get_input should return 2 elements + self.assertEqual(len(cmd.get_inputs()), 2) + + @unittest.skipUnless(bytecode_support, + 'sys.dont_write_bytecode not supported') + def test_dont_write_bytecode(self): + # makes sure byte_compile is not used + pkg_dir, dist = self.create_dist() + cmd = install_lib(dist) + cmd.compile = True + cmd.optimize = 1 + + self.addCleanup(setattr, sys, 'dont_write_bytecode', + sys.dont_write_bytecode) + sys.dont_write_bytecode = True + cmd.byte_compile([]) + + self.assertIn('byte-compiling is disabled', self.get_logs()[0]) + + +def test_suite(): + return unittest.makeSuite(InstallLibTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_install_scripts.py b/Lib/packaging/tests/test_command_install_scripts.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_install_scripts.py @@ -0,0 +1,78 @@ +"""Tests for packaging.command.install_scripts.""" +import os + +from packaging.tests import unittest, support +from packaging.command.install_scripts import install_scripts +from packaging.dist import Distribution + + +class InstallScriptsTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def test_default_settings(self): + dist = Distribution() + dist.command_obj["build"] = support.DummyCommand( + build_scripts="/foo/bar") + dist.command_obj["install_dist"] = support.DummyCommand( + install_scripts="/splat/funk", + force=True, + skip_build=True, + ) + cmd = install_scripts(dist) + self.assertFalse(cmd.force) + self.assertFalse(cmd.skip_build) + self.assertIs(cmd.build_dir, None) + self.assertIs(cmd.install_dir, None) + + cmd.finalize_options() + + self.assertTrue(cmd.force) + self.assertTrue(cmd.skip_build) + self.assertEqual(cmd.build_dir, "/foo/bar") + self.assertEqual(cmd.install_dir, "/splat/funk") + + def test_installation(self): + source = self.mkdtemp() + expected = [] + + def write_script(name, text): + expected.append(name) + f = open(os.path.join(source, name), "w") + try: + f.write(text) + finally: + f.close() + + write_script("script1.py", ("#! /usr/bin/env python2.3\n" + "# bogus script w/ Python sh-bang\n" + "pass\n")) + write_script("script2.py", ("#!/usr/bin/python\n" + "# bogus script w/ Python sh-bang\n" + "pass\n")) + write_script("shell.sh", ("#!/bin/sh\n" + "# bogus shell script w/ sh-bang\n" + "exit 0\n")) + + target = self.mkdtemp() + dist = Distribution() + dist.command_obj["build"] = support.DummyCommand(build_scripts=source) + dist.command_obj["install_dist"] = support.DummyCommand( + install_scripts=target, + force=True, + skip_build=True, + ) + cmd = install_scripts(dist) + cmd.finalize_options() + cmd.run() + + installed = os.listdir(target) + for name in expected: + self.assertIn(name, installed) + + +def test_suite(): + return unittest.makeSuite(InstallScriptsTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_register.py b/Lib/packaging/tests/test_command_register.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_register.py @@ -0,0 +1,259 @@ +"""Tests for packaging.command.register.""" +import os +import getpass +import urllib.request +import urllib.error +import urllib.parse + +try: + import docutils + DOCUTILS_SUPPORT = True +except ImportError: + DOCUTILS_SUPPORT = False + +from packaging.tests import unittest, support +from packaging.command import register as register_module +from packaging.command.register import register +from packaging.errors import PackagingSetupError + + +PYPIRC_NOPASSWORD = """\ +[distutils] + +index-servers = + server1 + +[server1] +username:me +""" + +WANTED_PYPIRC = """\ +[distutils] +index-servers = + pypi + +[pypi] +username:tarek +password:password +""" + + +class Inputs: + """Fakes user inputs.""" + def __init__(self, *answers): + self.answers = answers + self.index = 0 + + def __call__(self, prompt=''): + try: + return self.answers[self.index] + finally: + self.index += 1 + + +class FakeOpener: + """Fakes a PyPI server""" + def __init__(self): + self.reqs = [] + + def __call__(self, *args): + return self + + def open(self, req): + self.reqs.append(req) + return self + + def read(self): + return 'xxx' + + +class RegisterTestCase(support.TempdirManager, + support.EnvironRestorer, + support.LoggingCatcher, + unittest.TestCase): + + restore_environ = ['HOME'] + + def setUp(self): + super(RegisterTestCase, self).setUp() + self.tmp_dir = self.mkdtemp() + self.rc = os.path.join(self.tmp_dir, '.pypirc') + os.environ['HOME'] = self.tmp_dir + + # patching the password prompt + self._old_getpass = getpass.getpass + + def _getpass(prompt): + return 'password' + + getpass.getpass = _getpass + self.old_opener = urllib.request.build_opener + self.conn = urllib.request.build_opener = FakeOpener() + + def tearDown(self): + getpass.getpass = self._old_getpass + urllib.request.build_opener = self.old_opener + if hasattr(register_module, 'input'): + del register_module.input + super(RegisterTestCase, self).tearDown() + + def _get_cmd(self, metadata=None): + if metadata is None: + metadata = {'url': 'xxx', 'author': 'xxx', + 'author_email': 'xxx', + 'name': 'xxx', 'version': 'xxx'} + pkg_info, dist = self.create_dist(**metadata) + return register(dist) + + def test_create_pypirc(self): + # this test makes sure a .pypirc file + # is created when requested. + + # let's create a register instance + cmd = self._get_cmd() + + # we shouldn't have a .pypirc file yet + self.assertFalse(os.path.exists(self.rc)) + + # patching input and getpass.getpass + # so register gets happy + # Here's what we are faking : + # use your existing login (choice 1.) + # Username : 'tarek' + # Password : 'password' + # Save your login (y/N)? : 'y' + inputs = Inputs('1', 'tarek', 'y') + register_module.input = inputs + cmd.ensure_finalized() + cmd.run() + + # we should have a brand new .pypirc file + self.assertTrue(os.path.exists(self.rc)) + + # with the content similar to WANTED_PYPIRC + with open(self.rc) as fp: + content = fp.read() + self.assertEqual(content, WANTED_PYPIRC) + + # now let's make sure the .pypirc file generated + # really works : we shouldn't be asked anything + # if we run the command again + def _no_way(prompt=''): + raise AssertionError(prompt) + + register_module.input = _no_way + cmd.show_response = True + cmd.ensure_finalized() + cmd.run() + + # let's see what the server received : we should + # have 2 similar requests + self.assertEqual(len(self.conn.reqs), 2) + req1 = dict(self.conn.reqs[0].headers) + req2 = dict(self.conn.reqs[1].headers) + self.assertEqual(req2['Content-length'], req1['Content-length']) + self.assertIn('xxx', self.conn.reqs[1].data) + + def test_password_not_in_file(self): + + self.write_file(self.rc, PYPIRC_NOPASSWORD) + cmd = self._get_cmd() + cmd.finalize_options() + cmd._set_config() + cmd.send_metadata() + + # dist.password should be set + # therefore used afterwards by other commands + self.assertEqual(cmd.distribution.password, 'password') + + def test_registration(self): + # this test runs choice 2 + cmd = self._get_cmd() + inputs = Inputs('2', 'tarek', 'tarek at ziade.org') + register_module.input = inputs + # let's run the command + # FIXME does this send a real request? use a mock server + cmd.ensure_finalized() + cmd.run() + + # we should have send a request + self.assertEqual(len(self.conn.reqs), 1) + req = self.conn.reqs[0] + headers = dict(req.headers) + self.assertEqual(headers['Content-length'], '608') + self.assertIn('tarek', req.data) + + def test_password_reset(self): + # this test runs choice 3 + cmd = self._get_cmd() + inputs = Inputs('3', 'tarek at ziade.org') + register_module.input = inputs + cmd.ensure_finalized() + cmd.run() + + # we should have send a request + self.assertEqual(len(self.conn.reqs), 1) + req = self.conn.reqs[0] + headers = dict(req.headers) + self.assertEqual(headers['Content-length'], '290') + self.assertIn('tarek', req.data) + + @unittest.skipUnless(DOCUTILS_SUPPORT, 'needs docutils') + def test_strict(self): + # testing the script option + # when on, the register command stops if + # the metadata is incomplete or if + # long_description is not reSt compliant + + # empty metadata + cmd = self._get_cmd({'name': 'xxx', 'version': 'xxx'}) + cmd.ensure_finalized() + cmd.strict = True + inputs = Inputs('1', 'tarek', 'y') + register_module.input = inputs + self.assertRaises(PackagingSetupError, cmd.run) + + # metadata is OK but long_description is broken + metadata = {'home_page': 'xxx', 'author': 'xxx', + 'author_email': '?x?x?', + 'name': 'xxx', 'version': 'xxx', + 'description': 'title\n==\n\ntext'} + + cmd = self._get_cmd(metadata) + cmd.ensure_finalized() + cmd.strict = True + + self.assertRaises(PackagingSetupError, cmd.run) + + # now something that works + metadata['description'] = 'title\n=====\n\ntext' + cmd = self._get_cmd(metadata) + cmd.ensure_finalized() + cmd.strict = True + inputs = Inputs('1', 'tarek', 'y') + register_module.input = inputs + cmd.ensure_finalized() + cmd.run() + + # strict is not by default + cmd = self._get_cmd() + cmd.ensure_finalized() + inputs = Inputs('1', 'tarek', 'y') + register_module.input = inputs + cmd.ensure_finalized() + cmd.run() + + def test_register_pep345(self): + cmd = self._get_cmd({}) + cmd.ensure_finalized() + cmd.distribution.metadata['Requires-Dist'] = ['lxml'] + data = cmd.build_post_data('submit') + self.assertEqual(data['metadata_version'], '1.2') + self.assertEqual(data['requires_dist'], ['lxml']) + + +def test_suite(): + return unittest.makeSuite(RegisterTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_sdist.py b/Lib/packaging/tests/test_command_sdist.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_sdist.py @@ -0,0 +1,407 @@ +"""Tests for packaging.command.sdist.""" +import os +import zipfile +import tarfile +import logging + +# zlib is not used here, but if it's not available +# the tests that use zipfile may fail +try: + import zlib +except ImportError: + zlib = None + +try: + import grp + import pwd + UID_GID_SUPPORT = True +except ImportError: + UID_GID_SUPPORT = False + +from os.path import join +from packaging.tests import captured_stdout +from packaging.command.sdist import sdist +from packaging.command.sdist import show_formats +from packaging.dist import Distribution +from packaging.tests import unittest +from packaging.errors import PackagingOptionError +from packaging.util import find_executable +from packaging.tests import support +from shutil import get_archive_formats + +SETUP_PY = """ +from packaging.core import setup +import somecode + +setup(name='fake') +""" + +MANIFEST = """\ +# file GENERATED by packaging, do NOT edit +README +inroot.txt +data%(sep)sdata.dt +scripts%(sep)sscript.py +some%(sep)sfile.txt +some%(sep)sother_file.txt +somecode%(sep)s__init__.py +somecode%(sep)sdoc.dat +somecode%(sep)sdoc.txt +""" + + +def builder(dist, filelist): + filelist.append('bah') + + +class SDistTestCase(support.TempdirManager, + support.LoggingCatcher, + support.EnvironRestorer, + unittest.TestCase): + + restore_environ = ['HOME'] + + def setUp(self): + # PyPIRCCommandTestCase creates a temp dir already + # and put it in self.tmp_dir + super(SDistTestCase, self).setUp() + self.tmp_dir = self.mkdtemp() + os.environ['HOME'] = self.tmp_dir + # setting up an environment + self.old_path = os.getcwd() + os.mkdir(join(self.tmp_dir, 'somecode')) + os.mkdir(join(self.tmp_dir, 'dist')) + # a package, and a README + self.write_file((self.tmp_dir, 'README'), 'xxx') + self.write_file((self.tmp_dir, 'somecode', '__init__.py'), '#') + self.write_file((self.tmp_dir, 'setup.py'), SETUP_PY) + os.chdir(self.tmp_dir) + + def tearDown(self): + # back to normal + os.chdir(self.old_path) + super(SDistTestCase, self).tearDown() + + def get_cmd(self, metadata=None): + """Returns a cmd""" + if metadata is None: + metadata = {'name': 'fake', 'version': '1.0', + 'url': 'xxx', 'author': 'xxx', + 'author_email': 'xxx'} + dist = Distribution(metadata) + dist.script_name = 'setup.py' + dist.packages = ['somecode'] + dist.include_package_data = True + cmd = sdist(dist) + cmd.dist_dir = 'dist' + return dist, cmd + + @unittest.skipUnless(zlib, "requires zlib") + def test_prune_file_list(self): + # this test creates a package with some vcs dirs in it + # and launch sdist to make sure they get pruned + # on all systems + + # creating VCS directories with some files in them + os.mkdir(join(self.tmp_dir, 'somecode', '.svn')) + + self.write_file((self.tmp_dir, 'somecode', '.svn', 'ok.py'), 'xxx') + + os.mkdir(join(self.tmp_dir, 'somecode', '.hg')) + self.write_file((self.tmp_dir, 'somecode', '.hg', + 'ok'), 'xxx') + + os.mkdir(join(self.tmp_dir, 'somecode', '.git')) + self.write_file((self.tmp_dir, 'somecode', '.git', + 'ok'), 'xxx') + + # now building a sdist + dist, cmd = self.get_cmd() + + # zip is available universally + # (tar might not be installed under win32) + cmd.formats = ['zip'] + + cmd.ensure_finalized() + cmd.run() + + # now let's check what we have + dist_folder = join(self.tmp_dir, 'dist') + files = os.listdir(dist_folder) + self.assertEqual(files, ['fake-1.0.zip']) + + with zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip')) as zip_file: + content = zip_file.namelist() + + # making sure everything has been pruned correctly + self.assertEqual(len(content), 3) + + @unittest.skipUnless(zlib, "requires zlib") + @unittest.skipIf(find_executable('tar') is None or + find_executable('gzip') is None, + 'requires tar and gzip programs') + def test_make_distribution(self): + # building a sdist + dist, cmd = self.get_cmd() + + # creating a gztar then a tar + cmd.formats = ['gztar', 'tar'] + cmd.ensure_finalized() + cmd.run() + + # making sure we have two files + dist_folder = join(self.tmp_dir, 'dist') + result = sorted(os.listdir(dist_folder)) + self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz']) + + os.remove(join(dist_folder, 'fake-1.0.tar')) + os.remove(join(dist_folder, 'fake-1.0.tar.gz')) + + # now trying a tar then a gztar + cmd.formats = ['tar', 'gztar'] + + cmd.ensure_finalized() + cmd.run() + + result = sorted(os.listdir(dist_folder)) + self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz']) + + @unittest.skipUnless(zlib, "requires zlib") + def test_add_defaults(self): + + # http://bugs.python.org/issue2279 + + # add_default should also include + # data_files and package_data + dist, cmd = self.get_cmd() + + # filling data_files by pointing files + # in package_data + dist.package_data = {'': ['*.cfg', '*.dat'], + 'somecode': ['*.txt']} + self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') + self.write_file((self.tmp_dir, 'somecode', 'doc.dat'), '#') + + # adding some data in data_files + data_dir = join(self.tmp_dir, 'data') + os.mkdir(data_dir) + self.write_file((data_dir, 'data.dt'), '#') + some_dir = join(self.tmp_dir, 'some') + os.mkdir(some_dir) + self.write_file((self.tmp_dir, 'inroot.txt'), '#') + self.write_file((some_dir, 'file.txt'), '#') + self.write_file((some_dir, 'other_file.txt'), '#') + + dist.data_files = {'data/data.dt': '{appdata}/data.dt', + 'inroot.txt': '{appdata}/inroot.txt', + 'some/file.txt': '{appdata}/file.txt', + 'some/other_file.txt': '{appdata}/other_file.txt'} + + # adding a script + script_dir = join(self.tmp_dir, 'scripts') + os.mkdir(script_dir) + self.write_file((script_dir, 'script.py'), '#') + dist.scripts = [join('scripts', 'script.py')] + + cmd.formats = ['zip'] + cmd.use_defaults = True + + cmd.ensure_finalized() + cmd.run() + + # now let's check what we have + dist_folder = join(self.tmp_dir, 'dist') + files = os.listdir(dist_folder) + self.assertEqual(files, ['fake-1.0.zip']) + + with zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip')) as zip_file: + content = zip_file.namelist() + + # Making sure everything was added. This includes 9 code and data + # files in addition to PKG-INFO. + self.assertEqual(len(content), 10) + + # Checking the MANIFEST + with open(join(self.tmp_dir, 'MANIFEST')) as fp: + manifest = fp.read() + self.assertEqual(manifest, MANIFEST % {'sep': os.sep}) + + @unittest.skipUnless(zlib, "requires zlib") + def test_metadata_check_option(self): + # testing the `check-metadata` option + dist, cmd = self.get_cmd(metadata={'name': 'xxx', 'version': 'xxx'}) + + # this should raise some warnings + # with the check subcommand + cmd.ensure_finalized() + cmd.run() + warnings = self.get_logs(logging.WARN) + self.assertEqual(len(warnings), 3) + + # trying with a complete set of metadata + self.loghandler.flush() + dist, cmd = self.get_cmd() + cmd.ensure_finalized() + cmd.metadata_check = False + cmd.run() + warnings = self.get_logs(logging.WARN) + # removing manifest generated warnings + warnings = [warn for warn in warnings if + not warn.endswith('-- skipping')] + # the remaining warning is about the use of the default file list + self.assertEqual(len(warnings), 1) + + def test_show_formats(self): + __, stdout = captured_stdout(show_formats) + + # the output should be a header line + one line per format + num_formats = len(get_archive_formats()) + output = [line for line in stdout.split('\n') + if line.strip().startswith('--formats=')] + self.assertEqual(len(output), num_formats) + + def test_finalize_options(self): + + dist, cmd = self.get_cmd() + cmd.finalize_options() + + # default options set by finalize + self.assertEqual(cmd.manifest, 'MANIFEST') + self.assertEqual(cmd.dist_dir, 'dist') + + # formats has to be a string splitable on (' ', ',') or + # a stringlist + cmd.formats = 1 + self.assertRaises(PackagingOptionError, cmd.finalize_options) + cmd.formats = ['zip'] + cmd.finalize_options() + + # formats has to be known + cmd.formats = 'supazipa' + self.assertRaises(PackagingOptionError, cmd.finalize_options) + + @unittest.skipUnless(zlib, "requires zlib") + @unittest.skipUnless(UID_GID_SUPPORT, "requires grp and pwd support") + @unittest.skipIf(find_executable('tar') is None or + find_executable('gzip') is None, + 'requires tar and gzip programs') + def test_make_distribution_owner_group(self): + # building a sdist + dist, cmd = self.get_cmd() + + # creating a gztar and specifying the owner+group + cmd.formats = ['gztar'] + cmd.owner = pwd.getpwuid(0)[0] + cmd.group = grp.getgrgid(0)[0] + cmd.ensure_finalized() + cmd.run() + + # making sure we have the good rights + archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz') + with tarfile.open(archive_name) as archive: + for member in archive.getmembers(): + self.assertEqual(member.uid, 0) + self.assertEqual(member.gid, 0) + + # building a sdist again + dist, cmd = self.get_cmd() + + # creating a gztar + cmd.formats = ['gztar'] + cmd.ensure_finalized() + cmd.run() + + # making sure we have the good rights + archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz') + with tarfile.open(archive_name) as archive: + + # note that we are not testing the group ownership here + # because, depending on the platforms and the container + # rights (see #7408) + for member in archive.getmembers(): + self.assertEqual(member.uid, os.getuid()) + + def test_get_file_list(self): + # make sure MANIFEST is recalculated + dist, cmd = self.get_cmd() + # filling data_files by pointing files in package_data + dist.package_data = {'somecode': ['*.txt']} + self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') + cmd.ensure_finalized() + cmd.run() + + # Should produce four lines. Those lines are one comment, one default + # (README) and two package files. + with open(cmd.manifest) as f: + manifest = [line.strip() for line in f.read().split('\n') + if line.strip() != ''] + self.assertEqual(len(manifest), 4) + + # Adding a file + self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#') + + # make sure build_py is reinitialized, like a fresh run + build_py = dist.get_command_obj('build_py') + build_py.finalized = False + build_py.ensure_finalized() + + cmd.run() + + with open(cmd.manifest) as f: + manifest2 = [line.strip() for line in f.read().split('\n') + if line.strip() != ''] + + # Do we have the new file in MANIFEST? + self.assertEqual(len(manifest2), 5) + self.assertIn('doc2.txt', manifest2[-1]) + + def test_manifest_marker(self): + # check that autogenerated MANIFESTs have a marker + dist, cmd = self.get_cmd() + cmd.ensure_finalized() + cmd.run() + + with open(cmd.manifest) as f: + manifest = [line.strip() for line in f.read().split('\n') + if line.strip() != ''] + + self.assertEqual(manifest[0], + '# file GENERATED by packaging, do NOT edit') + + def test_manual_manifest(self): + # check that a MANIFEST without a marker is left alone + dist, cmd = self.get_cmd() + cmd.ensure_finalized() + self.write_file((self.tmp_dir, cmd.manifest), 'README.manual') + cmd.run() + + with open(cmd.manifest) as f: + manifest = [line.strip() for line in f.read().split('\n') + if line.strip() != ''] + + self.assertEqual(manifest, ['README.manual']) + + def test_template(self): + dist, cmd = self.get_cmd() + dist.extra_files = ['include yeah'] + cmd.ensure_finalized() + self.write_file((self.tmp_dir, 'yeah'), 'xxx') + cmd.run() + with open(cmd.manifest) as f: + content = f.read() + + self.assertIn('yeah', content) + + def test_manifest_builder(self): + dist, cmd = self.get_cmd() + cmd.manifest_builders = 'packaging.tests.test_command_sdist.builder' + cmd.ensure_finalized() + cmd.run() + self.assertIn('bah', cmd.filelist.files) + + +def test_suite(): + return unittest.makeSuite(SDistTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_test.py b/Lib/packaging/tests/test_command_test.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_test.py @@ -0,0 +1,225 @@ +import os +import re +import sys +import shutil +import logging +import unittest as ut1 +import packaging.database + +from os.path import join +from operator import getitem, setitem, delitem +from packaging.command.build import build +from packaging.tests import unittest +from packaging.tests.support import (TempdirManager, EnvironRestorer, + LoggingCatcher) +from packaging.command.test import test +from packaging.command import set_command +from packaging.dist import Distribution + + +EXPECTED_OUTPUT_RE = r'''FAIL: test_blah \(myowntestmodule.SomeTest\) +---------------------------------------------------------------------- +Traceback \(most recent call last\): + File ".+/myowntestmodule.py", line \d+, in test_blah + self.fail\("horribly"\) +AssertionError: horribly +''' + +here = os.path.dirname(os.path.abspath(__file__)) + + +class MockBuildCmd(build): + build_lib = "mock build lib" + command_name = 'build' + plat_name = 'whatever' + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + self._record.append("build has run") + + +class TestTest(TempdirManager, + EnvironRestorer, + LoggingCatcher, + unittest.TestCase): + + restore_environ = ['PYTHONPATH'] + + def setUp(self): + super(TestTest, self).setUp() + self.addCleanup(packaging.database.clear_cache) + new_pythonpath = os.path.dirname(os.path.dirname(here)) + pythonpath = os.environ.get('PYTHONPATH') + if pythonpath is not None: + new_pythonpath = os.pathsep.join((new_pythonpath, pythonpath)) + os.environ['PYTHONPATH'] = new_pythonpath + + def assert_re_match(self, pattern, string): + def quote(s): + lines = ['## ' + line for line in s.split('\n')] + sep = ["#" * 60] + return [''] + sep + lines + sep + msg = quote(pattern) + ["didn't match"] + quote(string) + msg = "\n".join(msg) + if not re.search(pattern, string): + self.fail(msg) + + def prepare_dist(self, dist_name): + pkg_dir = join(os.path.dirname(__file__), "dists", dist_name) + temp_pkg_dir = join(self.mkdtemp(), dist_name) + shutil.copytree(pkg_dir, temp_pkg_dir) + return temp_pkg_dir + + def safely_replace(self, obj, attr, + new_val=None, delete=False, dictionary=False): + """Replace a object's attribute returning to its original state at the + end of the test run. Creates the attribute if not present before + (deleting afterwards). When delete=True, makes sure the value is del'd + for the test run. If dictionary is set to True, operates of its items + rather than attributes.""" + if dictionary: + _setattr, _getattr, _delattr = setitem, getitem, delitem + + def _hasattr(_dict, value): + return value in _dict + else: + _setattr, _getattr, _delattr, _hasattr = (setattr, getattr, + delattr, hasattr) + + orig_has_attr = _hasattr(obj, attr) + if orig_has_attr: + orig_val = _getattr(obj, attr) + + if delete is False: + _setattr(obj, attr, new_val) + elif orig_has_attr: + _delattr(obj, attr) + + def do_cleanup(): + if orig_has_attr: + _setattr(obj, attr, orig_val) + elif _hasattr(obj, attr): + _delattr(obj, attr) + + self.addCleanup(do_cleanup) + + def test_runs_unittest(self): + module_name, a_module = self.prepare_a_module() + record = [] + a_module.recorder = lambda *args: record.append("suite") + + class MockTextTestRunner: + def __init__(*_, **__): + pass + + def run(_self, suite): + record.append("run") + + self.safely_replace(ut1, "TextTestRunner", MockTextTestRunner) + + dist = Distribution() + cmd = test(dist) + cmd.suite = "%s.recorder" % module_name + cmd.run() + self.assertEqual(record, ["suite", "run"]) + + def test_builds_before_running_tests(self): + self.addCleanup(set_command, 'packaging.command.build.build') + set_command('packaging.tests.test_command_test.MockBuildCmd') + + dist = Distribution() + dist.get_command_obj('build')._record = record = [] + cmd = test(dist) + cmd.runner = self.prepare_named_function(lambda: None) + cmd.ensure_finalized() + cmd.run() + self.assertEqual(['build has run'], record) + + def _test_works_with_2to3(self): + pass + + def test_checks_requires(self): + dist = Distribution() + cmd = test(dist) + phony_project = 'ohno_ohno-impossible_1234-name_stop-that!' + cmd.tests_require = [phony_project] + cmd.ensure_finalized() + logs = self.get_logs(logging.WARNING) + self.assertEqual(1, len(logs)) + self.assertIn(phony_project, logs[0]) + + def prepare_a_module(self): + tmp_dir = self.mkdtemp() + sys.path.append(tmp_dir) + self.addCleanup(sys.path.remove, tmp_dir) + + self.write_file((tmp_dir, 'packaging_tests_a.py'), '') + import packaging_tests_a as a_module + return "packaging_tests_a", a_module + + def prepare_named_function(self, func): + module_name, a_module = self.prepare_a_module() + a_module.recorder = func + return "%s.recorder" % module_name + + def test_custom_runner(self): + dist = Distribution() + cmd = test(dist) + record = [] + cmd.runner = self.prepare_named_function( + lambda: record.append("runner called")) + cmd.ensure_finalized() + cmd.run() + self.assertEqual(["runner called"], record) + + def prepare_mock_ut2(self): + class MockUTClass: + def __init__(*_, **__): + pass + + def discover(self): + pass + + def run(self, _): + pass + + class MockUTModule: + TestLoader = MockUTClass + TextTestRunner = MockUTClass + + mock_ut2 = MockUTModule() + self.safely_replace(sys.modules, "unittest2", + mock_ut2, dictionary=True) + return mock_ut2 + + def test_gets_unittest_discovery(self): + mock_ut2 = self.prepare_mock_ut2() + dist = Distribution() + cmd = test(dist) + self.safely_replace(ut1.TestLoader, "discover", lambda: None) + self.assertEqual(cmd.get_ut_with_discovery(), ut1) + + del ut1.TestLoader.discover + self.assertEqual(cmd.get_ut_with_discovery(), mock_ut2) + + def test_calls_discover(self): + self.safely_replace(ut1.TestLoader, "discover", delete=True) + mock_ut2 = self.prepare_mock_ut2() + record = [] + mock_ut2.TestLoader.discover = lambda self, path: record.append(path) + dist = Distribution() + cmd = test(dist) + cmd.run() + self.assertEqual([os.curdir], record) + + +def test_suite(): + return unittest.makeSuite(TestTest) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_upload.py b/Lib/packaging/tests/test_command_upload.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_upload.py @@ -0,0 +1,157 @@ +"""Tests for packaging.command.upload.""" +import os +import sys + +from packaging.command.upload import upload +from packaging.dist import Distribution +from packaging.errors import PackagingOptionError + +from packaging.tests import unittest, support +from packaging.tests.pypi_server import PyPIServer, PyPIServerTestCase + + +PYPIRC_NOPASSWORD = """\ +[distutils] + +index-servers = + server1 + +[server1] +username:me +""" + +PYPIRC = """\ +[distutils] + +index-servers = + server1 + server2 + +[server1] +username:me +password:secret + +[server2] +username:meagain +password: secret +realm:acme +repository:http://another.pypi/ +""" + + +class UploadTestCase(support.TempdirManager, support.EnvironRestorer, + support.LoggingCatcher, PyPIServerTestCase): + + restore_environ = ['HOME'] + + def setUp(self): + super(UploadTestCase, self).setUp() + self.tmp_dir = self.mkdtemp() + self.rc = os.path.join(self.tmp_dir, '.pypirc') + os.environ['HOME'] = self.tmp_dir + + def test_finalize_options(self): + # new format + self.write_file(self.rc, PYPIRC) + dist = Distribution() + cmd = upload(dist) + cmd.finalize_options() + for attr, expected in (('username', 'me'), ('password', 'secret'), + ('realm', 'pypi'), + ('repository', 'http://pypi.python.org/pypi')): + self.assertEqual(getattr(cmd, attr), expected) + + def test_finalize_options_unsigned_identity_raises_exception(self): + self.write_file(self.rc, PYPIRC) + dist = Distribution() + cmd = upload(dist) + cmd.identity = True + cmd.sign = False + self.assertRaises(PackagingOptionError, cmd.finalize_options) + + def test_saved_password(self): + # file with no password + self.write_file(self.rc, PYPIRC_NOPASSWORD) + + # make sure it passes + dist = Distribution() + cmd = upload(dist) + cmd.ensure_finalized() + self.assertEqual(cmd.password, None) + + # make sure we get it as well, if another command + # initialized it at the dist level + dist.password = 'xxx' + cmd = upload(dist) + cmd.finalize_options() + self.assertEqual(cmd.password, 'xxx') + + def test_upload_without_files_raises_exception(self): + dist = Distribution() + cmd = upload(dist) + self.assertRaises(PackagingOptionError, cmd.run) + + def test_upload(self): + path = os.path.join(self.tmp_dir, 'xxx') + self.write_file(path) + command, pyversion, filename = 'xxx', '3.3', path + dist_files = [(command, pyversion, filename)] + + # lets run it + pkg_dir, dist = self.create_dist(dist_files=dist_files, author='d?d?') + cmd = upload(dist) + cmd.ensure_finalized() + cmd.repository = self.pypi.full_address + cmd.run() + + # what did we send ? + handler, request_data = self.pypi.requests[-1] + headers = handler.headers + #self.assertIn('d?d?', str(request_data)) + self.assertIn(b'xxx', request_data) + + self.assertEqual(int(headers['content-length']), len(request_data)) + self.assertLess(int(headers['content-length']), 2500) + self.assertTrue(headers['content-type'].startswith('multipart/form-data')) + self.assertEqual(handler.command, 'POST') + self.assertNotIn('\n', headers['authorization']) + + def test_upload_docs(self): + path = os.path.join(self.tmp_dir, 'xxx') + self.write_file(path) + command, pyversion, filename = 'xxx', '3.3', path + dist_files = [(command, pyversion, filename)] + docs_path = os.path.join(self.tmp_dir, "build", "docs") + os.makedirs(docs_path) + self.write_file(os.path.join(docs_path, "index.html"), "yellow") + self.write_file(self.rc, PYPIRC) + + # lets run it + pkg_dir, dist = self.create_dist(dist_files=dist_files, author='d?d?') + + cmd = upload(dist) + cmd.get_finalized_command("build").run() + cmd.upload_docs = True + cmd.ensure_finalized() + cmd.repository = self.pypi.full_address + try: + prev_dir = os.getcwd() + os.chdir(self.tmp_dir) + cmd.run() + finally: + os.chdir(prev_dir) + + handler, request_data = self.pypi.requests[-1] + action, name, content = request_data.split( + "----------------GHSKFJDLGDS7543FJKLFHRE75642756743254" + .encode())[1:4] + + self.assertIn(b'name=":action"', action) + self.assertIn(b'doc_upload', action) + + +def test_suite(): + return unittest.makeSuite(UploadTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_command_upload_docs.py b/Lib/packaging/tests/test_command_upload_docs.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_command_upload_docs.py @@ -0,0 +1,205 @@ +"""Tests for packaging.command.upload_docs.""" +import os +import sys +import shutil +import zipfile + +from packaging.command import upload_docs as upload_docs_mod +from packaging.command.upload_docs import (upload_docs, zip_dir, + encode_multipart) +from packaging.dist import Distribution +from packaging.errors import PackagingFileError, PackagingOptionError + +from packaging.tests import unittest, support +from packaging.tests.pypi_server import PyPIServerTestCase + + +EXPECTED_MULTIPART_OUTPUT = [ + b'---x', + b'Content-Disposition: form-data; name="username"', + b'', + b'wok', + b'---x', + b'Content-Disposition: form-data; name="password"', + b'', + b'secret', + b'---x', + b'Content-Disposition: form-data; name="picture"; filename="wok.png"', + b'', + b'PNG89', + b'---x--', + b'', +] + +PYPIRC = """\ +[distutils] +index-servers = server1 + +[server1] +repository = %s +username = real_slim_shady +password = long_island +""" + +class UploadDocsTestCase(support.TempdirManager, + support.EnvironRestorer, + support.LoggingCatcher, + PyPIServerTestCase): + + restore_environ = ['HOME'] + + def setUp(self): + super(UploadDocsTestCase, self).setUp() + self.tmp_dir = self.mkdtemp() + self.rc = os.path.join(self.tmp_dir, '.pypirc') + os.environ['HOME'] = self.tmp_dir + self.dist = Distribution() + self.dist.metadata['Name'] = "distr-name" + self.cmd = upload_docs(self.dist) + + def test_default_uploaddir(self): + sandbox = self.mkdtemp() + previous = os.getcwd() + os.chdir(sandbox) + try: + os.mkdir("build") + self.prepare_sample_dir("build") + self.cmd.ensure_finalized() + self.assertEqual(self.cmd.upload_dir, os.path.join("build", "docs")) + finally: + os.chdir(previous) + + def test_default_uploaddir_looks_for_doc_also(self): + sandbox = self.mkdtemp() + previous = os.getcwd() + os.chdir(sandbox) + try: + os.mkdir("build") + self.prepare_sample_dir("build") + os.rename(os.path.join("build", "docs"), os.path.join("build", "doc")) + self.cmd.ensure_finalized() + self.assertEqual(self.cmd.upload_dir, os.path.join("build", "doc")) + finally: + os.chdir(previous) + + def prepare_sample_dir(self, sample_dir=None): + if sample_dir is None: + sample_dir = self.mkdtemp() + os.mkdir(os.path.join(sample_dir, "docs")) + self.write_file(os.path.join(sample_dir, "docs", "index.html"), "Ce mortel ennui") + self.write_file(os.path.join(sample_dir, "index.html"), "Oh la la") + return sample_dir + + def test_zip_dir(self): + source_dir = self.prepare_sample_dir() + compressed = zip_dir(source_dir) + + zip_f = zipfile.ZipFile(compressed) + self.assertEqual(zip_f.namelist(), ['index.html', 'docs/index.html']) + + def test_encode_multipart(self): + fields = [('username', 'wok'), ('password', 'secret')] + files = [('picture', 'wok.png', b'PNG89')] + content_type, body = encode_multipart(fields, files, b'-x') + self.assertEqual(b'multipart/form-data; boundary=-x', content_type) + self.assertEqual(EXPECTED_MULTIPART_OUTPUT, body.split(b'\r\n')) + + def prepare_command(self): + self.cmd.upload_dir = self.prepare_sample_dir() + self.cmd.ensure_finalized() + self.cmd.repository = self.pypi.full_address + self.cmd.username = "username" + self.cmd.password = "password" + + def test_upload(self): + self.prepare_command() + self.cmd.run() + + self.assertEqual(len(self.pypi.requests), 1) + handler, request_data = self.pypi.requests[-1] + self.assertIn(b"content", request_data) + self.assertIn("Basic", handler.headers['authorization']) + self.assertTrue(handler.headers['content-type'] + .startswith('multipart/form-data;')) + + action, name, version, content =\ + request_data.split("----------------GHSKFJDLGDS7543FJKLFHRE75642756743254".encode())[1:5] + + + # check that we picked the right chunks + self.assertIn(b'name=":action"', action) + self.assertIn(b'name="name"', name) + self.assertIn(b'name="version"', version) + self.assertIn(b'name="content"', content) + + # check their contents + self.assertIn(b'doc_upload', action) + self.assertIn(b'distr-name', name) + self.assertIn(b'docs/index.html', content) + self.assertIn(b'Ce mortel ennui', content) + + def test_https_connection(self): + https_called = False + + orig_https = upload_docs_mod.http.client.HTTPConnection + + def https_conn_wrapper(*args): + nonlocal https_called + https_called = True + # the testing server is http + return upload_docs_mod.http.client.HTTPConnection(*args) + + upload_docs_mod.http.client.HTTPSConnection = https_conn_wrapper + try: + self.prepare_command() + self.cmd.run() + self.assertFalse(https_called) + + self.cmd.repository = self.cmd.repository.replace("http", "https") + self.cmd.run() + self.assertTrue(https_called) + finally: + upload_docs_mod.http.client.HTTPConnection = orig_https + + def test_handling_response(self): + self.pypi.default_response_status = '403 Forbidden' + self.prepare_command() + self.cmd.run() + self.assertIn('Upload failed (403): Forbidden', self.get_logs()[-1]) + + self.pypi.default_response_status = '301 Moved Permanently' + self.pypi.default_response_headers.append(("Location", "brand_new_location")) + self.cmd.run() + self.assertIn('brand_new_location', self.get_logs()[-1]) + + def test_reads_pypirc_data(self): + self.write_file(self.rc, PYPIRC % self.pypi.full_address) + self.cmd.repository = self.pypi.full_address + self.cmd.upload_dir = self.prepare_sample_dir() + self.cmd.ensure_finalized() + self.assertEqual(self.cmd.username, "real_slim_shady") + self.assertEqual(self.cmd.password, "long_island") + + def test_checks_index_html_presence(self): + self.cmd.upload_dir = self.prepare_sample_dir() + os.remove(os.path.join(self.cmd.upload_dir, "index.html")) + self.assertRaises(PackagingFileError, self.cmd.ensure_finalized) + + def test_checks_upload_dir(self): + self.cmd.upload_dir = self.prepare_sample_dir() + shutil.rmtree(os.path.join(self.cmd.upload_dir)) + self.assertRaises(PackagingOptionError, self.cmd.ensure_finalized) + + def test_show_response(self): + self.prepare_command() + self.cmd.show_response = True + self.cmd.run() + record = self.get_logs()[-1] + self.assertTrue(record, "should report the response") + self.assertIn(self.pypi.default_response_data, record) + +def test_suite(): + return unittest.makeSuite(UploadDocsTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_compiler.py b/Lib/packaging/tests/test_compiler.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_compiler.py @@ -0,0 +1,66 @@ +"""Tests for distutils.compiler.""" +import os + +from packaging.compiler import (get_default_compiler, customize_compiler, + gen_lib_options) +from packaging.tests import unittest, support + + +class FakeCompiler: + + name = 'fake' + description = 'Fake' + + def library_dir_option(self, dir): + return "-L" + dir + + def runtime_library_dir_option(self, dir): + return ["-cool", "-R" + dir] + + def find_library_file(self, dirs, lib, debug=False): + return 'found' + + def library_option(self, lib): + return "-l" + lib + + +class CompilerTestCase(support.EnvironRestorer, unittest.TestCase): + + restore_environ = ['AR', 'ARFLAGS'] + + @unittest.skipUnless(get_default_compiler() == 'unix', + 'irrelevant if default compiler is not unix') + def test_customize_compiler(self): + + os.environ['AR'] = 'my_ar' + os.environ['ARFLAGS'] = '-arflags' + + # make sure AR gets caught + class compiler: + name = 'unix' + + def set_executables(self, **kw): + self.exes = kw + + comp = compiler() + customize_compiler(comp) + self.assertEqual(comp.exes['archiver'], 'my_ar -arflags') + + def test_gen_lib_options(self): + compiler = FakeCompiler() + libdirs = ['lib1', 'lib2'] + runlibdirs = ['runlib1'] + libs = [os.path.join('dir', 'name'), 'name2'] + + opts = gen_lib_options(compiler, libdirs, runlibdirs, libs) + wanted = ['-Llib1', '-Llib2', '-cool', '-Rrunlib1', 'found', + '-lname2'] + self.assertEqual(opts, wanted) + + +def test_suite(): + return unittest.makeSuite(CompilerTestCase) + + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/packaging/tests/test_config.py b/Lib/packaging/tests/test_config.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_config.py @@ -0,0 +1,424 @@ +"""Tests for packaging.config.""" +import os +import sys +import logging +from io import StringIO + +from packaging import command +from packaging.dist import Distribution +from packaging.errors import PackagingFileError +from packaging.compiler import new_compiler, _COMPILERS +from packaging.command.sdist import sdist + +from packaging.tests import unittest, support + + +SETUP_CFG = """ +[metadata] +name = RestingParrot +version = 0.6.4 +author = Carl Meyer +author_email = carl at oddbird.net +maintainer = ?ric Araujo +maintainer_email = merwok at netwok.org +summary = A sample project demonstrating packaging +description-file = %(description-file)s +keywords = packaging, sample project + +classifier = + Development Status :: 4 - Beta + Environment :: Console (Text Based) + Environment :: X11 Applications :: GTK; python_version < '3' + License :: OSI Approved :: MIT License + Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 3 + +requires_python = >=2.4, <3.2 + +requires_dist = + PetShoppe + MichaelPalin (> 1.1) + pywin32; sys.platform == 'win32' + pysqlite2; python_version < '2.5' + inotify (0.0.1); sys.platform == 'linux2' + +requires_external = libxml2 + +provides_dist = packaging-sample-project (0.2) + unittest2-sample-project + +project_url = + Main repository, http://bitbucket.org/carljm/sample-distutils2-project + Fork in progress, http://bitbucket.org/Merwok/sample-distutils2-project + +[files] +packages_root = src + +packages = one + two + three + +modules = haven + +scripts = + script1.py + scripts/find-coconuts + bin/taunt + +package_data = + cheese = data/templates/* + +extra_files = %(extra-files)s + +# Replaces MANIFEST.in +sdist_extra = + include THANKS HACKING + recursive-include examples *.txt *.py + prune examples/sample?/build + +resources= + bm/ {b1,b2}.gif = {icon} + Cf*/ *.CFG = {config}/baBar/ + init_script = {script}/JunGle/ + +[global] +commands = + packaging.tests.test_config.FooBarBazTest + +compilers = + packaging.tests.test_config.DCompiler + +setup_hook = %(setup-hook)s + + + +[install_dist] +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 +libraries = gecodeint gecodekernel -- sys.platform != 'win32' + GecodeInt GecodeKernel -- sys.platform == 'win32' + +[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 + -DGECODE_VERSION=$(./gecode_version) -- sys.platform != 'win32' + /DGECODE_VERSION='win32' -- sys.platform == 'win32' +language = cxx + +""" + + +class DCompiler: + name = 'd' + description = 'D Compiler' + + def __init__(self, *args): + pass + + +def hook(content): + content['metadata']['version'] += '.dev1' + + +class FooBarBazTest: + + def __init__(self, dist): + self.distribution = dist + + @classmethod + def get_command_name(cls): + return 'foo' + + def run(self): + self.distribution.foo_was_here = True + + def nothing(self): + pass + + def get_source_files(self): + return [] + + ensure_finalized = finalize_options = initialize_options = nothing + + +class ConfigTestCase(support.TempdirManager, + support.EnvironRestorer, + support.LoggingCatcher, + unittest.TestCase): + + restore_environ = ['PLAT'] + + def setUp(self): + super(ConfigTestCase, self).setUp() + self.addCleanup(setattr, sys, 'stdout', sys.stdout) + self.addCleanup(setattr, sys, 'stderr', sys.stderr) + sys.stdout = StringIO() + sys.stderr = StringIO() + + self.addCleanup(os.chdir, os.getcwd()) + tempdir = self.mkdtemp() + os.chdir(tempdir) + self.tempdir = tempdir + + def write_setup(self, kwargs=None): + opts = {'description-file': 'README', 'extra-files': '', + 'setup-hook': 'packaging.tests.test_config.hook'} + if kwargs: + opts.update(kwargs) + self.write_file('setup.cfg', SETUP_CFG % opts) + + def get_dist(self): + dist = Distribution() + dist.parse_config_files() + return dist + + def test_config(self): + self.write_setup() + self.write_file('README', 'yeah') + os.mkdir('bm') + self.write_file(('bm', 'b1.gif'), '') + self.write_file(('bm', 'b2.gif'), '') + os.mkdir('Cfg') + self.write_file(('Cfg', 'data.CFG'), '') + self.write_file('init_script', '') + + # try to load the metadata now + dist = self.get_dist() + + # check what was done + self.assertEqual(dist.metadata['Author'], 'Carl Meyer') + self.assertEqual(dist.metadata['Author-Email'], 'carl at oddbird.net') + + # the hook adds .dev1 + self.assertEqual(dist.metadata['Version'], '0.6.4.dev1') + + wanted = [ + 'Development Status :: 4 - Beta', + 'Environment :: Console (Text Based)', + "Environment :: X11 Applications :: GTK; python_version < '3'", + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3'] + self.assertEqual(dist.metadata['Classifier'], wanted) + + wanted = ['packaging', 'sample project'] + self.assertEqual(dist.metadata['Keywords'], wanted) + + self.assertEqual(dist.metadata['Requires-Python'], '>=2.4, <3.2') + + wanted = ['PetShoppe', + 'MichaelPalin (> 1.1)', + "pywin32; sys.platform == 'win32'", + "pysqlite2; python_version < '2.5'", + "inotify (0.0.1); sys.platform == 'linux2'"] + + self.assertEqual(dist.metadata['Requires-Dist'], wanted) + urls = [('Main repository', + 'http://bitbucket.org/carljm/sample-distutils2-project'), + ('Fork in progress', + '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/*'}) + self.assertEqual( + {'bm/b1.gif': '{icon}/b1.gif', + 'bm/b2.gif': '{icon}/b2.gif', + 'Cfg/data.CFG': '{config}/baBar/data.CFG', + 'init_script': '{script}/JunGle/init_script'}, + dist.data_files) + + 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 + # this test is run directly: foo is packaging.tests.test_config.Foo + # because get_command_class uses the full name, but a bare "Foo" in + # this file would be __main__.Foo when run as "python test_config.py". + # The name FooBarBazTest should be unique enough to prevent + # collisions. + self.assertEqual('FooBarBazTest', + dist.get_command_obj('foo').__class__.__name__) + + # did the README got loaded ? + self.assertEqual(dist.metadata['description'], 'yeah') + + # do we have the D Compiler enabled ? + self.assertIn('d', _COMPILERS) + d = new_compiler(compiler='d') + self.assertEqual(d.description, 'D Compiler') + + def test_multiple_description_file(self): + self.write_setup({'description-file': 'README CHANGES'}) + self.write_file('README', 'yeah') + self.write_file('CHANGES', 'changelog2') + dist = self.get_dist() + self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES']) + + def test_multiline_description_file(self): + self.write_setup({'description-file': 'README\n CHANGES'}) + self.write_file('README', 'yeah') + self.write_file('CHANGES', 'changelog') + dist = self.get_dist() + 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.get_dist() + + 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']) + libs = ['gecodeint', 'gecodekernel'] + if sys.platform == 'win32': + libs = ['GecodeInt', 'GecodeKernel'] + self.assertEqual(ext.libraries, libs) + 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']) + cargs = ['-fPIC', '-O2'] + if sys.platform == 'win32': + cargs.append("/DGECODE_VERSION='win32'") + else: + cargs.append('-DGECODE_VERSION=$(./gecode_version)') + self.assertEqual(ext.extra_compile_args, cargs) + self.assertEqual(ext.language, 'cxx') + + def test_missing_setuphook_warns(self): + self.write_setup({'setup-hook': 'this.does._not.exist'}) + self.write_file('README', 'yeah') + dist = self.get_dist() + logs = self.get_logs(logging.WARNING) + self.assertEqual(1, len(logs)) + self.assertIn('could not import setup_hook', logs[0]) + + def test_metadata_requires_description_files_missing(self): + self.write_setup({'description-file': 'README\n README2'}) + self.write_file('README', 'yeah') + self.write_file('README2', 'yeah') + os.mkdir('src') + self.write_file(('src', 'haven.py'), '#') + self.write_file('script1.py', '#') + os.mkdir('scripts') + self.write_file(('scripts', 'find-coconuts'), '#') + os.mkdir('bin') + self.write_file(('bin', 'taunt'), '#') + + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) + os.mkdir(pkg) + self.write_file((pkg, '__init__.py'), '#') + + dist = self.get_dist() + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() + self.assertRaises(PackagingFileError, cmd.make_distribution) + + def test_metadata_requires_description_files(self): + # Create the following file structure: + # README + # README2 + # script1.py + # scripts/ + # find-coconuts + # bin/ + # taunt + # src/ + # haven.py + # one/__init__.py + # two/__init__.py + # three/__init__.py + + self.write_setup({'description-file': 'README\n README2', + 'extra-files': '\n README3'}) + self.write_file('README', 'yeah 1') + self.write_file('README2', 'yeah 2') + self.write_file('README3', 'yeah 3') + os.mkdir('src') + self.write_file(('src', 'haven.py'), '#') + self.write_file('script1.py', '#') + os.mkdir('scripts') + self.write_file(('scripts', 'find-coconuts'), '#') + os.mkdir('bin') + self.write_file(('bin', 'taunt'), '#') + + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) + os.mkdir(pkg) + self.write_file((pkg, '__init__.py'), '#') + + dist = self.get_dist() + self.assertIn('yeah 1\nyeah 2', dist.metadata['description']) + + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() + self.assertRaises(PackagingFileError, cmd.make_distribution) + + self.write_setup({'description-file': 'README\n README2', + 'extra-files': '\n README2\n README'}) + dist = self.get_dist() + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() + cmd.make_distribution() + with open('MANIFEST') as fp: + self.assertIn('README\nREADME2\n', fp.read()) + + def test_sub_commands(self): + self.write_setup() + self.write_file('README', 'yeah') + os.mkdir('src') + self.write_file(('src', 'haven.py'), '#') + self.write_file('script1.py', '#') + os.mkdir('scripts') + self.write_file(('scripts', 'find-coconuts'), '#') + os.mkdir('bin') + self.write_file(('bin', 'taunt'), '#') + + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) + os.mkdir(pkg) + self.write_file((pkg, '__init__.py'), '#') + + # try to run the install command to see if foo is called + dist = self.get_dist() + self.assertIn('foo', command.get_command_names()) + self.assertEqual('FooBarBazTest', + dist.get_command_obj('foo').__class__.__name__) + + +def test_suite(): + return unittest.makeSuite(ConfigTestCase) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_create.py b/Lib/packaging/tests/test_create.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_create.py @@ -0,0 +1,235 @@ +"""Tests for packaging.create.""" +import io +import os +import sys +import sysconfig +from textwrap import dedent +from packaging.create import MainProgram, ask_yn, ask, main + +from packaging.tests import support, unittest + + +class CreateTestCase(support.TempdirManager, + support.EnvironRestorer, + unittest.TestCase): + + restore_environ = ['PLAT'] + + def setUp(self): + super(CreateTestCase, self).setUp() + self._stdin = sys.stdin # TODO use Inputs + self._stdout = sys.stdout + sys.stdin = io.StringIO() + sys.stdout = io.StringIO() + self._cwd = os.getcwd() + self.wdir = self.mkdtemp() + os.chdir(self.wdir) + # patch sysconfig + self._old_get_paths = sysconfig.get_paths + sysconfig.get_paths = lambda *args, **kwargs: { + 'man': sys.prefix + '/share/man', + 'doc': sys.prefix + '/share/doc/pyxfoil', } + + def tearDown(self): + super(CreateTestCase, self).tearDown() + sys.stdin = self._stdin + sys.stdout = self._stdout + os.chdir(self._cwd) + sysconfig.get_paths = self._old_get_paths + + def test_ask_yn(self): + sys.stdin.write('y\n') + sys.stdin.seek(0) + self.assertEqual('y', ask_yn('is this a test')) + + def test_ask(self): + sys.stdin.write('a\n') + sys.stdin.write('b\n') + sys.stdin.seek(0) + self.assertEqual('a', ask('is this a test')) + self.assertEqual('b', ask(str(list(range(0, 70))), default='c', + lengthy=True)) + + def test_set_multi(self): + mainprogram = MainProgram() + sys.stdin.write('aaaaa\n') + sys.stdin.seek(0) + mainprogram.data['author'] = [] + mainprogram._set_multi('_set_multi test', 'author') + self.assertEqual(['aaaaa'], mainprogram.data['author']) + + def test_find_files(self): + # making sure we scan a project dir correctly + mainprogram = MainProgram() + + # building the structure + tempdir = self.wdir + dirs = ['pkg1', 'data', 'pkg2', 'pkg2/sub'] + files = ['README', 'setup.cfg', 'foo.py', + 'pkg1/__init__.py', 'pkg1/bar.py', + 'data/data1', 'pkg2/__init__.py', + 'pkg2/sub/__init__.py'] + + for dir_ in dirs: + os.mkdir(os.path.join(tempdir, dir_)) + + for file_ in files: + path = os.path.join(tempdir, file_) + self.write_file(path, 'xxx') + + mainprogram._find_files() + mainprogram.data['packages'].sort() + + # do we have what we want? + self.assertEqual(mainprogram.data['packages'], + ['pkg1', 'pkg2', 'pkg2.sub']) + self.assertEqual(mainprogram.data['modules'], ['foo']) + data_fn = os.path.join('data', 'data1') + self.assertEqual(set(mainprogram.data['extra_files']), + set(['setup.cfg', 'README', data_fn])) + + def test_convert_setup_py_to_cfg(self): + self.write_file((self.wdir, 'setup.py'), + dedent(""" + # -*- coding: utf-8 -*- + from distutils.core import setup + + long_description = '''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=long_description, + 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() + + with open(os.path.join(self.wdir, 'setup.cfg')) as fp: + lines = set(line.rstrip() for line in fp) + + # FIXME don't use sets + 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 + fp = open('README.txt') + try: + long_description = fp.read() + finally: + fp.close() + + setup(name='pyxfoil', + version='0.2', + description='Python bindings for the Xfoil engine', + long_description=long_description, + 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', 'babar.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 in the public domain, +ho, baby! + ''')) + sys.stdin.write('y\n') + sys.stdin.seek(0) + # FIXME Out of memory error. + main() + with open(os.path.join(self.wdir, 'setup.cfg')) as fp: + lines = set(line.rstrip() for line in fp) + + 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', + ' pyxfoil/babar.so', + 'resources =', + ' README.rst = {doc}', + ' pyxfoil.1 = {man}', + ])) + + +def test_suite(): + return unittest.makeSuite(CreateTestCase) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_cygwinccompiler.py b/Lib/packaging/tests/test_cygwinccompiler.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_cygwinccompiler.py @@ -0,0 +1,88 @@ +"""Tests for packaging.cygwinccompiler.""" +import os +import sys +import sysconfig +from packaging.compiler.cygwinccompiler import ( + check_config_h, get_msvcr, + CONFIG_H_OK, CONFIG_H_NOTOK, CONFIG_H_UNCERTAIN) + +from packaging.tests import unittest, support + + +class CygwinCCompilerTestCase(support.TempdirManager, + unittest.TestCase): + + def setUp(self): + super(CygwinCCompilerTestCase, self).setUp() + self.version = sys.version + self.python_h = os.path.join(self.mkdtemp(), 'python.h') + self.old_get_config_h_filename = sysconfig.get_config_h_filename + sysconfig.get_config_h_filename = self._get_config_h_filename + + def tearDown(self): + sys.version = self.version + sysconfig.get_config_h_filename = self.old_get_config_h_filename + super(CygwinCCompilerTestCase, self).tearDown() + + def _get_config_h_filename(self): + return self.python_h + + def test_check_config_h(self): + # check_config_h looks for "GCC" in sys.version first + # returns CONFIG_H_OK if found + sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) \n[GCC ' + '4.0.1 (Apple Computer, Inc. build 5370)]') + + self.assertEqual(check_config_h()[0], CONFIG_H_OK) + + # then it tries to see if it can find "__GNUC__" in pyconfig.h + sys.version = 'something without the *CC word' + + # if the file doesn't exist it returns CONFIG_H_UNCERTAIN + self.assertEqual(check_config_h()[0], CONFIG_H_UNCERTAIN) + + # if it exists but does not contain __GNUC__, it returns CONFIG_H_NOTOK + self.write_file(self.python_h, 'xxx') + self.assertEqual(check_config_h()[0], CONFIG_H_NOTOK) + + # and CONFIG_H_OK if __GNUC__ is found + self.write_file(self.python_h, 'xxx __GNUC__ xxx') + self.assertEqual(check_config_h()[0], CONFIG_H_OK) + + def test_get_msvcr(self): + # none + sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) ' + '\n[GCC 4.0.1 (Apple Computer, Inc. build 5370)]') + self.assertEqual(get_msvcr(), None) + + # MSVC 7.0 + sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' + '[MSC v.1300 32 bits (Intel)]') + self.assertEqual(get_msvcr(), ['msvcr70']) + + # MSVC 7.1 + sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' + '[MSC v.1310 32 bits (Intel)]') + self.assertEqual(get_msvcr(), ['msvcr71']) + + # VS2005 / MSVC 8.0 + sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' + '[MSC v.1400 32 bits (Intel)]') + self.assertEqual(get_msvcr(), ['msvcr80']) + + # VS2008 / MSVC 9.0 + sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' + '[MSC v.1500 32 bits (Intel)]') + self.assertEqual(get_msvcr(), ['msvcr90']) + + # unknown + sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' + '[MSC v.1999 32 bits (Intel)]') + self.assertRaises(ValueError, get_msvcr) + + +def test_suite(): + return unittest.makeSuite(CygwinCCompilerTestCase) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_database.py b/Lib/packaging/tests/test_database.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_database.py @@ -0,0 +1,506 @@ +import os +import io +import csv +import imp +import sys +import shutil +import zipfile +import tempfile +from os.path import relpath # separate import for backport concerns +from hashlib import md5 + +from packaging.errors import PackagingError +from packaging.metadata import Metadata +from packaging.tests import unittest, run_unittest, support, TESTFN + +from packaging.database import ( + Distribution, EggInfoDistribution, get_distribution, get_distributions, + provides_distribution, obsoletes_distribution, get_file_users, + enable_cache, disable_cache, distinfo_dirname, _yield_distributions) + +# TODO Add a test for getting a distribution provided by another distribution +# TODO Add a test for absolute pathed RECORD items (e.g. /etc/myapp/config.ini) +# TODO Add tests from the former pep376 project (zipped site-packages, etc.) + + +def get_hexdigest(filename): + with open(filename, 'rb') as file: + checksum = md5(file.read()) + return checksum.hexdigest() + + +def record_pieces(file): + path = relpath(file, sys.prefix) + digest = get_hexdigest(file) + size = os.path.getsize(file) + return [path, digest, size] + + +class CommonDistributionTests: + """Mixin used to test the interface common to both Distribution classes. + + Derived classes define cls, sample_dist, dirs and records. These + attributes are used in test methods. See source code for details. + """ + + def setUp(self): + super(CommonDistributionTests, self).setUp() + self.addCleanup(enable_cache) + disable_cache() + self.fake_dists_path = os.path.abspath( + os.path.join(os.path.dirname(__file__), 'fake_dists')) + + def test_instantiation(self): + # check that useful attributes are here + name, version, distdir = self.sample_dist + here = os.path.abspath(os.path.dirname(__file__)) + dist_path = os.path.join(here, 'fake_dists', distdir) + + dist = self.dist = self.cls(dist_path) + self.assertEqual(dist.path, dist_path) + self.assertEqual(dist.name, name) + self.assertEqual(dist.metadata['Name'], name) + self.assertIsInstance(dist.metadata, Metadata) + self.assertEqual(dist.version, version) + self.assertEqual(dist.metadata['Version'], version) + + def test_repr(self): + dist = self.cls(self.dirs[0]) + # just check that the class name is in the repr + self.assertIn(self.cls.__name__, repr(dist)) + + def test_comparison(self): + # tests for __eq__ and __hash__ + dist = self.cls(self.dirs[0]) + dist2 = self.cls(self.dirs[0]) + dist3 = self.cls(self.dirs[1]) + self.assertIn(dist, {dist: True}) + self.assertEqual(dist, dist) + + self.assertIsNot(dist, dist2) + self.assertEqual(dist, dist2) + self.assertNotEqual(dist, dist3) + self.assertNotEqual(dist, ()) + + def test_list_installed_files(self): + for dir_ in self.dirs: + dist = self.cls(dir_) + for path, md5_, size in dist.list_installed_files(): + record_data = self.records[dist.path] + self.assertIn(path, record_data) + self.assertEqual(md5_, record_data[path][0]) + self.assertEqual(size, record_data[path][1]) + + +class TestDistribution(CommonDistributionTests, unittest.TestCase): + + cls = Distribution + sample_dist = 'choxie', '2.0.0.9', 'choxie-2.0.0.9.dist-info' + + def setUp(self): + super(TestDistribution, self).setUp() + self.dirs = [os.path.join(self.fake_dists_path, f) + for f in os.listdir(self.fake_dists_path) + if f.endswith('.dist-info')] + + self.records = {} + for distinfo_dir in self.dirs: + record_file = os.path.join(distinfo_dir, 'RECORD') + with open(record_file, 'w') as file: + record_writer = csv.writer( + file, delimiter=',', quoting=csv.QUOTE_NONE) + + dist_location = distinfo_dir.replace('.dist-info', '') + + for path, dirs, files in os.walk(dist_location): + for f in files: + record_writer.writerow(record_pieces( + os.path.join(path, f))) + for file in ('INSTALLER', 'METADATA', 'REQUESTED'): + record_writer.writerow(record_pieces( + os.path.join(distinfo_dir, file))) + record_writer.writerow([relpath(record_file, sys.prefix)]) + + with open(record_file) as file: + record_reader = csv.reader(file) + record_data = {} + for row in record_reader: + path, md5_, size = (row[:] + + [None for i in range(len(row), 3)]) + record_data[path] = md5_, size + self.records[distinfo_dir] = record_data + + def tearDown(self): + for distinfo_dir in self.dirs: + record_file = os.path.join(distinfo_dir, 'RECORD') + open(record_file, 'w').close() + super(TestDistribution, self).tearDown() + + def test_instantiation(self): + super(TestDistribution, self).test_instantiation() + self.assertIsInstance(self.dist.requested, bool) + + def test_uses(self): + # Test to determine if a distribution uses a specified file. + # Criteria to test against + distinfo_name = 'grammar-1.0a4' + distinfo_dir = os.path.join(self.fake_dists_path, + distinfo_name + '.dist-info') + true_path = [self.fake_dists_path, distinfo_name, + 'grammar', 'utils.py'] + true_path = relpath(os.path.join(*true_path), sys.prefix) + false_path = [self.fake_dists_path, 'towel_stuff-0.1', 'towel_stuff', + '__init__.py'] + false_path = relpath(os.path.join(*false_path), sys.prefix) + + # Test if the distribution uses the file in question + 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. + distinfo_name = 'choxie-2.0.0.9' + other_distinfo_name = 'grammar-1.0a4' + distinfo_dir = os.path.join(self.fake_dists_path, + distinfo_name + '.dist-info') + dist = Distribution(distinfo_dir) + # Test for known good file matches + distinfo_files = [ + # Relative paths + 'INSTALLER', 'METADATA', + # Absolute paths + os.path.join(distinfo_dir, 'RECORD'), + os.path.join(distinfo_dir, 'REQUESTED'), + ] + + for distfile in distinfo_files: + with dist.get_distinfo_file(distfile) as value: + self.assertIsInstance(value, io.TextIOWrapper) + # Is it the correct file? + self.assertEqual(value.name, + os.path.join(distinfo_dir, distfile)) + + # 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') + self.assertRaises(PackagingError, dist.get_distinfo_file, + other_distinfo_file) + # Test for a file that should not exist + self.assertRaises(PackagingError, dist.get_distinfo_file, + 'MAGICFILE') + + def test_list_distinfo_files(self): + # Test for the iteration of RECORD path entries. + distinfo_name = 'towel_stuff-0.1' + distinfo_dir = os.path.join(self.fake_dists_path, + distinfo_name + '.dist-info') + dist = Distribution(distinfo_dir) + # Test for the iteration of the raw path + distinfo_record_paths = self.records[distinfo_dir].keys() + found = dist.list_distinfo_files() + self.assertEqual(sorted(found), sorted(distinfo_record_paths)) + # Test for the iteration of local absolute paths + distinfo_record_paths = [os.path.join(sys.prefix, path) + for path in self.records[distinfo_dir]] + found = dist.list_distinfo_files(local=True) + self.assertEqual(sorted(found), sorted(distinfo_record_paths)) + + def test_get_resources_path(self): + distinfo_name = 'babar-0.1' + distinfo_dir = os.path.join(self.fake_dists_path, + distinfo_name + '.dist-info') + dist = Distribution(distinfo_dir) + resource_path = dist.get_resource_path('babar.png') + self.assertEqual(resource_path, 'babar.png') + self.assertRaises(KeyError, dist.get_resource_path, 'notexist') + + +class TestEggInfoDistribution(CommonDistributionTests, + support.LoggingCatcher, + unittest.TestCase): + + cls = EggInfoDistribution + sample_dist = 'bacon', '0.1', 'bacon-0.1.egg-info' + + def setUp(self): + super(TestEggInfoDistribution, self).setUp() + + self.dirs = [os.path.join(self.fake_dists_path, f) + for f in os.listdir(self.fake_dists_path) + if f.endswith('.egg') or f.endswith('.egg-info')] + + self.records = {} + + @unittest.skip('not implemented yet') + def test_list_installed_files(self): + # EggInfoDistribution defines list_installed_files but there is no + # test for it yet; someone with setuptools expertise needs to add a + # file with the list of installed files for one of the egg fake dists + # and write the support code to populate self.records (and then delete + # this method) + pass + + +class TestDatabase(support.LoggingCatcher, + unittest.TestCase): + + def setUp(self): + super(TestDatabase, self).setUp() + disable_cache() + # Setup the path environment with our fake distributions + current_path = os.path.abspath(os.path.dirname(__file__)) + self.sys_path = sys.path[:] + self.fake_dists_path = os.path.join(current_path, 'fake_dists') + sys.path.insert(0, self.fake_dists_path) + + def tearDown(self): + sys.path[:] = self.sys_path + enable_cache() + super(TestDatabase, self).tearDown() + + def test_distinfo_dirname(self): + # 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) + # Test for a very simple single word name and decimal version + # number + ('docutils', '0.5', 'docutils-0.5.dist-info'), + # Test for another except this time with a '-' in the name, which + # needs to be transformed during the name lookup + ('python-ldap', '2.5', 'python_ldap-2.5.dist-info'), + # Test for both '-' in the name and a funky version number + ('python-ldap', '2.5 a---5', 'python_ldap-2.5 a---5.dist-info'), + ] + + # Loop through the items to validate the results + for name, version, standard_dirname in items: + dirname = distinfo_dirname(name, version) + self.assertEqual(dirname, standard_dirname) + + def test_get_distributions(self): + # Lookup all distributions found in the ``sys.path``. + # This test could potentially pick up other installed distributions + fake_dists = [('grammar', '1.0a4'), ('choxie', '2.0.0.9'), + ('towel-stuff', '0.1'), ('babar', '0.1')] + found_dists = [] + + # Verify the fake dists have been found. + dists = [dist for dist in get_distributions()] + for dist in dists: + self.assertIsInstance(dist, Distribution) + if (dist.name in dict(fake_dists) and + dist.path.startswith(self.fake_dists_path)): + found_dists.append((dist.name, dist.metadata['version'], )) + else: + # check that it doesn't find anything more than this + self.assertFalse(dist.path.startswith(self.fake_dists_path)) + # otherwise we don't care what other distributions are found + + # Finally, test that we found all that we were looking for + self.assertEqual(sorted(found_dists), sorted(fake_dists)) + + # 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 = [] + + dists = [dist for dist in get_distributions(use_egg_info=True)] + for dist in dists: + self.assertIsInstance(dist, (Distribution, EggInfoDistribution)) + if (dist.name in dict(fake_dists) and + dist.path.startswith(self.fake_dists_path)): + found_dists.append((dist.name, dist.metadata['version'])) + else: + self.assertFalse(dist.path.startswith(self.fake_dists_path)) + + self.assertEqual(sorted(fake_dists), sorted(found_dists)) + + 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 + + # Lookup the distribution + dist = get_distribution(name) + self.assertIsInstance(dist, Distribution) + self.assertEqual(dist.name, name) + + # Verify that an unknown distribution returns None + self.assertIsNone(get_distribution('bogus')) + + # Verify partial name matching doesn't work + self.assertIsNone(get_distribution('towel')) + + # Verify that it does not find egg-info distributions, when not + # instructed to + self.assertIsNone(get_distribution('bacon')) + self.assertIsNone(get_distribution('cheese')) + self.assertIsNone(get_distribution('strawberry')) + self.assertIsNone(get_distribution('banana')) + + # Now check that it works well in both situations, when egg-info + # is a file and directory respectively. + dist = get_distribution('cheese', use_egg_info=True) + self.assertIsInstance(dist, EggInfoDistribution) + self.assertEqual(dist.name, 'cheese') + + dist = get_distribution('bacon', use_egg_info=True) + self.assertIsInstance(dist, EggInfoDistribution) + self.assertEqual(dist.name, 'bacon') + + dist = get_distribution('banana', use_egg_info=True) + self.assertIsInstance(dist, EggInfoDistribution) + self.assertEqual(dist.name, 'banana') + + dist = get_distribution('strawberry', use_egg_info=True) + self.assertIsInstance(dist, EggInfoDistribution) + self.assertEqual(dist.name, 'strawberry') + + def test_get_file_users(self): + # Test the iteration of distributions that use a file. + name = 'towel_stuff-0.1' + path = os.path.join(self.fake_dists_path, name, + 'towel_stuff', '__init__.py') + for dist in get_file_users(path): + self.assertIsInstance(dist, Distribution) + self.assertEqual(dist.name, name) + + def test_provides(self): + # Test for looking up distributions by what they provide + checkLists = lambda x, y: self.assertEqual(sorted(x), sorted(y)) + + l = [dist.name for dist in provides_distribution('truffles')] + checkLists(l, ['choxie', 'towel-stuff']) + + l = [dist.name for dist in provides_distribution('truffles', '1.0')] + checkLists(l, ['choxie']) + + l = [dist.name for dist in provides_distribution('truffles', '1.0', + use_egg_info=True)] + checkLists(l, ['choxie', 'cheese']) + + l = [dist.name for dist in provides_distribution('truffles', '1.1.2')] + checkLists(l, ['towel-stuff']) + + l = [dist.name for dist in provides_distribution('truffles', '1.1')] + checkLists(l, ['towel-stuff']) + + l = [dist.name for dist in provides_distribution('truffles', + '!=1.1,<=2.0')] + checkLists(l, ['choxie']) + + l = [dist.name for dist in provides_distribution('truffles', + '!=1.1,<=2.0', + use_egg_info=True)] + checkLists(l, ['choxie', 'bacon', 'cheese']) + + l = [dist.name for dist in provides_distribution('truffles', '>1.0')] + checkLists(l, ['towel-stuff']) + + l = [dist.name for dist in provides_distribution('truffles', '>1.5')] + checkLists(l, []) + + l = [dist.name for dist in provides_distribution('truffles', '>1.5', + use_egg_info=True)] + 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, ['coconuts-aster']) + + l = [dist.name for dist in provides_distribution('strawberry', '>=0.5', + use_egg_info=True)] + checkLists(l, ['coconuts-aster']) + + 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, ['coconuts-aster']) + + l = [dist.name for dist in provides_distribution('banana', '>=0.3', + use_egg_info=True)] + checkLists(l, ['coconuts-aster']) + + 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 + checkLists = lambda x, y: self.assertEqual(sorted(x), sorted(y)) + + l = [dist.name for dist in obsoletes_distribution('truffles', '1.0')] + checkLists(l, []) + + l = [dist.name for dist in obsoletes_distribution('truffles', '1.0', + use_egg_info=True)] + checkLists(l, ['cheese', 'bacon']) + + l = [dist.name for dist in obsoletes_distribution('truffles', '0.8')] + checkLists(l, ['choxie']) + + l = [dist.name for dist in obsoletes_distribution('truffles', '0.8', + use_egg_info=True)] + checkLists(l, ['choxie', 'cheese']) + + l = [dist.name for dist in obsoletes_distribution('truffles', '0.9.6')] + checkLists(l, ['choxie', 'towel-stuff']) + + l = [dist.name for dist in obsoletes_distribution('truffles', + '0.5.2.3')] + checkLists(l, ['choxie', 'towel-stuff']) + + l = [dist.name for dist in obsoletes_distribution('truffles', '0.2')] + checkLists(l, ['towel-stuff']) + + def test_yield_distribution(self): + # tests the internal function _yield_distributions + checkLists = lambda x, y: self.assertEqual(sorted(x), sorted(y)) + + eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), + ('truffles', '5.0'), ('cheese', '2.0.2'), + ('coconuts-aster', '10.3'), ('nut', 'funkyversion')] + dists = [('choxie', '2.0.0.9'), ('grammar', '1.0a4'), + ('towel-stuff', '0.1'), ('babar', '0.1')] + + checkLists([], _yield_distributions(False, False)) + + found = [(dist.name, dist.metadata['Version']) + for dist in _yield_distributions(False, True) + if dist.path.startswith(self.fake_dists_path)] + checkLists(eggs, found) + + found = [(dist.name, dist.metadata['Version']) + for dist in _yield_distributions(True, False) + if dist.path.startswith(self.fake_dists_path)] + checkLists(dists, found) + + found = [(dist.name, dist.metadata['Version']) + for dist in _yield_distributions(True, True) + if dist.path.startswith(self.fake_dists_path)] + checkLists(dists + eggs, found) + + +def test_suite(): + suite = unittest.TestSuite() + load = unittest.defaultTestLoader.loadTestsFromTestCase + suite.addTest(load(TestDistribution)) + suite.addTest(load(TestEggInfoDistribution)) + suite.addTest(load(TestDatabase)) + return suite + + +if __name__ == "__main__": + unittest.main(defaultTest='test_suite') diff --git a/Lib/packaging/tests/test_depgraph.py b/Lib/packaging/tests/test_depgraph.py new file mode 100644 --- /dev/null +++ b/Lib/packaging/tests/test_depgraph.py @@ -0,0 +1,301 @@ +"""Tests for packaging.depgraph """ +import io +import os +import re +import sys +import packaging.database +from packaging import depgraph + +from packaging.tests import unittest, support + + +class DepGraphTestCase(support.LoggingCatcher, + unittest.TestCase): + + DISTROS_DIST = ('choxie', 'grammar', 'towel-stuff') + DISTROS_EGG = ('bacon', 'banana', 'strawberry', 'cheese') + BAD_EGGS = ('nut',) + + EDGE = re.compile( + r'"(?P.*)" -> "(?P.*)" \[label="(?P