From python-checkins at python.org Fri Jul 1 03:06:32 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 03:06:32 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogdGVzdF9vczogYWRk?= =?utf8?q?_TemporaryFileTests_to_the_testcase_list?= Message-ID: http://hg.python.org/cpython/rev/00a874ad4fc9 changeset: 71104:00a874ad4fc9 branch: 3.2 parent: 71101:7c60c1b41da9 user: Victor Stinner date: Fri Jul 01 02:56:15 2011 +0200 summary: test_os: add TemporaryFileTests to the testcase list The testcase was never executed, it's now fixed. files: Lib/test/test_os.py | 1 + 1 files changed, 1 insertions(+), 0 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 @@ -1344,6 +1344,7 @@ PidTests, LoginTests, LinkTests, + TemporaryFileTests, ) if __name__ == "__main__": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 03:06:33 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 03:06:33 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28merge_3=2E2=29_test=5Fos=3A_add_TemporaryFileTests_to_the?= =?utf8?q?_testcase_list?= Message-ID: http://hg.python.org/cpython/rev/588fe0fc7160 changeset: 71105:588fe0fc7160 parent: 71103:0c49260e85a0 parent: 71104:00a874ad4fc9 user: Victor Stinner date: Fri Jul 01 02:57:33 2011 +0200 summary: (merge 3.2) test_os: add TemporaryFileTests to the testcase list The testcase was never executed, it's now fixed. files: Lib/test/test_os.py | 1 + 1 files changed, 1 insertions(+), 0 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 @@ -1632,6 +1632,7 @@ LinkTests, TestSendfile, ProgramPriorityTests, + TemporaryFileTests, ) if __name__ == "__main__": -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 1 05:09:12 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 01 Jul 2011 05:09:12 +0200 Subject: [Python-checkins] Daily reference leaks (588fe0fc7160): sum=300 Message-ID: results for 588fe0fc7160 on branch "default" -------------------------------------------- test_packaging leaked [100, 100, 100] references, sum=300 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog8iQK0e', '-x'] From python-checkins at python.org Fri Jul 1 12:59:35 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 12:59:35 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_libpython=2Epy_?= =?utf8?q?=28gdb=29_now_catchs_IOError_in_py-list_and_py-bt_commands?= Message-ID: http://hg.python.org/cpython/rev/316764e64b0a changeset: 71106:316764e64b0a branch: 3.2 parent: 71104:00a874ad4fc9 user: Victor Stinner date: Fri Jul 01 12:57:44 2011 +0200 summary: libpython.py (gdb) now catchs IOError in py-list and py-bt commands py-list displays the error. py-bt ignores the error (the filename and line number is already displayed). files: Tools/gdb/libpython.py | 22 ++++++++++++++++++---- 1 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -905,7 +905,11 @@ if self.is_optimized_out(): return '(frame information optimized out)' filename = self.filename() - with open(os_fsencode(filename), 'r') as f: + try: + f = open(os_fsencode(filename), 'r') + except IOError: + return None + with f: all_lines = f.readlines() # Convert from 1-based current_line_num to 0-based list offset: return all_lines[self.current_line_num()-1] @@ -1430,7 +1434,9 @@ if pyop: line = pyop.get_truncated_repr(MAX_OUTPUT_LEN) write_unicode(sys.stdout, '#%i %s\n' % (self.get_index(), line)) - sys.stdout.write(pyop.current_line()) + line = pyop.current_line() + if line is not None: + sys.stdout.write(line) else: sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index()) else: @@ -1441,7 +1447,9 @@ pyop = self.get_pyop() if pyop: pyop.print_traceback() - sys.stdout.write(' %s\n' % pyop.current_line().strip()) + line = pyop.current_line() + if line is not None: + sys.stdout.write(' %s\n' % line.strip()) else: sys.stdout.write(' (unable to read python frame information)\n') else: @@ -1501,7 +1509,13 @@ if start<1: start = 1 - with open(os_fsencode(filename), 'r') as f: + try: + f = open(os_fsencode(filename), 'r') + except IOError as err: + sys.stdout.write('Unable to open %s: %s\n' + % (filename, err)) + return + with f: all_lines = f.readlines() # start and end are 1-based, all_lines is 0-based; # so [start-1:end] as a python slice gives us [start, end] as a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 12:59:36 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 12:59:36 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28merge_3=2E2=29_libpython=2Epy_=28gdb=29_now_catchs_IOErro?= =?utf8?q?r_in_py-list_and_py-bt_commands?= Message-ID: http://hg.python.org/cpython/rev/2aa2a7c25f2c changeset: 71107:2aa2a7c25f2c parent: 71105:588fe0fc7160 parent: 71106:316764e64b0a user: Victor Stinner date: Fri Jul 01 12:59:30 2011 +0200 summary: (merge 3.2) libpython.py (gdb) now catchs IOError in py-list and py-bt commands py-list displays the error. py-bt ignores the error (the filename and line number is already displayed). files: Tools/gdb/libpython.py | 22 ++++++++++++++++++---- 1 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -905,7 +905,11 @@ if self.is_optimized_out(): return '(frame information optimized out)' filename = self.filename() - with open(os_fsencode(filename), 'r') as f: + try: + f = open(os_fsencode(filename), 'r') + except IOError: + return None + with f: all_lines = f.readlines() # Convert from 1-based current_line_num to 0-based list offset: return all_lines[self.current_line_num()-1] @@ -1430,7 +1434,9 @@ if pyop: line = pyop.get_truncated_repr(MAX_OUTPUT_LEN) write_unicode(sys.stdout, '#%i %s\n' % (self.get_index(), line)) - sys.stdout.write(pyop.current_line()) + line = pyop.current_line() + if line is not None: + sys.stdout.write(line) else: sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index()) else: @@ -1441,7 +1447,9 @@ pyop = self.get_pyop() if pyop: pyop.print_traceback() - sys.stdout.write(' %s\n' % pyop.current_line().strip()) + line = pyop.current_line() + if line is not None: + sys.stdout.write(' %s\n' % line.strip()) else: sys.stdout.write(' (unable to read python frame information)\n') else: @@ -1501,7 +1509,13 @@ if start<1: start = 1 - with open(os_fsencode(filename), 'r') as f: + try: + f = open(os_fsencode(filename), 'r') + except IOError as err: + sys.stdout.write('Unable to open %s: %s\n' + % (filename, err)) + return + with f: all_lines = f.readlines() # start and end are 1-based, all_lines is 0-based; # so [start-1:end] as a python slice gives us [start, end] as a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 13:47:08 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 13:47:08 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogdGVzdF9vczogcmVt?= =?utf8?q?ove_now_useless_TemporaryFileTests_testcase?= Message-ID: http://hg.python.org/cpython/rev/aa3a4614a6f3 changeset: 71108:aa3a4614a6f3 branch: 3.2 parent: 71106:316764e64b0a user: Victor Stinner date: Fri Jul 01 13:45:30 2011 +0200 summary: test_os: remove now useless TemporaryFileTests testcase TemporaryFileTests has tests for os.tempnam() and os.tmpfile(), functions removed from Python 3. Move fdopen() tests to the FileTests testcase to test fdopen() on a file descriptor, not on a directory descriptor (which raises an error on Windows). files: Lib/test/test_os.py | 117 +------------------------------ 1 files changed, 6 insertions(+), 111 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 @@ -109,124 +109,20 @@ self.write_windows_console(sys.executable, "-c", code) self.write_windows_console(sys.executable, "-u", "-c", code) - -class TemporaryFileTests(unittest.TestCase): - def setUp(self): - self.files = [] - os.mkdir(support.TESTFN) - - def tearDown(self): - for name in self.files: - os.unlink(name) - os.rmdir(support.TESTFN) - - def check_tempfile(self, name): - # make sure it doesn't already exist: - self.assertFalse(os.path.exists(name), - "file already exists for temporary file") - # make sure we can create the file - open(name, "w") - self.files.append(name) - - def test_tempnam(self): - if not hasattr(os, "tempnam"): - return - warnings.filterwarnings("ignore", "tempnam", RuntimeWarning, - r"test_os$") - self.check_tempfile(os.tempnam()) - - name = os.tempnam(support.TESTFN) - self.check_tempfile(name) - - name = os.tempnam(support.TESTFN, "pfx") - self.assertTrue(os.path.basename(name)[:3] == "pfx") - self.check_tempfile(name) - - def test_tmpfile(self): - if not hasattr(os, "tmpfile"): - return - # As with test_tmpnam() below, the Windows implementation of tmpfile() - # attempts to create a file in the root directory of the current drive. - # On Vista and Server 2008, this test will always fail for normal users - # as writing to the root directory requires elevated privileges. With - # XP and below, the semantics of tmpfile() are the same, but the user - # running the test is more likely to have administrative privileges on - # their account already. If that's the case, then os.tmpfile() should - # work. In order to make this test as useful as possible, rather than - # trying to detect Windows versions or whether or not the user has the - # right permissions, just try and create a file in the root directory - # and see if it raises a 'Permission denied' OSError. If it does, then - # test that a subsequent call to os.tmpfile() raises the same error. If - # it doesn't, assume we're on XP or below and the user running the test - # has administrative privileges, and proceed with the test as normal. - if sys.platform == 'win32': - name = '\\python_test_os_test_tmpfile.txt' - if os.path.exists(name): - os.remove(name) - try: - fp = open(name, 'w') - except IOError as first: - # open() failed, assert tmpfile() fails in the same way. - # Although open() raises an IOError and os.tmpfile() raises an - # OSError(), 'args' will be (13, 'Permission denied') in both - # cases. - try: - fp = os.tmpfile() - except OSError as second: - self.assertEqual(first.args, second.args) - else: - self.fail("expected os.tmpfile() to raise OSError") - return - else: - # open() worked, therefore, tmpfile() should work. Close our - # dummy file and proceed with the test as normal. - fp.close() - os.remove(name) - - fp = os.tmpfile() - fp.write("foobar") - fp.seek(0,0) - s = fp.read() - fp.close() - self.assertTrue(s == "foobar") - - def test_tmpnam(self): - if not hasattr(os, "tmpnam"): - return - warnings.filterwarnings("ignore", "tmpnam", RuntimeWarning, - r"test_os$") - name = os.tmpnam() - if sys.platform in ("win32",): - # The Windows tmpnam() seems useless. From the MS docs: - # - # The character string that tmpnam creates consists of - # the path prefix, defined by the entry P_tmpdir in the - # file STDIO.H, followed by a sequence consisting of the - # digit characters '0' through '9'; the numerical value - # of this string is in the range 1 - 65,535. Changing the - # definitions of L_tmpnam or P_tmpdir in STDIO.H does not - # change the operation of tmpnam. - # - # The really bizarre part is that, at least under MSVC6, - # P_tmpdir is "\\". That is, the path returned refers to - # the root of the current drive. That's a terrible place to - # put temp files, and, depending on privileges, the user - # may not even be able to open a file in the root directory. - self.assertFalse(os.path.exists(name), - "file already exists for temporary file") - else: - self.check_tempfile(name) - def fdopen_helper(self, *args): fd = os.open(support.TESTFN, os.O_RDONLY) - fp2 = os.fdopen(fd, *args) - fp2.close() + f = os.fdopen(fd, *args) + f.close() def test_fdopen(self): + fd = os.open(support.TESTFN, os.O_CREAT|os.O_RDWR) + os.close(fd) + self.fdopen_helper() self.fdopen_helper('r') self.fdopen_helper('r', 100) + # Test attributes on return values from os.*stat* family. class StatAttributeTests(unittest.TestCase): def setUp(self): @@ -1344,7 +1240,6 @@ PidTests, LoginTests, LinkTests, - TemporaryFileTests, ) if __name__ == "__main__": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 13:47:09 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 13:47:09 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28merge_3=2E2=29_test=5Fos=3A_remove_now_useless_TemporaryF?= =?utf8?q?ileTests_testcase?= Message-ID: http://hg.python.org/cpython/rev/23dc2be031ef changeset: 71109:23dc2be031ef parent: 71107:2aa2a7c25f2c parent: 71108:aa3a4614a6f3 user: Victor Stinner date: Fri Jul 01 13:47:03 2011 +0200 summary: (merge 3.2) test_os: remove now useless TemporaryFileTests testcase TemporaryFileTests has tests for os.tempnam() and os.tmpfile(), functions removed from Python 3. Move fdopen() tests to the FileTests testcase to test fdopen() on a file descriptor, not on a directory descriptor (which raises an error on Windows). files: Lib/test/test_os.py | 117 +------------------------------ 1 files changed, 6 insertions(+), 111 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 @@ -114,124 +114,20 @@ self.write_windows_console(sys.executable, "-c", code) self.write_windows_console(sys.executable, "-u", "-c", code) - -class TemporaryFileTests(unittest.TestCase): - def setUp(self): - self.files = [] - os.mkdir(support.TESTFN) - - def tearDown(self): - for name in self.files: - os.unlink(name) - os.rmdir(support.TESTFN) - - def check_tempfile(self, name): - # make sure it doesn't already exist: - self.assertFalse(os.path.exists(name), - "file already exists for temporary file") - # make sure we can create the file - open(name, "w") - self.files.append(name) - - def test_tempnam(self): - if not hasattr(os, "tempnam"): - return - warnings.filterwarnings("ignore", "tempnam", RuntimeWarning, - r"test_os$") - self.check_tempfile(os.tempnam()) - - name = os.tempnam(support.TESTFN) - self.check_tempfile(name) - - name = os.tempnam(support.TESTFN, "pfx") - self.assertTrue(os.path.basename(name)[:3] == "pfx") - self.check_tempfile(name) - - def test_tmpfile(self): - if not hasattr(os, "tmpfile"): - return - # As with test_tmpnam() below, the Windows implementation of tmpfile() - # attempts to create a file in the root directory of the current drive. - # On Vista and Server 2008, this test will always fail for normal users - # as writing to the root directory requires elevated privileges. With - # XP and below, the semantics of tmpfile() are the same, but the user - # running the test is more likely to have administrative privileges on - # their account already. If that's the case, then os.tmpfile() should - # work. In order to make this test as useful as possible, rather than - # trying to detect Windows versions or whether or not the user has the - # right permissions, just try and create a file in the root directory - # and see if it raises a 'Permission denied' OSError. If it does, then - # test that a subsequent call to os.tmpfile() raises the same error. If - # it doesn't, assume we're on XP or below and the user running the test - # has administrative privileges, and proceed with the test as normal. - if sys.platform == 'win32': - name = '\\python_test_os_test_tmpfile.txt' - if os.path.exists(name): - os.remove(name) - try: - fp = open(name, 'w') - except IOError as first: - # open() failed, assert tmpfile() fails in the same way. - # Although open() raises an IOError and os.tmpfile() raises an - # OSError(), 'args' will be (13, 'Permission denied') in both - # cases. - try: - fp = os.tmpfile() - except OSError as second: - self.assertEqual(first.args, second.args) - else: - self.fail("expected os.tmpfile() to raise OSError") - return - else: - # open() worked, therefore, tmpfile() should work. Close our - # dummy file and proceed with the test as normal. - fp.close() - os.remove(name) - - fp = os.tmpfile() - fp.write("foobar") - fp.seek(0,0) - s = fp.read() - fp.close() - self.assertTrue(s == "foobar") - - def test_tmpnam(self): - if not hasattr(os, "tmpnam"): - return - warnings.filterwarnings("ignore", "tmpnam", RuntimeWarning, - r"test_os$") - name = os.tmpnam() - if sys.platform in ("win32",): - # The Windows tmpnam() seems useless. From the MS docs: - # - # The character string that tmpnam creates consists of - # the path prefix, defined by the entry P_tmpdir in the - # file STDIO.H, followed by a sequence consisting of the - # digit characters '0' through '9'; the numerical value - # of this string is in the range 1 - 65,535. Changing the - # definitions of L_tmpnam or P_tmpdir in STDIO.H does not - # change the operation of tmpnam. - # - # The really bizarre part is that, at least under MSVC6, - # P_tmpdir is "\\". That is, the path returned refers to - # the root of the current drive. That's a terrible place to - # put temp files, and, depending on privileges, the user - # may not even be able to open a file in the root directory. - self.assertFalse(os.path.exists(name), - "file already exists for temporary file") - else: - self.check_tempfile(name) - def fdopen_helper(self, *args): fd = os.open(support.TESTFN, os.O_RDONLY) - fp2 = os.fdopen(fd, *args) - fp2.close() + f = os.fdopen(fd, *args) + f.close() def test_fdopen(self): + fd = os.open(support.TESTFN, os.O_CREAT|os.O_RDWR) + os.close(fd) + self.fdopen_helper() self.fdopen_helper('r') self.fdopen_helper('r', 100) + # Test attributes on return values from os.*stat* family. class StatAttributeTests(unittest.TestCase): def setUp(self): @@ -1632,7 +1528,6 @@ LinkTests, TestSendfile, ProgramPriorityTests, - TemporaryFileTests, ) if __name__ == "__main__": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 13:55:42 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Fri, 01 Jul 2011 13:55:42 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312442=3A_add_shuti?= =?utf8?b?bC5kaXNrX3VzYWdlKCk=?= Message-ID: http://hg.python.org/cpython/rev/2fc102ebaf73 changeset: 71110:2fc102ebaf73 user: Giampaolo Rodola' date: Fri Jul 01 13:55:36 2011 +0200 summary: Issue #12442: add shutil.disk_usage() files: Doc/library/shutil.rst | 8 ++++++++ Doc/whatsnew/3.3.rst | 11 ++++++++++- Lib/shutil.py | 19 +++++++++++++++++++ Lib/test/test_shutil.py | 10 ++++++++++ Misc/NEWS | 3 +++ Modules/posixmodule.c | 27 +++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 1 deletions(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -164,6 +164,14 @@ If the destination is on the current filesystem, then simply use rename. Otherwise, copy src (with :func:`copy2`) to the dst and then remove src. +.. function:: disk_usage(path) + + Return disk usage statistics about the given path as a namedtuple including + total, used and free space expressed in bytes. + + .. versionadded:: 3.3 + + Availability: Unix, Windows. .. exception:: Error 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 @@ -200,7 +200,16 @@ plaintex. This can be useful to take advantage of firewalls that know how to handle NAT with non-secure FTP without opening fixed ports. -(Patch submitted by Giampaolo Rodol? in :issue:`12139`.) +(Contributed by Giampaolo Rodol? in :issue:`12139`) + + +shutil +------ + +The :mod:`shutil` module has a new :func:`~shutil.disk_usage` providing total, +used and free disk space statistics. + +(Contributed by Giampaolo Rodol? in :issue:`12442`) Optimizations diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -12,6 +12,7 @@ import collections import errno import tarfile +from collections import namedtuple try: import bz2 @@ -754,3 +755,21 @@ func = _UNPACK_FORMATS[format][1] kwargs = dict(_UNPACK_FORMATS[format][2]) func(filename, extract_dir, **kwargs) + +if hasattr(os, "statvfs") or os.name == 'nt': + _ntuple_diskusage = namedtuple('usage', 'total used free') + + def disk_usage(path): + """Return disk usage statistics about the given path as a namedtuple + including total, used and free space expressed in bytes. + """ + if hasattr(os, "statvfs"): + st = os.statvfs(path) + free = (st.f_bavail * st.f_frsize) + total = (st.f_blocks * st.f_frsize) + used = (st.f_blocks - st.f_bfree) * st.f_frsize + else: + import nt + total, free = nt._getdiskusage(path) + used = total - free + return _ntuple_diskusage(total, used, free) 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 @@ -728,6 +728,16 @@ unregister_unpack_format('Boo2') self.assertEqual(get_unpack_formats(), formats) + @unittest.skipUnless(hasattr(shutil, 'disk_usage'), + "disk_usage not available on this platform") + def test_disk_usage(self): + usage = shutil.disk_usage(os.getcwd()) + self.assertTrue(usage.total > 0) + self.assertTrue(usage.used > 0) + self.assertTrue(usage.free >= 0) + self.assertTrue(usage.total >= usage.used) + self.assertTrue(usage.total > usage.free) + class TestMove(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -200,6 +200,9 @@ Library ------- +- Issue #12442: new shutil.disk_usage function, providing total, used and free + disk space statistics. + - Issue #12451: The XInclude default loader of xml.etree now decodes files from UTF-8 instead of the locale encoding if the encoding is not specified. It now also opens XML files for the parser in binary mode instead of the text mode diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7451,6 +7451,32 @@ } #endif /* HAVE_STATVFS */ +#ifdef MS_WINDOWS +PyDoc_STRVAR(win32__getdiskusage__doc__, +"_getdiskusage(path) -> (total, free)\n\n\ +Return disk usage statistics about the given path as (total, free) tuple."); + +static PyObject * +win32__getdiskusage(PyObject *self, PyObject *args) +{ + BOOL retval; + ULARGE_INTEGER _, total, free; + LPCTSTR path; + + if (! PyArg_ParseTuple(args, "s", &path)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + retval = GetDiskFreeSpaceEx(path, &_, &total, &free); + Py_END_ALLOW_THREADS + if (retval == 0) + return PyErr_SetFromWindowsErr(0); + + return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); +} +#endif + + /* This is used for fpathconf(), pathconf(), confstr() and sysconf(). * It maps strings representing configuration variable names to * integer values, allowing those functions to be called with the @@ -9716,6 +9742,7 @@ {"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL}, {"_getfileinformation", posix__getfileinformation, METH_VARARGS, NULL}, {"_isdir", posix__isdir, METH_VARARGS, posix__isdir__doc__}, + {"_getdiskusage", win32__getdiskusage, METH_VARARGS, win32__getdiskusage__doc__}, #endif #ifdef HAVE_GETLOADAVG {"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__}, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 14:19:30 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 14:19:30 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312462=3A_time=2Esl?= =?utf8?q?eep=28=29_now_calls_immediatly_the_=28Python=29_signal_handler_i?= =?utf8?q?f?= Message-ID: http://hg.python.org/cpython/rev/583be15e22ca changeset: 71111:583be15e22ca user: Victor Stinner date: Fri Jul 01 13:50:09 2011 +0200 summary: Issue #12462: time.sleep() now calls immediatly the (Python) signal handler if it is interrupted by a signal, instead of having to wait until the next instruction. Patch reviewed by Antoine Pitrou. files: Misc/NEWS | 4 ++++ Modules/timemodule.c | 17 +++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -200,6 +200,10 @@ Library ------- +- Issue #12462: time.sleep() now calls immediatly the (Python) signal handler + if it is interrupted by a signal, instead of having to wait until the next + instruction. + - Issue #12442: new shutil.disk_usage function, providing total, used and free disk space statistics. diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -915,23 +915,28 @@ #if defined(HAVE_SELECT) && !defined(__EMX__) struct timeval t; double frac; + int err; + frac = fmod(secs, 1.0); secs = floor(secs); t.tv_sec = (long)secs; t.tv_usec = (long)(frac*1000000.0); Py_BEGIN_ALLOW_THREADS - if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) { + err = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); + Py_END_ALLOW_THREADS + if (err != 0) { #ifdef EINTR - if (errno != EINTR) { -#else - if (1) { + if (errno == EINTR) { + if (PyErr_CheckSignals()) + return -1; + } + else #endif - Py_BLOCK_THREADS + { PyErr_SetFromErrno(PyExc_IOError); return -1; } } - Py_END_ALLOW_THREADS #elif defined(__WATCOMC__) && !defined(__QNX__) /* XXX Can't interrupt this sleep */ Py_BEGIN_ALLOW_THREADS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 14:53:41 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 14:53:41 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzExODcw?= =?utf8?q?=3A_Skip_test=5Fthreading=2Etest=5F2=5Fjoin=5Fin=5Fforked=5Fproc?= =?utf8?q?ess=28=29_on_platforms?= Message-ID: http://hg.python.org/cpython/rev/0ed5e6ff10f8 changeset: 71112:0ed5e6ff10f8 branch: 3.2 parent: 71108:aa3a4614a6f3 user: Victor Stinner date: Fri Jul 01 14:26:24 2011 +0200 summary: Issue #11870: Skip test_threading.test_2_join_in_forked_process() on platforms with known OS bugs Share the list of platforms with known OS bugs with other tests. Patch written by Charles-Fran?ois Natali. files: Lib/test/test_threading.py | 25 +++++++++++-------------- 1 files changed, 11 insertions(+), 14 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 @@ -410,6 +410,13 @@ class ThreadJoinOnShutdown(BaseTestCase): + # Between fork() and exec(), only async-safe functions are allowed (issues + # #12316 and #11870), and fork() from a worker thread is known to trigger + # problems with some operating systems (issue #3863): skip problematic tests + # on platforms known to behave badly. + platforms_to_skip = ('freebsd4', 'freebsd5', 'freebsd6', 'netbsd5', + 'os2emx') + def _run_and_join(self, script): script = """if 1: import sys, os, time, threading @@ -440,6 +447,7 @@ self._run_and_join(script) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_2_join_in_forked_process(self): # Like the test above, but from a forked interpreter script = """if 1: @@ -456,15 +464,11 @@ self._run_and_join(script) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_3_join_in_forked_from_thread(self): # Like the test above, but fork() was called from a worker thread # In the forked process, the main Thread object must be marked as stopped. - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'netbsd5', - 'os2emx'): - raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) script = """if 1: main_thread = threading.current_thread() def worker(): @@ -490,15 +494,11 @@ self.assertEqual(data, expected_output) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_4_joining_across_fork_in_worker_thread(self): # There used to be a possible deadlock when forking from a child # thread. See http://bugs.python.org/issue6643. - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): - raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) - # The script takes the following steps: # - The main thread in the parent process starts a new thread and then # tries to join it. @@ -567,6 +567,7 @@ self.assertScriptHasOutput(script, "end of main\n") @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_5_clear_waiter_locks_to_avoid_crash(self): # Check that a spawned thread that forks doesn't segfault on certain # platforms, namely OS X. This used to happen if there was a waiter @@ -579,10 +580,6 @@ # lock will be acquired, we can't know if the internal mutex will be # acquired at the time of the fork. - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): - raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) script = """if True: import os, time, threading -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 14:53:42 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 14:53:42 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28merge_3=2E2=29_Issue_=2311870=3A_Skip_test=5Fthreading=2E?= =?utf8?b?dGVzdF8yX2pvaW5faW5fZm9ya2VkX3Byb2Nlc3MoKQ==?= Message-ID: http://hg.python.org/cpython/rev/f43dee86fffd changeset: 71113:f43dee86fffd parent: 71111:583be15e22ca parent: 71112:0ed5e6ff10f8 user: Victor Stinner date: Fri Jul 01 14:53:07 2011 +0200 summary: (merge 3.2) Issue #11870: Skip test_threading.test_2_join_in_forked_process() on platforms with known OS bugs Share the list of platforms with known OS bugs with other tests. Patch written by Charles-Fran?ois Natali. files: Lib/test/test_threading.py | 25 +++++++++++-------------- 1 files changed, 11 insertions(+), 14 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 @@ -418,6 +418,13 @@ class ThreadJoinOnShutdown(BaseTestCase): + # Between fork() and exec(), only async-safe functions are allowed (issues + # #12316 and #11870), and fork() from a worker thread is known to trigger + # problems with some operating systems (issue #3863): skip problematic tests + # on platforms known to behave badly. + platforms_to_skip = ('freebsd4', 'freebsd5', 'freebsd6', 'netbsd5', + 'os2emx') + def _run_and_join(self, script): script = """if 1: import sys, os, time, threading @@ -448,6 +455,7 @@ self._run_and_join(script) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_2_join_in_forked_process(self): # Like the test above, but from a forked interpreter script = """if 1: @@ -464,15 +472,11 @@ self._run_and_join(script) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_3_join_in_forked_from_thread(self): # Like the test above, but fork() was called from a worker thread # In the forked process, the main Thread object must be marked as stopped. - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'netbsd5', - 'os2emx'): - raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) script = """if 1: main_thread = threading.current_thread() def worker(): @@ -498,15 +502,11 @@ self.assertEqual(data, expected_output) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_4_joining_across_fork_in_worker_thread(self): # There used to be a possible deadlock when forking from a child # thread. See http://bugs.python.org/issue6643. - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): - raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) - # The script takes the following steps: # - The main thread in the parent process starts a new thread and then # tries to join it. @@ -575,6 +575,7 @@ self.assertScriptHasOutput(script, "end of main\n") @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_5_clear_waiter_locks_to_avoid_crash(self): # Check that a spawned thread that forks doesn't segfault on certain # platforms, namely OS X. This used to happen if there was a waiter @@ -587,10 +588,6 @@ # lock will be acquired, we can't know if the internal mutex will be # acquired at the time of the fork. - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): - raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) script = """if True: import os, time, threading -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 15:05:01 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 15:05:01 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzExODcw?= =?utf8?q?=3A_Skip_test=5Fthreading=2Etest=5F2=5Fjoin=5Fin=5Fforked=5Fproc?= =?utf8?q?ess=28=29_on_platforms?= Message-ID: http://hg.python.org/cpython/rev/ff36b8cadfd6 changeset: 71114:ff36b8cadfd6 branch: 2.7 parent: 71086:9a0b6c07b488 user: Victor Stinner date: Fri Jul 01 15:04:03 2011 +0200 summary: Issue #11870: Skip test_threading.test_2_join_in_forked_process() on platforms with known OS bugs Share the list of platforms with known OS bugs with other tests. Patch written by Charles-Fran?ois Natali. files: Lib/test/test_threading.py | 35 +++++++++---------------- 1 files changed, 13 insertions(+), 22 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 @@ -417,6 +417,13 @@ class ThreadJoinOnShutdown(BaseTestCase): + # Between fork() and exec(), only async-safe functions are allowed (issues + # #12316 and #11870), and fork() from a worker thread is known to trigger + # problems with some operating systems (issue #3863): skip problematic tests + # on platforms known to behave badly. + platforms_to_skip = ('freebsd4', 'freebsd5', 'freebsd6', 'netbsd5', + 'os2emx') + def _run_and_join(self, script): script = """if 1: import sys, os, time, threading @@ -448,11 +455,10 @@ self._run_and_join(script) + @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_2_join_in_forked_process(self): # Like the test above, but from a forked interpreter - import os - if not hasattr(os, 'fork'): - return script = """if 1: childpid = os.fork() if childpid != 0: @@ -466,19 +472,11 @@ """ self._run_and_join(script) + @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_3_join_in_forked_from_thread(self): # Like the test above, but fork() was called from a worker thread # In the forked process, the main Thread object must be marked as stopped. - import os - if not hasattr(os, 'fork'): - return - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'netbsd5', - 'os2emx'): - print >>sys.stderr, ('Skipping test_3_join_in_forked_from_thread' - ' due to known OS bugs on'), sys.platform - return script = """if 1: main_thread = threading.current_thread() def worker(): @@ -507,15 +505,11 @@ self.assertEqual(data, expected_output) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_4_joining_across_fork_in_worker_thread(self): # There used to be a possible deadlock when forking from a child # thread. See http://bugs.python.org/issue6643. - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): - raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) - # The script takes the following steps: # - The main thread in the parent process starts a new thread and then # tries to join it. @@ -584,6 +578,7 @@ self.assertScriptHasOutput(script, "end of main\n") @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_5_clear_waiter_locks_to_avoid_crash(self): # Check that a spawned thread that forks doesn't segfault on certain # platforms, namely OS X. This used to happen if there was a waiter @@ -596,10 +591,6 @@ # lock will be acquired, we can't know if the internal mutex will be # acquired at the time of the fork. - # Skip platforms with known problems forking from a worker thread. - # See http://bugs.python.org/issue3863. - if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): - raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) script = """if True: import os, time, threading -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 15:26:02 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 15:26:02 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyMzYz?= =?utf8?q?=3A_improve_siginterrupt=28=29_tests?= Message-ID: http://hg.python.org/cpython/rev/8250f04d5a41 changeset: 71115:8250f04d5a41 branch: 3.2 parent: 71112:0ed5e6ff10f8 user: Victor Stinner date: Fri Jul 01 15:24:50 2011 +0200 summary: Issue #12363: improve siginterrupt() tests Backport commits 968b9ff9a059 and aff0a7b0cb12 from the default branch to 3.2 branch. Extract of the changelog messages: "The previous tests used time.sleep() to synchronize two processes. If the host was too slow, the test could fail. The new tests only use one process, but they use a subprocess to: - have only one thread - have a timeout on the blocking read (select cannot be used in the test, select always fail with EINTR, the kernel doesn't restart it) - not touch signal handling of the parent process" and "Add a basic synchronization code between the child and the parent processes: the child writes "ready" to stdout." I replaced .communicate(timeout=3.0) by an explicit waiting loop using Popen.poll(). files: Lib/test/test_signal.py | 167 +++++++++++++-------------- 1 files changed, 82 insertions(+), 85 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 @@ -1,13 +1,17 @@ -import unittest -from test import support -from contextlib import closing +import errno import gc +import os import pickle import select import signal import subprocess +import sys +import time import traceback -import sys, os, time, errno +import unittest +from test import support +from contextlib import closing +from test.script_helper import spawn_python if sys.platform in ('os2', 'riscos'): raise unittest.SkipTest("Can't test signal on %s" % sys.platform) @@ -276,103 +280,96 @@ @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class SiginterruptTest(unittest.TestCase): - def setUp(self): - """Install a no-op signal handler that can be set to allow - interrupts or not, and arrange for the original signal handler to be - re-installed when the test is finished. - """ - self.signum = signal.SIGUSR1 - oldhandler = signal.signal(self.signum, lambda x,y: None) - self.addCleanup(signal.signal, self.signum, oldhandler) - - def readpipe_interrupted(self): + def readpipe_interrupted(self, interrupt): """Perform a read during which a signal will arrive. Return True if the read is interrupted by the signal and raises an exception. Return False if it returns normally. """ - # Create a pipe that can be used for the read. Also clean it up - # when the test is over, since nothing else will (but see below for - # the write end). - r, w = os.pipe() - self.addCleanup(os.close, r) + class Timeout(Exception): + pass - # Create another process which can send a signal to this one to try - # to interrupt the read. - ppid = os.getpid() - pid = os.fork() + # use a subprocess to have only one thread, to have a timeout on the + # blocking read and to not touch signal handling in this process + code = """if 1: + import errno + import os + import signal + import sys - if pid == 0: - # Child code: sleep to give the parent enough time to enter the - # read() call (there's a race here, but it's really tricky to - # eliminate it); then signal the parent process. Also, sleep - # again to make it likely that the signal is delivered to the - # parent process before the child exits. If the child exits - # first, the write end of the pipe will be closed and the test - # is invalid. + interrupt = %r + r, w = os.pipe() + + def handler(signum, frame): + pass + + print("ready") + sys.stdout.flush() + + signal.signal(signal.SIGALRM, handler) + if interrupt is not None: + signal.siginterrupt(signal.SIGALRM, interrupt) + + # run the test twice + for loop in range(2): + # send a SIGALRM in a second (during the read) + signal.alarm(1) + try: + # blocking call: read from a pipe without data + os.read(r, 1) + except OSError as err: + if err.errno != errno.EINTR: + raise + else: + sys.exit(2) + sys.exit(3) + """ % (interrupt,) + with spawn_python('-c', code) as process: try: - time.sleep(0.2) - os.kill(ppid, self.signum) - time.sleep(0.2) - finally: - # No matter what, just exit as fast as possible now. - exit_subprocess() - else: - # Parent code. - # Make sure the child is eventually reaped, else it'll be a - # zombie for the rest of the test suite run. - self.addCleanup(os.waitpid, pid, 0) + # wait until the child process is loaded and has started + first_line = process.stdout.readline() - # Close the write end of the pipe. The child has a copy, so - # it's not really closed until the child exits. We need it to - # close when the child exits so that in the non-interrupt case - # the read eventually completes, otherwise we could just close - # it *after* the test. - os.close(w) + # Wait the process with a timeout of 3 seconds + timeout = time.time() + 3.0 + while True: + if timeout < time.time(): + raise Timeout() + status = process.poll() + if status is not None: + break + time.sleep(0.1) - # Try the read and report whether it is interrupted or not to - # the caller. - try: - d = os.read(r, 1) + stdout, stderr = process.communicate() + except Timeout: + process.kill() return False - except OSError as err: - if err.errno != errno.EINTR: - raise - return True + else: + stdout = first_line + stdout + exitcode = process.wait() + if exitcode not in (2, 3): + raise Exception("Child error (exit code %s): %s" + % (exitcode, stdout)) + return (exitcode == 3) 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. - """ - i = self.readpipe_interrupted() - self.assertTrue(i) - # Arrival of the signal shouldn't have changed anything. - i = self.readpipe_interrupted() - self.assertTrue(i) + # 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. + interrupted = self.readpipe_interrupted(None) + self.assertTrue(interrupted) 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. - """ - signal.siginterrupt(self.signum, 1) - i = self.readpipe_interrupted() - self.assertTrue(i) - # Arrival of the signal shouldn't have changed anything. - i = self.readpipe_interrupted() - self.assertTrue(i) + # 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. + interrupted = self.readpipe_interrupted(True) + self.assertTrue(interrupted) 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. - """ - signal.siginterrupt(self.signum, 0) - i = self.readpipe_interrupted() - self.assertFalse(i) - # Arrival of the signal shouldn't have changed anything. - i = self.readpipe_interrupted() - self.assertFalse(i) + # 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. + interrupted = self.readpipe_interrupted(False) + self.assertFalse(interrupted) @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 15:26:03 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 15:26:03 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28null_merge_3=2E2=2C_patch_already_applied_to_3=2E3=29?= Message-ID: http://hg.python.org/cpython/rev/7feb11a8acc4 changeset: 71116:7feb11a8acc4 parent: 71113:f43dee86fffd parent: 71115:8250f04d5a41 user: Victor Stinner date: Fri Jul 01 15:25:58 2011 +0200 summary: (null merge 3.2, patch already applied to 3.3) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 16:00:00 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 16:00:00 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyMzYz?= =?utf8?q?=3A_increase_the_timeout_of_siginterrupt=28=29_tests?= Message-ID: http://hg.python.org/cpython/rev/3f30cfe51315 changeset: 71117:3f30cfe51315 branch: 3.2 parent: 71115:8250f04d5a41 user: Victor Stinner date: Fri Jul 01 15:58:39 2011 +0200 summary: Issue #12363: increase the timeout of siginterrupt() tests Move also the "ready" trigger after the installation of the signal handler and the call to siginterrupt(). Use a timeout of 5 seconds instead of 3. Two seconds are supposed to be enough, but some of our buildbots are really slow (especially the FreeBSD 6 VM). files: Lib/test/test_signal.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 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 @@ -302,13 +302,13 @@ def handler(signum, frame): pass - print("ready") - sys.stdout.flush() - signal.signal(signal.SIGALRM, handler) if interrupt is not None: signal.siginterrupt(signal.SIGALRM, interrupt) + print("ready") + sys.stdout.flush() + # run the test twice for loop in range(2): # send a SIGALRM in a second (during the read) @@ -328,8 +328,8 @@ # wait until the child process is loaded and has started first_line = process.stdout.readline() - # Wait the process with a timeout of 3 seconds - timeout = time.time() + 3.0 + # Wait the process with a timeout of 5 seconds + timeout = time.time() + 5.0 while True: if timeout < time.time(): raise Timeout() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 16:00:00 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 01 Jul 2011 16:00:00 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28merge_3=2E2=29_Issue_=2312363=3A_increase_the_timeout_of_?= =?utf8?q?siginterrupt=28=29_tests?= Message-ID: http://hg.python.org/cpython/rev/423268537083 changeset: 71118:423268537083 parent: 71116:7feb11a8acc4 parent: 71117:3f30cfe51315 user: Victor Stinner date: Fri Jul 01 15:59:54 2011 +0200 summary: (merge 3.2) Issue #12363: increase the timeout of siginterrupt() tests Move also the "ready" trigger after the installation of the signal handler and the call to siginterrupt(). Use a timeout of 5 seconds instead of 3. Two seconds are supposed to be enough, but some of our buildbots are really slow (especially the FreeBSD 6 VM). files: Lib/test/test_signal.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 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 @@ -358,13 +358,13 @@ def handler(signum, frame): pass - print("ready") - sys.stdout.flush() - signal.signal(signal.SIGALRM, handler) if interrupt is not None: signal.siginterrupt(signal.SIGALRM, interrupt) + print("ready") + sys.stdout.flush() + # run the test twice for loop in range(2): # send a SIGALRM in a second (during the read) @@ -384,7 +384,7 @@ # wait until the child process is loaded and has started first_line = process.stdout.readline() - stdout, stderr = process.communicate(timeout=3.0) + stdout, stderr = process.communicate(timeout=5.0) except subprocess.TimeoutExpired: process.kill() return False -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 17:54:02 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 01 Jul 2011 17:54:02 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzExODczOiBmaXgg?= =?utf8?q?test_regex_so_it_covers_windows_os=2Esep_as_well=2E?= Message-ID: http://hg.python.org/cpython/rev/f8ece8c93918 changeset: 71119:f8ece8c93918 branch: 3.2 parent: 71117:3f30cfe51315 user: R David Murray date: Fri Jul 01 11:51:50 2011 -0400 summary: #11873: fix test regex so it covers windows os.sep as well. files: Lib/test/test_compileall.py | 2 +- 1 files changed, 1 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', r'ba[^\/]*$', self.pkgdir) self.assertNotCompiled(self.barfn) self.assertCompiled(self.initfn) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 17:54:07 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 01 Jul 2011 17:54:07 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_=2311873=3A_fix_test_regex_so_it_covers_windows_os=2Es?= =?utf8?q?ep_as_well=2E?= Message-ID: http://hg.python.org/cpython/rev/e543c0ddec63 changeset: 71120:e543c0ddec63 parent: 71118:423268537083 parent: 71119:f8ece8c93918 user: R David Murray date: Fri Jul 01 11:53:19 2011 -0400 summary: merge #11873: fix test regex so it covers windows os.sep as well. files: Lib/test/test_compileall.py | 2 +- 1 files changed, 1 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', r'ba[^\/]*$', self.pkgdir) self.assertNotCompiled(self.barfn) self.assertCompiled(self.initfn) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 20:57:37 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 01 Jul 2011 20:57:37 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzExODczOiBhbm90?= =?utf8?q?her_try_at_fixing_the_regex=2C_courtesy_of_Victor_Stinner?= Message-ID: http://hg.python.org/cpython/rev/6fdb1f000d36 changeset: 71121:6fdb1f000d36 branch: 3.2 parent: 71119:f8ece8c93918 user: R David Murray date: Fri Jul 01 14:55:43 2011 -0400 summary: #11873: another try at fixing the regex, courtesy of Victor Stinner files: Lib/test/test_compileall.py | 2 +- 1 files changed, 1 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', r'ba[^\/]*$', self.pkgdir) + self.assertRunOK('-q', '-x', r'ba[^\\/]*$', self.pkgdir) self.assertNotCompiled(self.barfn) self.assertCompiled(self.initfn) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 20:57:37 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 01 Jul 2011 20:57:37 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_=2311873=3A_another_try_at_fixing_the_regex=2C_courtes?= =?utf8?q?y_of_Victor_Stinner?= Message-ID: http://hg.python.org/cpython/rev/775356b583d1 changeset: 71122:775356b583d1 parent: 71120:e543c0ddec63 parent: 71121:6fdb1f000d36 user: R David Murray date: Fri Jul 01 14:57:00 2011 -0400 summary: merge #11873: another try at fixing the regex, courtesy of Victor Stinner files: Lib/test/test_compileall.py | 2 +- 1 files changed, 1 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', r'ba[^\/]*$', self.pkgdir) + self.assertRunOK('-q', '-x', r'ba[^\\/]*$', self.pkgdir) self.assertNotCompiled(self.barfn) self.assertCompiled(self.initfn) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 1 22:56:47 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 01 Jul 2011 22:56:47 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Really_fix_issu?= =?utf8?q?e_=2310898=3A_posixmodule=2Ec_redefines_FSTAT?= Message-ID: http://hg.python.org/cpython/rev/45b27448f95c changeset: 71123:45b27448f95c branch: 2.7 parent: 71114:ff36b8cadfd6 user: Antoine Pitrou date: Fri Jul 01 22:56:03 2011 +0200 summary: Really fix issue #10898: posixmodule.c redefines FSTAT files: Modules/posixmodule.c | 28 ++++++++++++++-------------- 1 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -338,20 +338,6 @@ #define USE_TMPNAM_R #endif -/* choose the appropriate stat and fstat functions and return structs */ -#undef STAT -#undef FSTAT -#undef STRUCT_STAT -#if defined(MS_WIN64) || defined(MS_WINDOWS) -# define STAT win32_stat -# define FSTAT win32_fstat -# define STRUCT_STAT struct win32_stat -#else -# define STAT stat -# define FSTAT fstat -# define STRUCT_STAT struct stat -#endif - #if defined(MAJOR_IN_MKDEV) #include #else @@ -842,6 +828,20 @@ } #endif +/* choose the appropriate stat and fstat functions and return structs */ +#undef STAT +#undef FSTAT +#undef STRUCT_STAT +#if defined(MS_WIN64) || defined(MS_WINDOWS) +# define STAT win32_stat +# define FSTAT win32_fstat +# define STRUCT_STAT struct win32_stat +#else +# define STAT stat +# define FSTAT fstat +# define STRUCT_STAT struct stat +#endif + #ifdef MS_WINDOWS /* The CRT of Windows has a number of flaws wrt. its stat() implementation: - time stamps are restricted to second resolution -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jul 2 05:12:35 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 02 Jul 2011 05:12:35 +0200 Subject: [Python-checkins] Daily reference leaks (775356b583d1): sum=244 Message-ID: results for 775356b583d1 on branch "default" -------------------------------------------- test_packaging leaked [100, 100, 100] references, sum=300 test_pyexpat leaked [0, 0, -56] references, sum=-56 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogBVSJOX', '-x'] From python-checkins at python.org Sat Jul 2 13:57:40 2011 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 02 Jul 2011 13:57:40 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyMzUy?= =?utf8?q?=3A_Fix_a_deadlock_in_multiprocessing=2EHeap_when_a_block_is_fre?= =?utf8?q?ed_by?= Message-ID: http://hg.python.org/cpython/rev/96a0788583c6 changeset: 71124:96a0788583c6 branch: 2.7 user: Charles-Fran?ois Natali date: Sat Jul 02 13:56:19 2011 +0200 summary: Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. files: Lib/multiprocessing/heap.py | 39 ++++++++++++++++--- Lib/test/test_multiprocessing.py | 25 ++++++++++++ Misc/NEWS | 3 + 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -101,6 +101,8 @@ self._stop_to_block = {} self._allocated_blocks = set() self._arenas = [] + # list of pending blocks to free - see free() comment below + self._pending_free_blocks = [] @staticmethod def _roundup(n, alignment): @@ -175,15 +177,39 @@ return start, stop + def _free_pending_blocks(self): + # Free all the blocks in the pending list - called with the lock held. + while True: + try: + block = self._pending_free_blocks.pop() + except IndexError: + break + self._allocated_blocks.remove(block) + self._free(block) + def free(self, block): # free a block returned by malloc() + # Since free() can be called asynchronously by the GC, it could happen + # that it's called while self._lock is held: in that case, + # self._lock.acquire() would deadlock (issue #12352). To avoid that, a + # trylock is used instead, and if the lock can't be acquired + # immediately, the block is added to a list of blocks to be freed + # synchronously sometimes later from malloc() or free(), by calling + # _free_pending_blocks() (appending and retrieving from a list is not + # strictly thread-safe but under cPython it's atomic thanks to the GIL). assert os.getpid() == self._lastpid - self._lock.acquire() - try: - self._allocated_blocks.remove(block) - self._free(block) - finally: - self._lock.release() + if not self._lock.acquire(False): + # can't acquire the lock right now, add the block to the list of + # pending blocks to free + self._pending_free_blocks.append(block) + else: + # we hold the lock + try: + self._free_pending_blocks() + self._allocated_blocks.remove(block) + self._free(block) + finally: + self._lock.release() def malloc(self, size): # return a block of right size (possibly rounded up) @@ -191,6 +217,7 @@ if os.getpid() != self._lastpid: self.__init__() # reinitialize after fork self._lock.acquire() + self._free_pending_blocks() try: size = self._roundup(max(size,1), self._alignment) (arena, start, stop) = self._malloc(size) 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 @@ -1615,6 +1615,8 @@ # verify the state of the heap all = [] occupied = 0 + heap._lock.acquire() + self.addCleanup(heap._lock.release) for L in heap._len_to_seq.values(): for arena, start, stop in L: all.append((heap._arenas.index(arena), start, stop, @@ -1632,6 +1634,29 @@ self.assertTrue((arena != narena and nstart == 0) or (stop == nstart)) + def test_free_from_gc(self): + # Check that freeing of blocks by the garbage collector doesn't deadlock + # (issue #12352). + # Make sure the GC is enabled, and set lower collection thresholds to + # make collections more frequent (and increase the probability of + # deadlock). + if gc.isenabled(): + thresholds = gc.get_threshold() + self.addCleanup(gc.set_threshold, *thresholds) + else: + gc.enable() + self.addCleanup(gc.disable) + gc.set_threshold(10) + + # perform numerous block allocations, with cyclic references to make + # sure objects are collected asynchronously by the gc + for i in range(5000): + a = multiprocessing.heap.BufferWrapper(1) + b = multiprocessing.heap.BufferWrapper(1) + # circular references + a.buddy = b + b.buddy = a + # # # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by + the garbage collector while the Heap lock is held. + - Issue #9516: On Mac OS X, change Distutils to no longer globally attempt to check or set the MACOSX_DEPLOYMENT_TARGET environment variable for the interpreter process. This could cause failures in non-Distutils subprocesses -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 14:09:48 2011 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 02 Jul 2011 14:09:48 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyMzUy?= =?utf8?q?=3A_In_test=5Ffree=5Ffrom=5Fgc=28=29=2C_restore_the_GC_threshold?= =?utf8?q?s_even_if_the_GC?= Message-ID: http://hg.python.org/cpython/rev/874143242d79 changeset: 71125:874143242d79 branch: 2.7 user: Charles-Fran?ois Natali date: Sat Jul 02 14:08:27 2011 +0200 summary: Issue #12352: In test_free_from_gc(), restore the GC thresholds even if the GC wasn't enabled at first. files: Lib/test/test_multiprocessing.py | 7 +++---- 1 files changed, 3 insertions(+), 4 deletions(-) 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 @@ -1640,12 +1640,11 @@ # Make sure the GC is enabled, and set lower collection thresholds to # make collections more frequent (and increase the probability of # deadlock). - if gc.isenabled(): - thresholds = gc.get_threshold() - self.addCleanup(gc.set_threshold, *thresholds) - else: + if not gc.isenabled(): gc.enable() self.addCleanup(gc.disable) + thresholds = gc.get_threshold() + self.addCleanup(gc.set_threshold, *thresholds) gc.set_threshold(10) # perform numerous block allocations, with cyclic references to make -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 14:36:24 2011 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 02 Jul 2011 14:36:24 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4xKTogSXNzdWUgIzEyMzUy?= =?utf8?q?=3A_Fix_a_deadlock_in_multiprocessing=2EHeap_when_a_block_is_fre?= =?utf8?q?ed_by?= Message-ID: http://hg.python.org/cpython/rev/0d4ca1e77205 changeset: 71126:0d4ca1e77205 branch: 3.1 parent: 71040:633597815463 user: Charles-Fran?ois Natali date: Sat Jul 02 14:35:49 2011 +0200 summary: Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. files: Lib/multiprocessing/heap.py | 39 ++++++++++++++++--- Lib/test/test_multiprocessing.py | 24 ++++++++++++ Misc/NEWS | 3 + 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -101,6 +101,8 @@ self._stop_to_block = {} self._allocated_blocks = set() self._arenas = [] + # list of pending blocks to free - see free() comment below + self._pending_free_blocks = [] @staticmethod def _roundup(n, alignment): @@ -175,15 +177,39 @@ return start, stop + def _free_pending_blocks(self): + # Free all the blocks in the pending list - called with the lock held. + while True: + try: + block = self._pending_free_blocks.pop() + except IndexError: + break + self._allocated_blocks.remove(block) + self._free(block) + def free(self, block): # free a block returned by malloc() + # Since free() can be called asynchronously by the GC, it could happen + # that it's called while self._lock is held: in that case, + # self._lock.acquire() would deadlock (issue #12352). To avoid that, a + # trylock is used instead, and if the lock can't be acquired + # immediately, the block is added to a list of blocks to be freed + # synchronously sometimes later from malloc() or free(), by calling + # _free_pending_blocks() (appending and retrieving from a list is not + # strictly thread-safe but under cPython it's atomic thanks to the GIL). assert os.getpid() == self._lastpid - self._lock.acquire() - try: - self._allocated_blocks.remove(block) - self._free(block) - finally: - self._lock.release() + if not self._lock.acquire(False): + # can't acquire the lock right now, add the block to the list of + # pending blocks to free + self._pending_free_blocks.append(block) + else: + # we hold the lock + try: + self._free_pending_blocks() + self._allocated_blocks.remove(block) + self._free(block) + finally: + self._lock.release() def malloc(self, size): # return a block of right size (possibly rounded up) @@ -191,6 +217,7 @@ if os.getpid() != self._lastpid: self.__init__() # reinitialize after fork self._lock.acquire() + self._free_pending_blocks() try: size = self._roundup(max(size,1), self._alignment) (arena, start, stop) = self._malloc(size) 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 @@ -1580,6 +1580,8 @@ # verify the state of the heap all = [] occupied = 0 + heap._lock.acquire() + self.addCleanup(heap._lock.release) for L in list(heap._len_to_seq.values()): for arena, start, stop in L: all.append((heap._arenas.index(arena), start, stop, @@ -1597,6 +1599,28 @@ self.assertTrue((arena != narena and nstart == 0) or (stop == nstart)) + def test_free_from_gc(self): + # Check that freeing of blocks by the garbage collector doesn't deadlock + # (issue #12352). + # Make sure the GC is enabled, and set lower collection thresholds to + # make collections more frequent (and increase the probability of + # deadlock). + if not gc.isenabled(): + gc.enable() + self.addCleanup(gc.disable) + thresholds = gc.get_threshold() + self.addCleanup(gc.set_threshold, *thresholds) + gc.set_threshold(10) + + # perform numerous block allocations, with cyclic references to make + # sure objects are collected asynchronously by the gc + for i in range(5000): + a = multiprocessing.heap.BufferWrapper(1) + b = multiprocessing.heap.BufferWrapper(1) + # circular references + a.buddy = b + b.buddy = a + # # # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -107,6 +107,9 @@ Library ------- +- Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by + the garbage collector while the Heap lock is held. + - Issue #985064: Make plistlib more resilient to faulty input plists. Patch by Mher Movsisyan. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 14:40:21 2011 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 02 Jul 2011 14:40:21 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4xIC0+IDMuMik6?= =?utf8?q?_Merge_issue_=2312352=3A_Fix_a_deadlock_in_multiprocessing=2EHea?= =?utf8?q?p_when_a_block_is?= Message-ID: http://hg.python.org/cpython/rev/37606505b227 changeset: 71127:37606505b227 branch: 3.2 parent: 71121:6fdb1f000d36 parent: 71126:0d4ca1e77205 user: Charles-Fran?ois Natali date: Sat Jul 02 14:39:53 2011 +0200 summary: Merge issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. files: Lib/multiprocessing/heap.py | 39 ++++++++++++++++--- Lib/test/test_multiprocessing.py | 24 ++++++++++++ Misc/NEWS | 3 + 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -101,6 +101,8 @@ self._stop_to_block = {} self._allocated_blocks = set() self._arenas = [] + # list of pending blocks to free - see free() comment below + self._pending_free_blocks = [] @staticmethod def _roundup(n, alignment): @@ -175,15 +177,39 @@ return start, stop + def _free_pending_blocks(self): + # Free all the blocks in the pending list - called with the lock held. + while True: + try: + block = self._pending_free_blocks.pop() + except IndexError: + break + self._allocated_blocks.remove(block) + self._free(block) + def free(self, block): # free a block returned by malloc() + # Since free() can be called asynchronously by the GC, it could happen + # that it's called while self._lock is held: in that case, + # self._lock.acquire() would deadlock (issue #12352). To avoid that, a + # trylock is used instead, and if the lock can't be acquired + # immediately, the block is added to a list of blocks to be freed + # synchronously sometimes later from malloc() or free(), by calling + # _free_pending_blocks() (appending and retrieving from a list is not + # strictly thread-safe but under cPython it's atomic thanks to the GIL). assert os.getpid() == self._lastpid - self._lock.acquire() - try: - self._allocated_blocks.remove(block) - self._free(block) - finally: - self._lock.release() + if not self._lock.acquire(False): + # can't acquire the lock right now, add the block to the list of + # pending blocks to free + self._pending_free_blocks.append(block) + else: + # we hold the lock + try: + self._free_pending_blocks() + self._allocated_blocks.remove(block) + self._free(block) + finally: + self._lock.release() def malloc(self, size): # return a block of right size (possibly rounded up) @@ -191,6 +217,7 @@ if os.getpid() != self._lastpid: self.__init__() # reinitialize after fork self._lock.acquire() + self._free_pending_blocks() try: size = self._roundup(max(size,1), self._alignment) (arena, start, stop) = self._malloc(size) 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 @@ -1672,6 +1672,8 @@ # verify the state of the heap all = [] occupied = 0 + heap._lock.acquire() + self.addCleanup(heap._lock.release) for L in list(heap._len_to_seq.values()): for arena, start, stop in L: all.append((heap._arenas.index(arena), start, stop, @@ -1689,6 +1691,28 @@ self.assertTrue((arena != narena and nstart == 0) or (stop == nstart)) + def test_free_from_gc(self): + # Check that freeing of blocks by the garbage collector doesn't deadlock + # (issue #12352). + # Make sure the GC is enabled, and set lower collection thresholds to + # make collections more frequent (and increase the probability of + # deadlock). + if not gc.isenabled(): + gc.enable() + self.addCleanup(gc.disable) + thresholds = gc.get_threshold() + self.addCleanup(gc.set_threshold, *thresholds) + gc.set_threshold(10) + + # perform numerous block allocations, with cyclic references to make + # sure objects are collected asynchronously by the gc + for i in range(5000): + a = multiprocessing.heap.BufferWrapper(1) + b = multiprocessing.heap.BufferWrapper(1) + # circular references + a.buddy = b + b.buddy = a + # # # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by + the garbage collector while the Heap lock is held. + - Issue #12451: The XInclude default loader of xml.etree now decodes files from UTF-8 instead of the locale encoding if the encoding is not specified. It now also opens XML files for the parser in binary mode instead of the text mode -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 14:43:41 2011 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 02 Jul 2011 14:43:41 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_issue_=2312352=3A_Fix_a_deadlock_in_multiprocessing=2E?= =?utf8?q?Heap_when_a_block_is?= Message-ID: http://hg.python.org/cpython/rev/fd8dc3746992 changeset: 71128:fd8dc3746992 parent: 71122:775356b583d1 parent: 71127:37606505b227 user: Charles-Fran?ois Natali date: Sat Jul 02 14:43:11 2011 +0200 summary: Merge issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. files: Lib/multiprocessing/heap.py | 39 ++++++++++++++++--- Lib/test/test_multiprocessing.py | 24 ++++++++++++ Misc/NEWS | 3 + 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -101,6 +101,8 @@ self._stop_to_block = {} self._allocated_blocks = set() self._arenas = [] + # list of pending blocks to free - see free() comment below + self._pending_free_blocks = [] @staticmethod def _roundup(n, alignment): @@ -175,15 +177,39 @@ return start, stop + def _free_pending_blocks(self): + # Free all the blocks in the pending list - called with the lock held. + while True: + try: + block = self._pending_free_blocks.pop() + except IndexError: + break + self._allocated_blocks.remove(block) + self._free(block) + def free(self, block): # free a block returned by malloc() + # Since free() can be called asynchronously by the GC, it could happen + # that it's called while self._lock is held: in that case, + # self._lock.acquire() would deadlock (issue #12352). To avoid that, a + # trylock is used instead, and if the lock can't be acquired + # immediately, the block is added to a list of blocks to be freed + # synchronously sometimes later from malloc() or free(), by calling + # _free_pending_blocks() (appending and retrieving from a list is not + # strictly thread-safe but under cPython it's atomic thanks to the GIL). assert os.getpid() == self._lastpid - self._lock.acquire() - try: - self._allocated_blocks.remove(block) - self._free(block) - finally: - self._lock.release() + if not self._lock.acquire(False): + # can't acquire the lock right now, add the block to the list of + # pending blocks to free + self._pending_free_blocks.append(block) + else: + # we hold the lock + try: + self._free_pending_blocks() + self._allocated_blocks.remove(block) + self._free(block) + finally: + self._lock.release() def malloc(self, size): # return a block of right size (possibly rounded up) @@ -191,6 +217,7 @@ if os.getpid() != self._lastpid: self.__init__() # reinitialize after fork self._lock.acquire() + self._free_pending_blocks() try: size = self._roundup(max(size,1), self._alignment) (arena, start, stop) = self._malloc(size) 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 @@ -1721,6 +1721,8 @@ # verify the state of the heap all = [] occupied = 0 + heap._lock.acquire() + self.addCleanup(heap._lock.release) for L in list(heap._len_to_seq.values()): for arena, start, stop in L: all.append((heap._arenas.index(arena), start, stop, @@ -1738,6 +1740,28 @@ self.assertTrue((arena != narena and nstart == 0) or (stop == nstart)) + def test_free_from_gc(self): + # Check that freeing of blocks by the garbage collector doesn't deadlock + # (issue #12352). + # Make sure the GC is enabled, and set lower collection thresholds to + # make collections more frequent (and increase the probability of + # deadlock). + if not gc.isenabled(): + gc.enable() + self.addCleanup(gc.disable) + thresholds = gc.get_threshold() + self.addCleanup(gc.set_threshold, *thresholds) + gc.set_threshold(10) + + # perform numerous block allocations, with cyclic references to make + # sure objects are collected asynchronously by the gc + for i in range(5000): + a = multiprocessing.heap.BufferWrapper(1) + b = multiprocessing.heap.BufferWrapper(1) + # circular references + a.buddy = b + b.buddy = a + # # # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -200,6 +200,9 @@ Library ------- +- Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by + the garbage collector while the Heap lock is held. + - Issue #12462: time.sleep() now calls immediatly the (Python) signal handler if it is interrupted by a signal, instead of having to wait until the next instruction. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 16:18:05 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 02 Jul 2011 16:18:05 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_possibily_uninitialized?= =?utf8?q?_memory_usage_=28closes_=2312474=29?= Message-ID: http://hg.python.org/cpython/rev/6b3872a11299 changeset: 71129:6b3872a11299 user: Benjamin Peterson date: Sat Jul 02 09:22:13 2011 -0500 summary: fix possibily uninitialized memory usage (closes #12474) files: Python/symtable.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -904,10 +904,10 @@ st->st_cur = NULL; size = PyList_GET_SIZE(st->st_stack); if (size) { - st->st_cur = (PySTEntryObject *)PyList_GET_ITEM(st->st_stack, - size - 2); if (PyList_SetSlice(st->st_stack, size - 1, size, NULL) < 0) return 0; + if (--size) + st->st_cur = (PySTEntryObject *)PyList_GET_ITEM(st->st_stack, size - 1); } return 1; } -- Repository URL: http://hg.python.org/cpython From merwok at netwok.org Sat Jul 2 16:23:48 2011 From: merwok at netwok.org (=?UTF-8?B?w4lyaWMgQXJhdWpv?=) Date: Sat, 02 Jul 2011 16:23:48 +0200 Subject: [Python-checkins] cpython: Issue #12451: Add support.create_empty_file() In-Reply-To: References: Message-ID: <4E0F29F4.9010100@netwok.org> > changeset: 71103:0c49260e85a0 > user: Victor Stinner > summary: > Issue #12451: Add support.create_empty_file() > > files: > Lib/distutils/tests/test_build_py.py | 6 ++-- Please don?t make cosmetic changes in distutils, especially in tests: It?s not worth the time. This can also make future merges of bugfixes a bit less easy. If you don?t back out the whole changeset (following Antoine?s comment about uselessness, with which I agree), I?ll back out the changes in this distutils test file. Regards From python-checkins at python.org Sat Jul 2 16:47:40 2011 From: python-checkins at python.org (eric.araujo) Date: Sat, 02 Jul 2011 16:47:40 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Clean_up_NEWS_entry_and_tes?= =?utf8?q?ts_for_shutil=2Edisk=5Fusage_=28=2312442=29?= Message-ID: http://hg.python.org/cpython/rev/479973c6aa03 changeset: 71130:479973c6aa03 user: ?ric Araujo date: Sat Jul 02 16:45:45 2011 +0200 summary: Clean up NEWS entry and tests for shutil.disk_usage (#12442) files: Doc/whatsnew/3.3.rst | 2 +- Lib/test/test_shutil.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 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 @@ -206,7 +206,7 @@ shutil ------ -The :mod:`shutil` module has a new :func:`~shutil.disk_usage` providing total, +The :mod:`shutil` module has a new :func:`~shutil.disk_usage` function providing total, used and free disk space statistics. (Contributed by Giampaolo Rodol? in :issue:`12442`) 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 @@ -732,11 +732,11 @@ "disk_usage not available on this platform") def test_disk_usage(self): usage = shutil.disk_usage(os.getcwd()) - self.assertTrue(usage.total > 0) - self.assertTrue(usage.used > 0) - self.assertTrue(usage.free >= 0) - self.assertTrue(usage.total >= usage.used) - self.assertTrue(usage.total > usage.free) + self.assertGreater(usage.total, 0) + self.assertGreater(usage.used, 0) + self.assertGreaterEqual(usage.free, 0) + self.assertGreaterEqual(usage.total, usage.used) + self.assertGreater(usage.total, usage.free) class TestMove(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 17:43:17 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 02 Jul 2011 17:43:17 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2312291?= =?utf8?q?=3A_Fixed_bug_which_was_found_when_doing__multiple_loads_from_on?= =?utf8?q?e?= Message-ID: http://hg.python.org/cpython/rev/edba722f3b02 changeset: 71131:edba722f3b02 branch: 3.2 parent: 71127:37606505b227 user: Vinay Sajip date: Sat Jul 02 16:42:47 2011 +0100 summary: Closes #12291: Fixed bug which was found when doing multiple loads from one stream. files: Lib/importlib/test/source/test_file_loader.py | 2 +- Lib/test/test_marshal.py | 24 + Misc/NEWS | 3 + Python/marshal.c | 215 +++++++-- 4 files changed, 183 insertions(+), 61 deletions(-) diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py --- a/Lib/importlib/test/source/test_file_loader.py +++ b/Lib/importlib/test/source/test_file_loader.py @@ -214,7 +214,7 @@ lambda bc: bc[:8] + b'', del_source=del_source) file_path = mapping['_temp'] if not del_source else bytecode_path - with self.assertRaises(ValueError): + with self.assertRaises(EOFError): self.import_(file_path, '_temp') def _test_bad_magic(self, test, *, del_source=False): diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -211,6 +211,30 @@ invalid_string = b'l\x02\x00\x00\x00\x00\x00\x00\x00' self.assertRaises(ValueError, marshal.loads, invalid_string) + def test_multiple_dumps_and_loads(self): + # Issue 12291: marshal.load() should be callable multiple times + # with interleaved data written by non-marshal code + # Adapted from a patch by Engelbert Gruber. + data = (1, 'abc', b'def', 1.0, (2, 'a', ['b', b'c'])) + for interleaved in (b'', b'0123'): + ilen = len(interleaved) + positions = [] + try: + with open(support.TESTFN, 'wb') as f: + for d in data: + marshal.dump(d, f) + if ilen: + f.write(interleaved) + positions.append(f.tell()) + with open(support.TESTFN, 'rb') as f: + for i, d in enumerate(data): + self.assertEqual(d, marshal.load(f)) + if ilen: + f.read(ilen) + self.assertEqual(positions[i], f.tell()) + finally: + support.unlink(support.TESTFN) + def test_main(): support.run_unittest(IntTestCase, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12291: You can now load multiple marshalled objects from a stream, + with other data interleaved between marshalled objects. + - Issue #12084: os.stat on Windows now works properly with relative symbolic links when called from any directory. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -57,6 +57,7 @@ int error; /* see WFERR_* values */ int depth; /* If fp == NULL, the following are valid: */ + PyObject * readable; /* Stream-like object being read from */ PyObject *str; char *ptr; char *end; @@ -466,27 +467,75 @@ #define rs_byte(p) (((p)->ptr < (p)->end) ? (unsigned char)*(p)->ptr++ : EOF) -#define r_byte(p) ((p)->fp ? getc((p)->fp) : rs_byte(p)) - static int r_string(char *s, int n, RFILE *p) { - if (p->fp != NULL) - /* The result fits into int because it must be <=n. */ - return (int)fread(s, 1, n, p->fp); - if (p->end - p->ptr < n) - n = (int)(p->end - p->ptr); - memcpy(s, p->ptr, n); - p->ptr += n; - return n; + char * ptr; + int read, left; + + if (!p->readable) { + if (p->fp != NULL) + /* The result fits into int because it must be <=n. */ + read = (int) fread(s, 1, n, p->fp); + else { + left = (int)(p->end - p->ptr); + read = (left < n) ? left : n; + memcpy(s, p->ptr, read); + p->ptr += read; + } + } + else { + PyObject *data = PyObject_CallMethod(p->readable, "read", "i", n); + read = 0; + if (data != NULL) { + if (!PyBytes_Check(data)) { + PyErr_Format(PyExc_TypeError, + "f.read() returned not bytes but %.100s", + data->ob_type->tp_name); + } + else { + read = PyBytes_GET_SIZE(data); + if (read > 0) { + ptr = PyBytes_AS_STRING(data); + memcpy(s, ptr, read); + } + } + Py_DECREF(data); + } + } + if (!PyErr_Occurred() && (read < n)) { + PyErr_SetString(PyExc_EOFError, "EOF read where not expected"); + } + return read; +} + + +static int +r_byte(RFILE *p) +{ + int c = EOF; + unsigned char ch; + int n; + + if (!p->readable) + c = p->fp ? getc(p->fp) : rs_byte(p); + else { + n = r_string((char *) &ch, 1, p); + if (n > 0) + c = ch; + } + return c; } static int r_short(RFILE *p) { register short x; - x = r_byte(p); - x |= r_byte(p) << 8; + unsigned char buffer[2]; + + r_string((char *) buffer, 2, p); + x = buffer[0]; + x |= buffer[1] << 8; /* Sign-extension, in case short greater than 16 bits */ x |= -(x & 0x8000); return x; @@ -496,19 +545,13 @@ r_long(RFILE *p) { register long x; - register FILE *fp = p->fp; - if (fp) { - x = getc(fp); - x |= (long)getc(fp) << 8; - x |= (long)getc(fp) << 16; - x |= (long)getc(fp) << 24; - } - else { - x = rs_byte(p); - x |= (long)rs_byte(p) << 8; - x |= (long)rs_byte(p) << 16; - x |= (long)rs_byte(p) << 24; - } + unsigned char buffer[4]; + + r_string((char *) buffer, 4, p); + x = buffer[0]; + x |= (long)buffer[1] << 8; + x |= (long)buffer[2] << 16; + x |= (long)buffer[3] << 24; #if SIZEOF_LONG > 4 /* Sign extension for 64-bit machines */ x |= -(x & 0x80000000L); @@ -526,25 +569,30 @@ static PyObject * r_long64(RFILE *p) { + PyObject * result = NULL; long lo4 = r_long(p); long hi4 = r_long(p); + + if (!PyErr_Occurred()) { #if SIZEOF_LONG > 4 - long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); - return PyLong_FromLong(x); + long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); + result = PyLong_FromLong(x); #else - unsigned char buf[8]; - int one = 1; - int is_little_endian = (int)*(char*)&one; - if (is_little_endian) { - memcpy(buf, &lo4, 4); - memcpy(buf+4, &hi4, 4); + unsigned char buf[8]; + int one = 1; + int is_little_endian = (int)*(char*)&one; + if (is_little_endian) { + memcpy(buf, &lo4, 4); + memcpy(buf+4, &hi4, 4); + } + else { + memcpy(buf, &hi4, 4); + memcpy(buf+4, &lo4, 4); + } + result = _PyLong_FromByteArray(buf, 8, is_little_endian, 1); +#endif } - else { - memcpy(buf, &hi4, 4); - memcpy(buf+4, &lo4, 4); - } - return _PyLong_FromByteArray(buf, 8, is_little_endian, 1); -#endif + return result; } static PyObject * @@ -556,6 +604,8 @@ digit d; n = r_long(p); + if (PyErr_Occurred()) + return NULL; if (n == 0) return (PyObject *)_PyLong_New(0); if (n < -INT_MAX || n > INT_MAX) { @@ -575,6 +625,8 @@ d = 0; for (j=0; j < PyLong_MARSHAL_RATIO; j++) { md = r_short(p); + if (PyErr_Occurred()) + break; if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; d += (digit)md << j*PyLong_MARSHAL_SHIFT; @@ -584,6 +636,8 @@ d = 0; for (j=0; j < shorts_in_top_digit; j++) { md = r_short(p); + if (PyErr_Occurred()) + break; if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; /* topmost marshal digit should be nonzero */ @@ -595,6 +649,10 @@ } d += (digit)md << j*PyLong_MARSHAL_SHIFT; } + if (PyErr_Occurred()) { + Py_DECREF(ob); + return NULL; + } /* top digit should be nonzero, else the resulting PyLong won't be normalized */ ob->ob_digit[size-1] = d; @@ -663,7 +721,8 @@ break; case TYPE_INT: - retval = PyLong_FromLong(r_long(p)); + n = r_long(p); + retval = PyErr_Occurred() ? NULL : PyLong_FromLong(n); break; case TYPE_INT64: @@ -773,6 +832,10 @@ case TYPE_STRING: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); retval = NULL; @@ -798,6 +861,10 @@ char *buffer; n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (unicode size out of range)"); retval = NULL; @@ -823,6 +890,10 @@ case TYPE_TUPLE: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (tuple size out of range)"); retval = NULL; @@ -850,6 +921,10 @@ case TYPE_LIST: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (list size out of range)"); retval = NULL; @@ -902,6 +977,10 @@ case TYPE_SET: case TYPE_FROZENSET: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (set size out of range)"); retval = NULL; @@ -955,10 +1034,20 @@ /* XXX ignore long->int overflows for now */ argcount = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; kwonlyargcount = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; nlocals = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; stacksize = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; flags = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; code = r_object(p); if (code == NULL) goto code_error; @@ -1040,6 +1129,7 @@ { RFILE rf; assert(fp); + rf.readable = NULL; rf.fp = fp; rf.strings = NULL; rf.end = rf.ptr = NULL; @@ -1051,6 +1141,7 @@ { RFILE rf; rf.fp = fp; + rf.readable = NULL; rf.strings = NULL; rf.ptr = rf.end = NULL; return r_long(&rf); @@ -1112,6 +1203,7 @@ RFILE rf; PyObject *result; rf.fp = fp; + rf.readable = NULL; rf.strings = PyList_New(0); rf.depth = 0; rf.ptr = rf.end = NULL; @@ -1126,6 +1218,7 @@ RFILE rf; PyObject *result; rf.fp = NULL; + rf.readable = NULL; rf.ptr = str; rf.end = str + len; rf.strings = PyList_New(0); @@ -1142,6 +1235,7 @@ PyObject *res = NULL; wf.fp = NULL; + wf.readable = NULL; wf.str = PyBytes_FromStringAndSize((char *)NULL, 50); if (wf.str == NULL) return NULL; @@ -1219,33 +1313,33 @@ static PyObject * marshal_load(PyObject *self, PyObject *f) { - /* XXX Quick hack -- need to do this differently */ PyObject *data, *result; RFILE rf; - data = PyObject_CallMethod(f, "read", ""); + char *p; + int n; + + /* + * Make a call to the read method, but read zero bytes. + * This is to ensure that the object passed in at least + * has a read method which returns bytes. + */ + data = PyObject_CallMethod(f, "read", "i", 0); if (data == NULL) return NULL; - rf.fp = NULL; - if (PyBytes_Check(data)) { - rf.ptr = PyBytes_AS_STRING(data); - rf.end = rf.ptr + PyBytes_GET_SIZE(data); - } - else if (PyBytes_Check(data)) { - rf.ptr = PyBytes_AS_STRING(data); - rf.end = rf.ptr + PyBytes_GET_SIZE(data); + if (!PyBytes_Check(data)) { + PyErr_Format(PyExc_TypeError, + "f.read() returned not bytes but %.100s", + data->ob_type->tp_name); + result = NULL; } else { - PyErr_Format(PyExc_TypeError, - "f.read() returned neither string " - "nor bytes but %.100s", - data->ob_type->tp_name); - Py_DECREF(data); - return NULL; + rf.strings = PyList_New(0); + rf.depth = 0; + rf.fp = NULL; + rf.readable = f; + result = read_object(&rf); + Py_DECREF(rf.strings); } - rf.strings = PyList_New(0); - rf.depth = 0; - result = read_object(&rf); - Py_DECREF(rf.strings); Py_DECREF(data); return result; } @@ -1296,6 +1390,7 @@ s = p.buf; n = p.len; rf.fp = NULL; + rf.readable = NULL; rf.ptr = s; rf.end = s + n; rf.strings = PyList_New(0); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 18:16:10 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 02 Jul 2011 18:16:10 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Closes_=2312291_for_3=2E3_-_merged_fix_from_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/42dd11028e94 changeset: 71132:42dd11028e94 parent: 71130:479973c6aa03 parent: 71131:edba722f3b02 user: Vinay Sajip date: Sat Jul 02 17:16:02 2011 +0100 summary: Closes #12291 for 3.3 - merged fix from 3.2. files: Lib/importlib/test/source/test_file_loader.py | 2 +- Lib/test/test_marshal.py | 24 + Misc/NEWS | 3 + Python/marshal.c | 214 +++++++-- 4 files changed, 183 insertions(+), 60 deletions(-) diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py --- a/Lib/importlib/test/source/test_file_loader.py +++ b/Lib/importlib/test/source/test_file_loader.py @@ -214,7 +214,7 @@ lambda bc: bc[:8] + b'', del_source=del_source) file_path = mapping['_temp'] if not del_source else bytecode_path - with self.assertRaises(ValueError): + with self.assertRaises(EOFError): self.import_(file_path, '_temp') def _test_bad_magic(self, test, *, del_source=False): diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -228,6 +228,30 @@ invalid_string = b'l\x02\x00\x00\x00\x00\x00\x00\x00' self.assertRaises(ValueError, marshal.loads, invalid_string) + def test_multiple_dumps_and_loads(self): + # Issue 12291: marshal.load() should be callable multiple times + # with interleaved data written by non-marshal code + # Adapted from a patch by Engelbert Gruber. + data = (1, 'abc', b'def', 1.0, (2, 'a', ['b', b'c'])) + for interleaved in (b'', b'0123'): + ilen = len(interleaved) + positions = [] + try: + with open(support.TESTFN, 'wb') as f: + for d in data: + marshal.dump(d, f) + if ilen: + f.write(interleaved) + positions.append(f.tell()) + with open(support.TESTFN, 'rb') as f: + for i, d in enumerate(data): + self.assertEqual(d, marshal.load(f)) + if ilen: + f.read(ilen) + self.assertEqual(positions[i], f.tell()) + finally: + support.unlink(support.TESTFN) + def test_main(): support.run_unittest(IntTestCase, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12291: You can now load multiple marshalled objects from a stream, + with other data interleaved between marshalled objects. + - Issue #12356: When required positional or keyword-only arguments are not given, produce a informative error message which includes the name(s) of the missing arguments. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -57,6 +57,7 @@ int error; /* see WFERR_* values */ int depth; /* If fp == NULL, the following are valid: */ + PyObject * readable; /* Stream-like object being read from */ PyObject *str; PyObject *current_filename; char *ptr; @@ -463,27 +464,75 @@ #define rs_byte(p) (((p)->ptr < (p)->end) ? (unsigned char)*(p)->ptr++ : EOF) -#define r_byte(p) ((p)->fp ? getc((p)->fp) : rs_byte(p)) - static int r_string(char *s, int n, RFILE *p) { - if (p->fp != NULL) - /* The result fits into int because it must be <=n. */ - return (int)fread(s, 1, n, p->fp); - if (p->end - p->ptr < n) - n = (int)(p->end - p->ptr); - memcpy(s, p->ptr, n); - p->ptr += n; - return n; + char * ptr; + int read, left; + + if (!p->readable) { + if (p->fp != NULL) + /* The result fits into int because it must be <=n. */ + read = (int) fread(s, 1, n, p->fp); + else { + left = (int)(p->end - p->ptr); + read = (left < n) ? left : n; + memcpy(s, p->ptr, read); + p->ptr += read; + } + } + else { + PyObject *data = PyObject_CallMethod(p->readable, "read", "i", n); + read = 0; + if (data != NULL) { + if (!PyBytes_Check(data)) { + PyErr_Format(PyExc_TypeError, + "f.read() returned not bytes but %.100s", + data->ob_type->tp_name); + } + else { + read = PyBytes_GET_SIZE(data); + if (read > 0) { + ptr = PyBytes_AS_STRING(data); + memcpy(s, ptr, read); + } + } + Py_DECREF(data); + } + } + if (!PyErr_Occurred() && (read < n)) { + PyErr_SetString(PyExc_EOFError, "EOF read where not expected"); + } + return read; +} + + +static int +r_byte(RFILE *p) +{ + int c = EOF; + unsigned char ch; + int n; + + if (!p->readable) + c = p->fp ? getc(p->fp) : rs_byte(p); + else { + n = r_string((char *) &ch, 1, p); + if (n > 0) + c = ch; + } + return c; } static int r_short(RFILE *p) { register short x; - x = r_byte(p); - x |= r_byte(p) << 8; + unsigned char buffer[2]; + + r_string((char *) buffer, 2, p); + x = buffer[0]; + x |= buffer[1] << 8; /* Sign-extension, in case short greater than 16 bits */ x |= -(x & 0x8000); return x; @@ -493,19 +542,13 @@ r_long(RFILE *p) { register long x; - register FILE *fp = p->fp; - if (fp) { - x = getc(fp); - x |= (long)getc(fp) << 8; - x |= (long)getc(fp) << 16; - x |= (long)getc(fp) << 24; - } - else { - x = rs_byte(p); - x |= (long)rs_byte(p) << 8; - x |= (long)rs_byte(p) << 16; - x |= (long)rs_byte(p) << 24; - } + unsigned char buffer[4]; + + r_string((char *) buffer, 4, p); + x = buffer[0]; + x |= (long)buffer[1] << 8; + x |= (long)buffer[2] << 16; + x |= (long)buffer[3] << 24; #if SIZEOF_LONG > 4 /* Sign extension for 64-bit machines */ x |= -(x & 0x80000000L); @@ -523,25 +566,30 @@ static PyObject * r_long64(RFILE *p) { + PyObject * result = NULL; long lo4 = r_long(p); long hi4 = r_long(p); + + if (!PyErr_Occurred()) { #if SIZEOF_LONG > 4 - long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); - return PyLong_FromLong(x); + long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); + result = PyLong_FromLong(x); #else - unsigned char buf[8]; - int one = 1; - int is_little_endian = (int)*(char*)&one; - if (is_little_endian) { - memcpy(buf, &lo4, 4); - memcpy(buf+4, &hi4, 4); + unsigned char buf[8]; + int one = 1; + int is_little_endian = (int)*(char*)&one; + if (is_little_endian) { + memcpy(buf, &lo4, 4); + memcpy(buf+4, &hi4, 4); + } + else { + memcpy(buf, &hi4, 4); + memcpy(buf+4, &lo4, 4); + } + result = _PyLong_FromByteArray(buf, 8, is_little_endian, 1); +#endif } - else { - memcpy(buf, &hi4, 4); - memcpy(buf+4, &lo4, 4); - } - return _PyLong_FromByteArray(buf, 8, is_little_endian, 1); -#endif + return result; } static PyObject * @@ -553,6 +601,8 @@ digit d; n = r_long(p); + if (PyErr_Occurred()) + return NULL; if (n == 0) return (PyObject *)_PyLong_New(0); if (n < -INT_MAX || n > INT_MAX) { @@ -572,6 +622,8 @@ d = 0; for (j=0; j < PyLong_MARSHAL_RATIO; j++) { md = r_short(p); + if (PyErr_Occurred()) + break; if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; d += (digit)md << j*PyLong_MARSHAL_SHIFT; @@ -581,6 +633,8 @@ d = 0; for (j=0; j < shorts_in_top_digit; j++) { md = r_short(p); + if (PyErr_Occurred()) + break; if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; /* topmost marshal digit should be nonzero */ @@ -592,6 +646,10 @@ } d += (digit)md << j*PyLong_MARSHAL_SHIFT; } + if (PyErr_Occurred()) { + Py_DECREF(ob); + return NULL; + } /* top digit should be nonzero, else the resulting PyLong won't be normalized */ ob->ob_digit[size-1] = d; @@ -660,7 +718,8 @@ break; case TYPE_INT: - retval = PyLong_FromLong(r_long(p)); + n = r_long(p); + retval = PyErr_Occurred() ? NULL : PyLong_FromLong(n); break; case TYPE_INT64: @@ -770,6 +829,10 @@ case TYPE_STRING: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); retval = NULL; @@ -795,6 +858,10 @@ char *buffer; n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (unicode size out of range)"); retval = NULL; @@ -820,6 +887,10 @@ case TYPE_TUPLE: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (tuple size out of range)"); retval = NULL; @@ -847,6 +918,10 @@ case TYPE_LIST: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (list size out of range)"); retval = NULL; @@ -899,6 +974,10 @@ case TYPE_SET: case TYPE_FROZENSET: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (set size out of range)"); retval = NULL; @@ -952,10 +1031,20 @@ /* XXX ignore long->int overflows for now */ argcount = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; kwonlyargcount = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; nlocals = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; stacksize = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; flags = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; code = r_object(p); if (code == NULL) goto code_error; @@ -1049,6 +1138,7 @@ { RFILE rf; assert(fp); + rf.readable = NULL; rf.fp = fp; rf.current_filename = NULL; rf.end = rf.ptr = NULL; @@ -1060,6 +1150,7 @@ { RFILE rf; rf.fp = fp; + rf.readable = NULL; rf.current_filename = NULL; rf.ptr = rf.end = NULL; return r_long(&rf); @@ -1121,6 +1212,7 @@ RFILE rf; PyObject *result; rf.fp = fp; + rf.readable = NULL; rf.current_filename = NULL; rf.depth = 0; rf.ptr = rf.end = NULL; @@ -1134,6 +1226,7 @@ RFILE rf; PyObject *result; rf.fp = NULL; + rf.readable = NULL; rf.current_filename = NULL; rf.ptr = str; rf.end = str + len; @@ -1149,6 +1242,7 @@ PyObject *res = NULL; wf.fp = NULL; + wf.readable = NULL; wf.str = PyBytes_FromStringAndSize((char *)NULL, 50); if (wf.str == NULL) return NULL; @@ -1224,32 +1318,33 @@ static PyObject * marshal_load(PyObject *self, PyObject *f) { - /* XXX Quick hack -- need to do this differently */ PyObject *data, *result; RFILE rf; - data = PyObject_CallMethod(f, "read", ""); + char *p; + int n; + + /* + * Make a call to the read method, but read zero bytes. + * This is to ensure that the object passed in at least + * has a read method which returns bytes. + */ + data = PyObject_CallMethod(f, "read", "i", 0); if (data == NULL) return NULL; - rf.fp = NULL; - rf.current_filename = NULL; - if (PyBytes_Check(data)) { - rf.ptr = PyBytes_AS_STRING(data); - rf.end = rf.ptr + PyBytes_GET_SIZE(data); - } - else if (PyBytes_Check(data)) { - rf.ptr = PyBytes_AS_STRING(data); - rf.end = rf.ptr + PyBytes_GET_SIZE(data); + if (!PyBytes_Check(data)) { + PyErr_Format(PyExc_TypeError, + "f.read() returned not bytes but %.100s", + data->ob_type->tp_name); + result = NULL; } else { - PyErr_Format(PyExc_TypeError, - "f.read() returned neither string " - "nor bytes but %.100s", - data->ob_type->tp_name); - Py_DECREF(data); - return NULL; + rf.strings = PyList_New(0); + rf.depth = 0; + rf.fp = NULL; + rf.readable = f; + result = read_object(&rf); + Py_DECREF(rf.strings); } - rf.depth = 0; - result = read_object(&rf); Py_DECREF(data); return result; } @@ -1300,6 +1395,7 @@ s = p.buf; n = p.len; rf.fp = NULL; + rf.readable = NULL; rf.current_filename = NULL; rf.ptr = s; rf.end = s + n; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 18:20:00 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 02 Jul 2011 18:20:00 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Removed_breaking_typo_accid?= =?utf8?q?entally_introduced_during_merge_with_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/a7978d73ef2f changeset: 71133:a7978d73ef2f user: Vinay Sajip date: Sat Jul 02 17:19:51 2011 +0100 summary: Removed breaking typo accidentally introduced during merge with 3.2. files: Python/marshal.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1320,8 +1320,6 @@ { PyObject *data, *result; RFILE rf; - char *p; - int n; /* * Make a call to the read method, but read zero bytes. @@ -1338,12 +1336,10 @@ result = NULL; } else { - rf.strings = PyList_New(0); rf.depth = 0; rf.fp = NULL; rf.readable = f; result = read_object(&rf); - Py_DECREF(rf.strings); } Py_DECREF(data); return result; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 18:23:05 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 02 Jul 2011 18:23:05 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Removed_some_un?= =?utf8?q?used_local_variables=2E?= Message-ID: http://hg.python.org/cpython/rev/14efcccc70e6 changeset: 71134:14efcccc70e6 branch: 3.2 parent: 71131:edba722f3b02 user: Vinay Sajip date: Sat Jul 02 17:21:37 2011 +0100 summary: Removed some unused local variables. files: Python/marshal.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1315,8 +1315,6 @@ { PyObject *data, *result; RFILE rf; - char *p; - int n; /* * Make a call to the read method, but read zero bytes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 18:23:06 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 02 Jul 2011 18:23:06 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merged_unused_variable_removal_from_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/abb6b2363418 changeset: 71135:abb6b2363418 parent: 71133:a7978d73ef2f parent: 71134:14efcccc70e6 user: Vinay Sajip date: Sat Jul 02 17:22:58 2011 +0100 summary: Merged unused variable removal from 3.2. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 19:42:31 2011 From: python-checkins at python.org (vinay.sajip) Date: Sat, 02 Jul 2011 19:42:31 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Correct_uninitialized_data_?= =?utf8?q?problem_in_marshal_code=2E?= Message-ID: http://hg.python.org/cpython/rev/42193f3ffc94 changeset: 71136:42193f3ffc94 user: Vinay Sajip date: Sat Jul 02 18:42:21 2011 +0100 summary: Correct uninitialized data problem in marshal code. files: Python/marshal.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1339,6 +1339,7 @@ rf.depth = 0; rf.fp = NULL; rf.readable = f; + rf.current_filename = NULL; result = read_object(&rf); } Py_DECREF(data); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 2 21:21:14 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 02 Jul 2011 21:21:14 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312456=3A_fix_a_pos?= =?utf8?q?sible_hang_on_shutdown_of_a?= Message-ID: http://hg.python.org/cpython/rev/51c1f2cedb96 changeset: 71137:51c1f2cedb96 user: Antoine Pitrou date: Sat Jul 02 21:20:25 2011 +0200 summary: Issue #12456: fix a possible hang on shutdown of a concurrent.futures.ProcessPoolExecutor. files: Lib/concurrent/futures/process.py | 30 +++++++++++----- Lib/test/test_concurrent_futures.py | 7 +++ 2 files changed, 28 insertions(+), 9 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 @@ -50,7 +50,7 @@ from concurrent.futures import _base import queue import multiprocessing -from multiprocessing.queues import SimpleQueue, SentinelReady +from multiprocessing.queues import SimpleQueue, SentinelReady, Full import threading import weakref @@ -195,6 +195,10 @@ result_queue: A multiprocessing.Queue of _ResultItems generated by the process workers. """ + executor = None + + def shutting_down(): + return _shutdown or executor is None or executor._shutdown_thread def shutdown_worker(): # This is an upper bound @@ -202,8 +206,7 @@ for i in range(0, nb_children_alive): call_queue.put(None) # If .join() is not called on the created processes then - # some multiprocessing.Queue methods may deadlock on Mac OS - # X. + # some multiprocessing.Queue methods may deadlock on Mac OS X. for p in processes.values(): p.join() @@ -222,7 +225,7 @@ if executor is not None: executor._broken = True executor._shutdown_thread = True - del executor + executor = None # All futures in flight must be marked failed for work_id, work_item in pending_work_items.items(): work_item.future.set_exception( @@ -242,7 +245,11 @@ if isinstance(result_item, int): # Clean shutdown of a worker using its PID # (avoids marking the executor broken) + assert shutting_down() del processes[result_item] + if not processes: + shutdown_worker() + return elif result_item is not None: work_item = pending_work_items.pop(result_item.work_id, None) # work_item can be None if another process terminated (see above) @@ -257,16 +264,21 @@ # - The interpreter is shutting down OR # - The executor that owns this worker has been collected OR # - The executor that owns this worker has been shutdown. - if _shutdown or executor is None or executor._shutdown_thread: + if shutting_down(): # Since no new work items can be added, it is safe to shutdown # this thread if there are no pending work items. - if not pending_work_items: + if not pending_work_items and call_queue.qsize() == 0: shutdown_worker() return - else: + try: # Start shutting down by telling a process it can exit. - call_queue.put(None) - del executor + call_queue.put_nowait(None) + except Full: + # This is not a problem: we will eventually be woken up (in + # result_queue.get()) and be able to send a sentinel again, + # if necessary. + pass + executor = None _system_limits_checked = False _system_limited = None diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -367,6 +367,13 @@ self.assertEqual([None, None], results) + def test_shutdown_race_issue12456(self): + # Issue #12456: race condition at shutdown where trying to post a + # sentinel in the call queue blocks (the queue is full while processes + # have exited). + self.executor.map(str, [2] * (self.worker_count + 1)) + self.executor.shutdown() + class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest): def test_map_submits_without_iteration(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 03:14:31 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 03 Jul 2011 03:14:31 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzEyMTQ3OiBtYWtl?= =?utf8?q?_send=5Fmessage_correctly_handle_Sender_and_Resent-_headers=2E?= Message-ID: http://hg.python.org/cpython/rev/0f5ea42fb46c changeset: 71138:0f5ea42fb46c branch: 3.2 parent: 71134:14efcccc70e6 user: R David Murray date: Sat Jul 02 21:03:19 2011 -0400 summary: #12147: make send_message correctly handle Sender and Resent- headers. Original patch by Nicolas Estibals. My tweaks to the patch were mostly style/cosmetic, and adding more tests. files: Doc/library/smtplib.rst | 27 ++++- Lib/smtplib.py | 52 +++++++++--- Lib/test/test_smtplib.py | 111 ++++++++++++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + 5 files changed, 172 insertions(+), 22 deletions(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -323,21 +323,32 @@ .. versionchanged:: 3.2 *msg* may be a byte string. -.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=[], rcpt_options=[]) +.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, \ + mail_options=[], rcpt_options=[]) This is a convenience method for calling :meth:`sendmail` with the message represented by an :class:`email.message.Message` object. The arguments have the same meaning as for :meth:`sendmail`, except that *msg* is a ``Message`` object. - If *from_addr* is ``None``, ``send_message`` sets its value to the value of - the :mailheader:`From` header from *msg*. If *to_addrs* is ``None``, - ``send_message`` combines the values (if any) of the :mailheader:`To`, - :mailheader:`CC`, and :mailheader:`Bcc` fields from *msg*. Regardless of - the values of *from_addr* and *to_addrs*, ``send_message`` deletes any Bcc - field from *msg*. It then serializes *msg* using + If *from_addr* is ``None`` or *to_addrs* is ``None``, ``send_message`` fills + those arguments with addresses extracted from the headers of *msg* as + specified in :rfc:`2822`\: *from_addr* is set to the :mailheader:`Sender` + field if it is present, and otherwise to the :mailheader:`From` field. + *to_adresses* combines the values (if any) of the :mailheader:`To`, + :mailheader:`Cc`, and :mailheader:`Bcc` fields from *msg*. If exactly one + set of :mailheader:`Resent-*` headers appear in the message, the regular + headers are ignored and the :mailheader:`Resent-*` headers are used instead. + If the message contains more than one set of :mailheader:`Resent-*` headers, + a :exc:`ValueError` is raised, since there is no way to unambiguously detect + the most recent set of :mailheader:`Resent-` headers. + + ``send_message`` serializes *msg* using :class:`~email.generator.BytesGenerator` with ``\r\n`` as the *linesep*, and - calls :meth:`sendmail` to transmit the resulting message. + calls :meth:`sendmail` to transmit the resulting message. Regardless of the + values of *from_addr* and *to_addrs*, ``send_message`` does not transmit any + :mailheader:`Bcc` or :mailheader:`Resent-Bcc` headers that may appear + in *msg*. .. versionadded:: 3.2 diff --git a/Lib/smtplib.py b/Lib/smtplib.py old mode 100755 new mode 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -49,6 +49,7 @@ import email.generator import base64 import hmac +import copy from email.base64mime import body_encode as encode_base64 from sys import stderr @@ -674,7 +675,7 @@ msg may be a string containing characters in the ASCII range, or a byte string. A string is encoded to bytes using the ascii codec, and lone - \r and \n characters are converted to \r\n characters. + \\r and \\n characters are converted to \\r\\n characters. If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first. If the server does ESMTP, message size @@ -757,24 +758,49 @@ """Converts message to a bytestring and passes it to sendmail. The arguments are as for sendmail, except that msg is an - email.message.Message object. If from_addr is None, the from_addr is - taken from the 'From' header of the Message. If to_addrs is None, its - value is composed from the addresses listed in the 'To', 'CC', and - 'Bcc' fields. Regardless of the values of from_addr and to_addr, any - Bcc field in the Message object is deleted. The Message object is then - serialized using email.generator.BytesGenerator and sendmail is called - to transmit the message. + email.message.Message object. If from_addr is None or to_addrs is + None, these arguments are taken from the headers of the Message as + described in RFC 2822 (a ValueError is raised if there is more than + one set of 'Resent-' headers). Regardless of the values of from_addr and + to_addr, any Bcc field (or Resent-Bcc field, when the Message is a + resent) of the Message object won't be transmitted. The Message + object is then serialized using email.generator.BytesGenerator and + sendmail is called to transmit the message. + """ + # 'Resent-Date' is a mandatory field if the Message is resent (RFC 2822 + # Section 3.6.6). In such a case, we use the 'Resent-*' fields. However, + # if there is more than one 'Resent-' block there's no way to + # unambiguously determine which one is the most recent in all cases, + # so rather than guess we raise a ValueError in that case. + # + # TODO implement heuristics to guess the correct Resent-* block with an + # option allowing the user to enable the heuristics. (It should be + # possible to guess correctly almost all of the time.) + resent =msg.get_all('Resent-Date') + if resent is None: + header_prefix = '' + elif len(resent) == 1: + header_prefix = 'Resent-' + else: + raise ValueError("message has more than one 'Resent-' header block") if from_addr is None: - from_addr = msg['From'] + # Prefer the sender field per RFC 2822:3.6.2. + from_addr = (msg[header_prefix+'Sender'] + if (header_prefix+'Sender') in msg + else msg[header_prefix+'From']) if to_addrs is None: - addr_fields = [f for f in (msg['To'], msg['Bcc'], msg['CC']) - if f is not None] + addr_fields = [f for f in (msg[header_prefix+'To'], + msg[header_prefix+'Bcc'], + msg[header_prefix+'Cc']) if f is not None] to_addrs = [a[1] for a in email.utils.getaddresses(addr_fields)] - del msg['Bcc'] + # Make a local copy so we can delete the bcc headers. + msg_copy = copy.copy(msg) + del msg_copy['Bcc'] + del msg_copy['Resent-Bcc'] with io.BytesIO() as bytesmsg: g = email.generator.BytesGenerator(bytesmsg) - g.flatten(msg, linesep='\r\n') + g.flatten(msg_copy, linesep='\r\n') flatmsg = bytesmsg.getvalue() return self.sendmail(from_addr, to_addrs, flatmsg, mail_options, rcpt_options) 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 @@ -320,13 +320,16 @@ # XXX (see comment in testSend) time.sleep(0.01) smtp.quit() + # make sure the Bcc header is still in the message. + self.assertEqual(m['Bcc'], 'John Root , "Dinsdale" ' + '') self.client_evt.set() self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds m['X-Peer'] = socket.gethostbyname('localhost') - # The Bcc header is deleted before serialization. + # The Bcc header should not be transmitted. del m['Bcc'] mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) @@ -365,6 +368,112 @@ re.MULTILINE) self.assertRegex(debugout, to_addr) + def testSendMessageWithSpecifiedAddresses(self): + # Make sure addresses specified in call override those in message. + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John, Dinsdale' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m, from_addr='joe at example.com', to_addrs='foo at example.net') + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: joe at example.com$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('John', 'Dinsdale'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertNotRegex(debugout, to_addr) + recip = re.compile(r"^recips: .*'foo at example.net'.*$", re.MULTILINE) + self.assertRegex(debugout, recip) + + def testSendMessageWithMultipleFrom(self): + # Sender overrides To + m = email.mime.text.MIMEText('A test message') + m['From'] = 'Bernard, Bianca' + m['Sender'] = 'the_rescuers at Rescue-Aid-Society.com' + m['To'] = 'John, Dinsdale' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: the_rescuers at Rescue-Aid-Society.com$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('John', 'Dinsdale'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertRegex(debugout, to_addr) + + def testSendMessageResent(self): + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John' + m['CC'] = 'Sally, Fred' + m['Bcc'] = 'John Root , "Dinsdale" ' + m['Resent-Date'] = 'Thu, 1 Jan 1970 17:42:00 +0000' + m['Resent-From'] = 'holy at grail.net' + m['Resent-To'] = 'Martha , Jeff' + m['Resent-Bcc'] = 'doe at losthope.net' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # The Resent-Bcc headers are deleted before serialization. + del m['Bcc'] + del m['Resent-Bcc'] + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: holy at grail.net$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('my_mom at great.cooker.com', 'Jeff', 'doe at losthope.net'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertRegex(debugout, to_addr) + + def testSendMessageMultipleResentRaises(self): + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John' + m['CC'] = 'Sally, Fred' + m['Bcc'] = 'John Root , "Dinsdale" ' + m['Resent-Date'] = 'Thu, 1 Jan 1970 17:42:00 +0000' + m['Resent-From'] = 'holy at grail.net' + m['Resent-To'] = 'Martha , Jeff' + m['Resent-Bcc'] = 'doe at losthope.net' + m['Resent-Date'] = 'Thu, 2 Jan 1970 17:42:00 +0000' + m['Resent-To'] = 'holy at grail.net' + m['Resent-From'] = 'Martha , Jeff' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + with self.assertRaises(ValueError): + smtp.send_message(m) + smtp.close() class NonConnectingTests(unittest.TestCase): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -265,6 +265,7 @@ Ben Escoto Andy Eskilsson Stefan Esser +Nicolas Estibals Stephen D Evans Carey Evans Tim Everett diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,9 @@ Library ------- +- Issue #12147: Adjust the new-in-3.2 smtplib.send_message method for better + conformance to the RFCs: correctly handle Sender and Resent- headers. + - Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 03:14:31 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 03 Jul 2011 03:14:31 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_=2312147=3A_make_send=5Fmessage_correctly_handle_Sende?= =?utf8?q?r_and_Resent-_headers=2E?= Message-ID: http://hg.python.org/cpython/rev/b8cec4f3faaa changeset: 71139:b8cec4f3faaa parent: 71137:51c1f2cedb96 parent: 71138:0f5ea42fb46c user: R David Murray date: Sat Jul 02 21:10:44 2011 -0400 summary: merge #12147: make send_message correctly handle Sender and Resent- headers. files: Doc/library/smtplib.rst | 27 ++++- Lib/smtplib.py | 52 +++++++++--- Lib/test/test_smtplib.py | 111 ++++++++++++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + 5 files changed, 172 insertions(+), 22 deletions(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -348,21 +348,32 @@ .. versionchanged:: 3.2 *msg* may be a byte string. -.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=[], rcpt_options=[]) +.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, \ + mail_options=[], rcpt_options=[]) This is a convenience method for calling :meth:`sendmail` with the message represented by an :class:`email.message.Message` object. The arguments have the same meaning as for :meth:`sendmail`, except that *msg* is a ``Message`` object. - If *from_addr* is ``None``, ``send_message`` sets its value to the value of - the :mailheader:`From` header from *msg*. If *to_addrs* is ``None``, - ``send_message`` combines the values (if any) of the :mailheader:`To`, - :mailheader:`CC`, and :mailheader:`Bcc` fields from *msg*. Regardless of - the values of *from_addr* and *to_addrs*, ``send_message`` deletes any Bcc - field from *msg*. It then serializes *msg* using + If *from_addr* is ``None`` or *to_addrs* is ``None``, ``send_message`` fills + those arguments with addresses extracted from the headers of *msg* as + specified in :rfc:`2822`\: *from_addr* is set to the :mailheader:`Sender` + field if it is present, and otherwise to the :mailheader:`From` field. + *to_adresses* combines the values (if any) of the :mailheader:`To`, + :mailheader:`Cc`, and :mailheader:`Bcc` fields from *msg*. If exactly one + set of :mailheader:`Resent-*` headers appear in the message, the regular + headers are ignored and the :mailheader:`Resent-*` headers are used instead. + If the message contains more than one set of :mailheader:`Resent-*` headers, + a :exc:`ValueError` is raised, since there is no way to unambiguously detect + the most recent set of :mailheader:`Resent-` headers. + + ``send_message`` serializes *msg* using :class:`~email.generator.BytesGenerator` with ``\r\n`` as the *linesep*, and - calls :meth:`sendmail` to transmit the resulting message. + calls :meth:`sendmail` to transmit the resulting message. Regardless of the + values of *from_addr* and *to_addrs*, ``send_message`` does not transmit any + :mailheader:`Bcc` or :mailheader:`Resent-Bcc` headers that may appear + in *msg*. .. versionadded:: 3.2 diff --git a/Lib/smtplib.py b/Lib/smtplib.py old mode 100755 new mode 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -49,6 +49,7 @@ import email.generator import base64 import hmac +import copy from email.base64mime import body_encode as encode_base64 from sys import stderr @@ -676,7 +677,7 @@ msg may be a string containing characters in the ASCII range, or a byte string. A string is encoded to bytes using the ascii codec, and lone - \r and \n characters are converted to \r\n characters. + \\r and \\n characters are converted to \\r\\n characters. If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first. If the server does ESMTP, message size @@ -759,24 +760,49 @@ """Converts message to a bytestring and passes it to sendmail. The arguments are as for sendmail, except that msg is an - email.message.Message object. If from_addr is None, the from_addr is - taken from the 'From' header of the Message. If to_addrs is None, its - value is composed from the addresses listed in the 'To', 'CC', and - 'Bcc' fields. Regardless of the values of from_addr and to_addr, any - Bcc field in the Message object is deleted. The Message object is then - serialized using email.generator.BytesGenerator and sendmail is called - to transmit the message. + email.message.Message object. If from_addr is None or to_addrs is + None, these arguments are taken from the headers of the Message as + described in RFC 2822 (a ValueError is raised if there is more than + one set of 'Resent-' headers). Regardless of the values of from_addr and + to_addr, any Bcc field (or Resent-Bcc field, when the Message is a + resent) of the Message object won't be transmitted. The Message + object is then serialized using email.generator.BytesGenerator and + sendmail is called to transmit the message. + """ + # 'Resent-Date' is a mandatory field if the Message is resent (RFC 2822 + # Section 3.6.6). In such a case, we use the 'Resent-*' fields. However, + # if there is more than one 'Resent-' block there's no way to + # unambiguously determine which one is the most recent in all cases, + # so rather than guess we raise a ValueError in that case. + # + # TODO implement heuristics to guess the correct Resent-* block with an + # option allowing the user to enable the heuristics. (It should be + # possible to guess correctly almost all of the time.) + resent =msg.get_all('Resent-Date') + if resent is None: + header_prefix = '' + elif len(resent) == 1: + header_prefix = 'Resent-' + else: + raise ValueError("message has more than one 'Resent-' header block") if from_addr is None: - from_addr = msg['From'] + # Prefer the sender field per RFC 2822:3.6.2. + from_addr = (msg[header_prefix+'Sender'] + if (header_prefix+'Sender') in msg + else msg[header_prefix+'From']) if to_addrs is None: - addr_fields = [f for f in (msg['To'], msg['Bcc'], msg['CC']) - if f is not None] + addr_fields = [f for f in (msg[header_prefix+'To'], + msg[header_prefix+'Bcc'], + msg[header_prefix+'Cc']) if f is not None] to_addrs = [a[1] for a in email.utils.getaddresses(addr_fields)] - del msg['Bcc'] + # Make a local copy so we can delete the bcc headers. + msg_copy = copy.copy(msg) + del msg_copy['Bcc'] + del msg_copy['Resent-Bcc'] with io.BytesIO() as bytesmsg: g = email.generator.BytesGenerator(bytesmsg) - g.flatten(msg, linesep='\r\n') + g.flatten(msg_copy, linesep='\r\n') flatmsg = bytesmsg.getvalue() return self.sendmail(from_addr, to_addrs, flatmsg, mail_options, rcpt_options) 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 @@ -320,13 +320,16 @@ # XXX (see comment in testSend) time.sleep(0.01) smtp.quit() + # make sure the Bcc header is still in the message. + self.assertEqual(m['Bcc'], 'John Root , "Dinsdale" ' + '') self.client_evt.set() self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds m['X-Peer'] = socket.gethostbyname('localhost') - # The Bcc header is deleted before serialization. + # The Bcc header should not be transmitted. del m['Bcc'] mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) @@ -365,6 +368,112 @@ re.MULTILINE) self.assertRegex(debugout, to_addr) + def testSendMessageWithSpecifiedAddresses(self): + # Make sure addresses specified in call override those in message. + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John, Dinsdale' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m, from_addr='joe at example.com', to_addrs='foo at example.net') + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: joe at example.com$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('John', 'Dinsdale'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertNotRegex(debugout, to_addr) + recip = re.compile(r"^recips: .*'foo at example.net'.*$", re.MULTILINE) + self.assertRegex(debugout, recip) + + def testSendMessageWithMultipleFrom(self): + # Sender overrides To + m = email.mime.text.MIMEText('A test message') + m['From'] = 'Bernard, Bianca' + m['Sender'] = 'the_rescuers at Rescue-Aid-Society.com' + m['To'] = 'John, Dinsdale' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: the_rescuers at Rescue-Aid-Society.com$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('John', 'Dinsdale'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertRegex(debugout, to_addr) + + def testSendMessageResent(self): + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John' + m['CC'] = 'Sally, Fred' + m['Bcc'] = 'John Root , "Dinsdale" ' + m['Resent-Date'] = 'Thu, 1 Jan 1970 17:42:00 +0000' + m['Resent-From'] = 'holy at grail.net' + m['Resent-To'] = 'Martha , Jeff' + m['Resent-Bcc'] = 'doe at losthope.net' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # The Resent-Bcc headers are deleted before serialization. + del m['Bcc'] + del m['Resent-Bcc'] + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: holy at grail.net$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('my_mom at great.cooker.com', 'Jeff', 'doe at losthope.net'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertRegex(debugout, to_addr) + + def testSendMessageMultipleResentRaises(self): + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John' + m['CC'] = 'Sally, Fred' + m['Bcc'] = 'John Root , "Dinsdale" ' + m['Resent-Date'] = 'Thu, 1 Jan 1970 17:42:00 +0000' + m['Resent-From'] = 'holy at grail.net' + m['Resent-To'] = 'Martha , Jeff' + m['Resent-Bcc'] = 'doe at losthope.net' + m['Resent-Date'] = 'Thu, 2 Jan 1970 17:42:00 +0000' + m['Resent-To'] = 'holy at grail.net' + m['Resent-From'] = 'Martha , Jeff' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + with self.assertRaises(ValueError): + smtp.send_message(m) + smtp.close() class NonConnectingTests(unittest.TestCase): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -278,6 +278,7 @@ Andy Eskilsson Andr? Espaze Stefan Esser +Nicolas Estibals Stephen D Evans Carey Evans Tim Everett diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -203,6 +203,9 @@ Library ------- +- Issue #12147: Adjust the new-in-3.2 smtplib.send_message method for better + conformance to the RFCs: correctly handle Sender and Resent- headers. + - Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 3 05:09:01 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 03 Jul 2011 05:09:01 +0200 Subject: [Python-checkins] Daily reference leaks (b8cec4f3faaa): sum=-393 Message-ID: results for b8cec4f3faaa on branch "default" -------------------------------------------- test_concurrent_futures leaked [0, 0, -693] references, sum=-693 test_packaging leaked [100, 100, 100] references, sum=300 test_pydoc leaked [0, -323, 323] references, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog4pW5vH', '-x'] From python-checkins at python.org Sun Jul 3 09:22:48 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 03 Jul 2011 09:22:48 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_disable_ASDLGEN?= =?utf8?q?_if_hg_won=27t_work=2C_or_if_python_is_not_installed=2E?= Message-ID: http://hg.python.org/cpython/rev/4e0c1128cda2 changeset: 71140:4e0c1128cda2 branch: 3.2 parent: 71138:0f5ea42fb46c user: Ralf Schmitt date: Tue May 31 17:10:03 2011 -0500 summary: disable ASDLGEN if hg won't work, or if python is not installed. This change makes configure check for - the existence of a hg repository - the hg executable itself - the python executable Running $(srcdir)/Parser/asdl_c.py (i.e. ASDLGEN) will fail if any of the above prerequisites is missing, so we now disable it instead. closes #12225 files: Makefile.pre.in | 2 +- configure.in | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -274,7 +274,7 @@ ASDLGEN_FILES= $(srcdir)/Parser/asdl.py $(srcdir)/Parser/asdl_c.py # XXX Note that a build now requires Python exist before the build starts -ASDLGEN= $(srcdir)/Parser/asdl_c.py +ASDLGEN= @DISABLE_ASDLGEN@ $(srcdir)/Parser/asdl_c.py ########################################################################## # Python diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -832,7 +832,13 @@ AC_SUBST(HGVERSION) AC_SUBST(HGTAG) AC_SUBST(HGBRANCH) + +if test -e $srcdir/.hg/00changelog.i +then AC_CHECK_PROG(HAS_HG, hg, found, not-found) +else +HAS_HG=no-repository +fi if test $HAS_HG = found then HGVERSION="hg id -i \$(srcdir)" @@ -844,6 +850,15 @@ HGBRANCH="" fi +AC_SUBST(DISABLE_ASDLGEN) +DISABLE_ASDLGEN="" +AC_CHECK_PROG(HAS_PYTHON, python, found, not-found) +if test $HAS_HG != found -o $HAS_PYTHON != found +then + DISABLE_ASDLGEN="@echo hg: $HAS_HG, python: $HAS_PYTHON! cannot run \$(srcdir)/Parser/asdl_c.py #" +fi + + case $MACHDEP in bsdos*|hp*|HP*) # install -d does not work on BSDI or HP-UX -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 09:22:49 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 03 Jul 2011 09:22:49 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Regenerate_conf?= =?utf8?q?igure=2E?= Message-ID: http://hg.python.org/cpython/rev/2a3563bc9fcb changeset: 71141:2a3563bc9fcb branch: 3.2 user: Georg Brandl date: Sun Jul 03 09:23:20 2011 +0200 summary: Regenerate configure. files: configure | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 54 insertions(+), 0 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -644,6 +644,8 @@ INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM +HAS_PYTHON +DISABLE_ASDLGEN HAS_HG HGBRANCH HGTAG @@ -5204,6 +5206,9 @@ + +if test -e $srcdir/.hg/00changelog.i +then # Extract the first word of "hg", so it can be a program name with args. set dummy hg; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -5242,6 +5247,9 @@ fi +else +HAS_HG=no-repository +fi if test $HAS_HG = found then HGVERSION="hg id -i \$(srcdir)" @@ -5253,6 +5261,52 @@ HGBRANCH="" fi + +DISABLE_ASDLGEN="" +# Extract the first word of "python", so it can be a program name with args. +set dummy python; 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_PYTHON+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$HAS_PYTHON"; then + ac_cv_prog_HAS_PYTHON="$HAS_PYTHON" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_HAS_PYTHON="found" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_HAS_PYTHON" && ac_cv_prog_HAS_PYTHON="not-found" +fi +fi +HAS_PYTHON=$ac_cv_prog_HAS_PYTHON +if test -n "$HAS_PYTHON"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAS_PYTHON" >&5 +$as_echo "$HAS_PYTHON" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +if test $HAS_HG != found -o $HAS_PYTHON != found +then + DISABLE_ASDLGEN="@echo hg: $HAS_HG, python: $HAS_PYTHON! cannot run \$(srcdir)/Parser/asdl_c.py #" +fi + + case $MACHDEP in bsdos*|hp*|HP*) # install -d does not work on BSDI or HP-UX -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 09:25:01 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 03 Jul 2011 09:25:01 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Dummy-merge_configure_change_from_3=2E2_that_is_already_in_d?= =?utf8?q?efault=2E?= Message-ID: http://hg.python.org/cpython/rev/6395a901c380 changeset: 71142:6395a901c380 parent: 71139:b8cec4f3faaa parent: 71141:2a3563bc9fcb user: Georg Brandl date: Sun Jul 03 09:25:32 2011 +0200 summary: Dummy-merge configure change from 3.2 that is already in default. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 11:35:47 2011 From: python-checkins at python.org (vinay.sajip) Date: Sun, 03 Jul 2011 11:35:47 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312406=3A_Added_upa?= =?utf8?q?tes_for_packaging=27s_=2Eexe_files=2C_command=5Ftemplate=2C_and?= Message-ID: http://hg.python.org/cpython/rev/3ce11ddc9ec3 changeset: 71143:3ce11ddc9ec3 user: Vinay Sajip date: Sun Jul 03 10:35:41 2011 +0100 summary: Issue #12406: Added upates for packaging's .exe files, command_template, and sysconfig.cfg. files: Tools/msi/msi.py | 7 ++++++- 1 files changed, 6 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 @@ -119,6 +119,7 @@ "30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}", "31":"{4afcba0b-13e4-47c3-bebe-477428b46913}", "32":"{3ff95315-1096-4d31-bd86-601d5438ad5e}", + "33":"{f7581ca4-d368-4eea-8f82-d48c64c4f047}", } [major+minor] # Compute the name that Sphinx gives to the docfile @@ -1010,6 +1011,8 @@ lib.remove_pyc() # package READMEs if present lib.glob("README") + if dir=='Lib': + lib.add_file("sysconfig.cfg") if dir=='test' and parent.physical=='Lib': lib.add_file("185test.db") lib.add_file("audiotest.au") @@ -1045,7 +1048,7 @@ if dir=="Icons": lib.glob("*.gif") lib.add_file("idle.icns") - if dir=="command" and parent.physical=="distutils": + if dir=="command" and parent.physical in ("distutils", "packaging"): lib.glob("wininst*.exe") lib.add_file("command_template") if dir=="lib2to3": @@ -1156,6 +1159,8 @@ lib.add_file("README.txt", src="README") if f == 'Scripts': lib.add_file("2to3.py", src="2to3") + lib.add_file("pydoc3.py", src="pydoc3") + lib.add_file("pysetup3.py", src="pysetup3") if have_tcl: lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw") lib.add_file("pydocgui.pyw") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 13:17:52 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 03 Jul 2011 13:17:52 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Followup_to_51c1f2cedb96_?= =?utf8?q?=28and_issue_=2312456=29=3A?= Message-ID: http://hg.python.org/cpython/rev/ce52310f61a0 changeset: 71144:ce52310f61a0 user: Antoine Pitrou date: Sun Jul 03 13:17:06 2011 +0200 summary: Followup to 51c1f2cedb96 (and issue #12456): qsize() raises NotImplementedError on OS X, don't use it. files: Lib/concurrent/futures/process.py | 20 +++++++++--------- 1 files changed, 10 insertions(+), 10 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 @@ -204,7 +204,7 @@ # This is an upper bound nb_children_alive = sum(p.is_alive() for p in processes.values()) for i in range(0, nb_children_alive): - call_queue.put(None) + call_queue.put_nowait(None) # If .join() is not called on the created processes then # some multiprocessing.Queue methods may deadlock on Mac OS X. for p in processes.values(): @@ -265,18 +265,18 @@ # - The executor that owns this worker has been collected OR # - The executor that owns this worker has been shutdown. if shutting_down(): - # Since no new work items can be added, it is safe to shutdown - # this thread if there are no pending work items. - if not pending_work_items and call_queue.qsize() == 0: - shutdown_worker() - return try: - # Start shutting down by telling a process it can exit. - call_queue.put_nowait(None) + # Since no new work items can be added, it is safe to shutdown + # this thread if there are no pending work items. + if not pending_work_items: + shutdown_worker() + return + else: + # Start shutting down by telling a process it can exit. + call_queue.put_nowait(None) except Full: # This is not a problem: we will eventually be woken up (in - # result_queue.get()) and be able to send a sentinel again, - # if necessary. + # result_queue.get()) and be able to send a sentinel again. pass executor = None -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 19:13:19 2011 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 03 Jul 2011 19:13:19 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_reST_indentatio?= =?utf8?q?n_fix_in_sqlite3_docs=2E_rst_uses_3_space_indentation=2E?= Message-ID: http://hg.python.org/cpython/rev/08400969067e changeset: 71145:08400969067e branch: 2.7 parent: 71125:874143242d79 user: Senthil Kumaran date: Sun Jul 03 10:12:59 2011 -0700 summary: reST indentation fix in sqlite3 docs. rst uses 3 space indentation. files: Doc/library/sqlite3.rst | 73 ++++++++++++++-------------- 1 files changed, 37 insertions(+), 36 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -604,42 +604,42 @@ Let's assume we initialize a table as in the example given above:: - conn = sqlite3.connect(":memory:") - c = conn.cursor() - c.execute('''create table stocks - (date text, trans text, symbol text, - qty real, price real)''') - c.execute("""insert into stocks - values ('2006-01-05','BUY','RHAT',100,35.14)""") - conn.commit() - c.close() + conn = sqlite3.connect(":memory:") + c = conn.cursor() + c.execute('''create table stocks + (date text, trans text, symbol text, + qty real, price real)''') + c.execute("""insert into stocks + values ('2006-01-05','BUY','RHAT',100,35.14)""") + conn.commit() + c.close() Now we plug :class:`Row` in:: - >>> conn.row_factory = sqlite3.Row - >>> c = conn.cursor() - >>> c.execute('select * from stocks') - - >>> r = c.fetchone() - >>> type(r) - - >>> r - (u'2006-01-05', u'BUY', u'RHAT', 100.0, 35.14) - >>> len(r) - 5 - >>> r[2] - u'RHAT' - >>> r.keys() - ['date', 'trans', 'symbol', 'qty', 'price'] - >>> r['qty'] - 100.0 - >>> for member in r: print member - ... - 2006-01-05 - BUY - RHAT - 100.0 - 35.14 + >>> conn.row_factory = sqlite3.Row + >>> c = conn.cursor() + >>> c.execute('select * from stocks') + + >>> r = c.fetchone() + >>> type(r) + + >>> r + (u'2006-01-05', u'BUY', u'RHAT', 100.0, 35.14) + >>> len(r) + 5 + >>> r[2] + u'RHAT' + >>> r.keys() + ['date', 'trans', 'symbol', 'qty', 'price'] + >>> r['qty'] + 100.0 + >>> for member in r: print member + ... + 2006-01-05 + BUY + RHAT + 100.0 + 35.14 .. _sqlite3-types: @@ -901,7 +901,8 @@ .. rubric:: Footnotes .. [#f1] The sqlite3 module is not built with loadable extension support by - default, because some platforms (notably Mac OS X) have SQLite libraries which - are compiled without this feature. To get loadable extension support, you must - modify setup.py and remove the line that sets SQLITE_OMIT_LOAD_EXTENSION. + default, because some platforms (notably Mac OS X) have SQLite libraries + which are compiled without this feature. To get loadable extension support, + you must modify setup.py and remove the line that sets + SQLITE_OMIT_LOAD_EXTENSION. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 19:22:47 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 03 Jul 2011 19:22:47 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_mention_of_medical_c?= =?utf8?q?ondition_from_the_test_suite=2E?= Message-ID: http://hg.python.org/cpython/rev/76452b892838 changeset: 71146:76452b892838 parent: 71144:ce52310f61a0 user: Georg Brandl date: Sun Jul 03 19:22:42 2011 +0200 summary: Remove mention of medical condition from the test suite. files: Lib/test/test_csv.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -459,20 +459,20 @@ '5', '6']]) def test_quoted_quote(self): - self.readerAssertEqual('1,2,3,"""I see,"" said the blind man","as he picked up his hammer and saw"', + self.readerAssertEqual('1,2,3,"""I see,"" said the happy man","as he picked up his hammer and saw"', [['1', '2', '3', - '"I see," said the blind man', + '"I see," said the happy man', 'as he picked up his hammer and saw']]) def test_quoted_nl(self): input = '''\ 1,2,3,"""I see,"" -said the blind man","as he picked up his +said the happy man","as he picked up his hammer and saw" 9,8,7,6''' self.readerAssertEqual(input, [['1', '2', '3', - '"I see,"\nsaid the blind man', + '"I see,"\nsaid the happy man', 'as he picked up his\nhammer and saw'], ['9','8','7','6']]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 19:24:01 2011 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 03 Jul 2011 19:24:01 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_reST_indentatio?= =?utf8?q?n_fix_in_sqlite3_docs=2E_rst_uses_3_space_indentation=2E?= Message-ID: http://hg.python.org/cpython/rev/5d1a2b8f508c changeset: 71147:5d1a2b8f508c branch: 3.2 parent: 71141:2a3563bc9fcb user: Senthil Kumaran date: Sun Jul 03 10:17:22 2011 -0700 summary: reST indentation fix in sqlite3 docs. rst uses 3 space indentation. files: Doc/library/sqlite3.rst | 75 ++++++++++++++-------------- 1 files changed, 38 insertions(+), 37 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -599,43 +599,43 @@ Let's assume we initialize a table as in the example given above:: - conn = sqlite3.connect(":memory:") - c = conn.cursor() - c.execute('''create table stocks - (date text, trans text, symbol text, - qty real, price real)''') - c.execute("""insert into stocks - values ('2006-01-05','BUY','RHAT',100,35.14)""") - conn.commit() - c.close() + conn = sqlite3.connect(":memory:") + c = conn.cursor() + c.execute('''create table stocks + (date text, trans text, symbol text, + qty real, price real)''') + c.execute("""insert into stocks + values ('2006-01-05','BUY','RHAT',100,35.14)""") + conn.commit() + c.close() Now we plug :class:`Row` in:: - >>> conn.row_factory = sqlite3.Row - >>> c = conn.cursor() - >>> c.execute('select * from stocks') - - >>> r = c.fetchone() - >>> type(r) - - >>> tuple(r) - ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14) - >>> len(r) - 5 - >>> r[2] - 'RHAT' - >>> r.keys() - ['date', 'trans', 'symbol', 'qty', 'price'] - >>> r['qty'] - 100.0 - >>> for member in r: - ... print(member) - ... - 2006-01-05 - BUY - RHAT - 100.0 - 35.14 + >>> conn.row_factory = sqlite3.Row + >>> c = conn.cursor() + >>> c.execute('select * from stocks') + + >>> r = c.fetchone() + >>> type(r) + + >>> tuple(r) + ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14) + >>> len(r) + 5 + >>> r[2] + 'RHAT' + >>> r.keys() + ['date', 'trans', 'symbol', 'qty', 'price'] + >>> r['qty'] + 100.0 + >>> for member in r: + ... print(member) + ... + 2006-01-05 + BUY + RHAT + 100.0 + 35.14 .. _sqlite3-types: @@ -886,6 +886,7 @@ .. rubric:: Footnotes .. [#f1] The sqlite3 module is not built with loadable extension support by - default, because some platforms (notably Mac OS X) have SQLite libraries which - are compiled without this feature. To get loadable extension support, you must - pass --enable-loadable-sqlite-extensions to configure. + default, because some platforms (notably Mac OS X) have SQLite + libraries which are compiled without this feature. To get loadable + extension support, you must pass --enable-loadable-sqlite-extensions to + configure. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 19:24:02 2011 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 03 Jul 2011 19:24:02 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_from_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/a085e755c892 changeset: 71148:a085e755c892 parent: 71146:76452b892838 parent: 71147:5d1a2b8f508c user: Senthil Kumaran date: Sun Jul 03 10:23:43 2011 -0700 summary: merge from 3.2 files: Doc/library/sqlite3.rst | 75 ++++++++++++++-------------- 1 files changed, 38 insertions(+), 37 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -615,43 +615,43 @@ Let's assume we initialize a table as in the example given above:: - conn = sqlite3.connect(":memory:") - c = conn.cursor() - c.execute('''create table stocks - (date text, trans text, symbol text, - qty real, price real)''') - c.execute("""insert into stocks - values ('2006-01-05','BUY','RHAT',100,35.14)""") - conn.commit() - c.close() + conn = sqlite3.connect(":memory:") + c = conn.cursor() + c.execute('''create table stocks + (date text, trans text, symbol text, + qty real, price real)''') + c.execute("""insert into stocks + values ('2006-01-05','BUY','RHAT',100,35.14)""") + conn.commit() + c.close() Now we plug :class:`Row` in:: - >>> conn.row_factory = sqlite3.Row - >>> c = conn.cursor() - >>> c.execute('select * from stocks') - - >>> r = c.fetchone() - >>> type(r) - - >>> tuple(r) - ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14) - >>> len(r) - 5 - >>> r[2] - 'RHAT' - >>> r.keys() - ['date', 'trans', 'symbol', 'qty', 'price'] - >>> r['qty'] - 100.0 - >>> for member in r: - ... print(member) - ... - 2006-01-05 - BUY - RHAT - 100.0 - 35.14 + >>> conn.row_factory = sqlite3.Row + >>> c = conn.cursor() + >>> c.execute('select * from stocks') + + >>> r = c.fetchone() + >>> type(r) + + >>> tuple(r) + ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14) + >>> len(r) + 5 + >>> r[2] + 'RHAT' + >>> r.keys() + ['date', 'trans', 'symbol', 'qty', 'price'] + >>> r['qty'] + 100.0 + >>> for member in r: + ... print(member) + ... + 2006-01-05 + BUY + RHAT + 100.0 + 35.14 .. _sqlite3-types: @@ -902,6 +902,7 @@ .. rubric:: Footnotes .. [#f1] The sqlite3 module is not built with loadable extension support by - default, because some platforms (notably Mac OS X) have SQLite libraries which - are compiled without this feature. To get loadable extension support, you must - pass --enable-loadable-sqlite-extensions to configure. + default, because some platforms (notably Mac OS X) have SQLite + libraries which are compiled without this feature. To get loadable + extension support, you must pass --enable-loadable-sqlite-extensions to + configure. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 20:44:32 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 20:44:32 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogYWRkIDMuMi4yIGhl?= =?utf8?q?ading?= Message-ID: http://hg.python.org/cpython/rev/60cc7eb9816e changeset: 71149:60cc7eb9816e branch: 3.2 parent: 71127:37606505b227 user: Benjamin Peterson date: Sun Jul 03 13:31:34 2011 -0500 summary: add 3.2.2 heading files: Misc/NEWS | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,20 @@ Python News +++++++++++ +What's New in Python 3.2.2? +=========================== + +*Release date: XX-XX-2011* + +Core and Builtins +----------------- + +Library +------- + +C-API +----- + What's New in Python 3.2.1 release candidate 2? =============================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 20:44:33 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 20:44:33 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/6c955e38daa5 changeset: 71150:6c955e38daa5 parent: 71129:6b3872a11299 parent: 71149:60cc7eb9816e user: Benjamin Peterson date: Sun Jul 03 13:32:17 2011 -0500 summary: merge 3.2 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 20:44:34 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 20:44:34 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_restore_a_gener?= =?utf8?q?ator=27s_caller=27s_exception_state_both_on_yield_and_=28last=29?= =?utf8?q?_return?= Message-ID: http://hg.python.org/cpython/rev/cc7ae81cfe91 changeset: 71151:cc7ae81cfe91 branch: 3.2 parent: 71149:60cc7eb9816e user: Benjamin Peterson date: Sun Jul 03 13:44:00 2011 -0500 summary: restore a generator's caller's exception state both on yield and (last) return This prevents generator exception state from leaking into the caller. Closes #12475. files: Lib/test/test_exceptions.py | 15 +++++++++++++++ Misc/NEWS | 3 +++ Python/ceval.c | 9 +++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -566,6 +566,21 @@ del g self.assertEqual(sys.exc_info()[0], TypeError) + def test_generator_leaking2(self): + # See issue 12475. + def g(): + yield + try: + raise RuntimeError + except RuntimeError: + it = g() + next(it) + try: + next(it) + except StopIteration: + pass + self.assertEqual(sys.exc_info(), (None, None, None)) + def test_generator_finalizing_and_exc_info(self): # See #7173 def simple_gen(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12475: Prevent generators from leaking their exception state into the + callers frame as they return for the last time. + Library ------- diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1881,10 +1881,6 @@ retval = POP(); f->f_stacktop = stack_pointer; why = WHY_YIELD; - /* Put aside the current exception state and restore - that of the calling frame. This only serves when - "yield" is used inside an except handler. */ - SWAP_EXC_STATE(); goto fast_yield; TARGET(POP_EXCEPT) @@ -3021,6 +3017,11 @@ retval = NULL; fast_yield: + if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) + /* Put aside the current exception state and restore that of the + calling frame. */ + SWAP_EXC_STATE(); + if (tstate->use_tracing) { if (tstate->c_tracefunc) { if (why == WHY_RETURN || why == WHY_YIELD) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 20:44:35 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 20:44:35 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/36bc49565281 changeset: 71152:36bc49565281 branch: 3.2 parent: 71151:cc7ae81cfe91 parent: 71147:5d1a2b8f508c user: Benjamin Peterson date: Sun Jul 03 13:44:56 2011 -0500 summary: merge heads files: Doc/library/smtplib.rst | 27 +- Doc/library/sqlite3.rst | 75 +- Lib/importlib/test/source/test_file_loader.py | 2 +- Lib/smtplib.py | 52 +- Lib/test/test_marshal.py | 24 + Lib/test/test_smtplib.py | 111 +++++- Makefile.pre.in | 2 +- Misc/ACKS | 1 + Misc/NEWS | 6 + Python/marshal.c | 213 +++++++-- configure | 54 ++ configure.in | 15 + 12 files changed, 461 insertions(+), 121 deletions(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -323,21 +323,32 @@ .. versionchanged:: 3.2 *msg* may be a byte string. -.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=[], rcpt_options=[]) +.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, \ + mail_options=[], rcpt_options=[]) This is a convenience method for calling :meth:`sendmail` with the message represented by an :class:`email.message.Message` object. The arguments have the same meaning as for :meth:`sendmail`, except that *msg* is a ``Message`` object. - If *from_addr* is ``None``, ``send_message`` sets its value to the value of - the :mailheader:`From` header from *msg*. If *to_addrs* is ``None``, - ``send_message`` combines the values (if any) of the :mailheader:`To`, - :mailheader:`CC`, and :mailheader:`Bcc` fields from *msg*. Regardless of - the values of *from_addr* and *to_addrs*, ``send_message`` deletes any Bcc - field from *msg*. It then serializes *msg* using + If *from_addr* is ``None`` or *to_addrs* is ``None``, ``send_message`` fills + those arguments with addresses extracted from the headers of *msg* as + specified in :rfc:`2822`\: *from_addr* is set to the :mailheader:`Sender` + field if it is present, and otherwise to the :mailheader:`From` field. + *to_adresses* combines the values (if any) of the :mailheader:`To`, + :mailheader:`Cc`, and :mailheader:`Bcc` fields from *msg*. If exactly one + set of :mailheader:`Resent-*` headers appear in the message, the regular + headers are ignored and the :mailheader:`Resent-*` headers are used instead. + If the message contains more than one set of :mailheader:`Resent-*` headers, + a :exc:`ValueError` is raised, since there is no way to unambiguously detect + the most recent set of :mailheader:`Resent-` headers. + + ``send_message`` serializes *msg* using :class:`~email.generator.BytesGenerator` with ``\r\n`` as the *linesep*, and - calls :meth:`sendmail` to transmit the resulting message. + calls :meth:`sendmail` to transmit the resulting message. Regardless of the + values of *from_addr* and *to_addrs*, ``send_message`` does not transmit any + :mailheader:`Bcc` or :mailheader:`Resent-Bcc` headers that may appear + in *msg*. .. versionadded:: 3.2 diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -599,43 +599,43 @@ Let's assume we initialize a table as in the example given above:: - conn = sqlite3.connect(":memory:") - c = conn.cursor() - c.execute('''create table stocks - (date text, trans text, symbol text, - qty real, price real)''') - c.execute("""insert into stocks - values ('2006-01-05','BUY','RHAT',100,35.14)""") - conn.commit() - c.close() + conn = sqlite3.connect(":memory:") + c = conn.cursor() + c.execute('''create table stocks + (date text, trans text, symbol text, + qty real, price real)''') + c.execute("""insert into stocks + values ('2006-01-05','BUY','RHAT',100,35.14)""") + conn.commit() + c.close() Now we plug :class:`Row` in:: - >>> conn.row_factory = sqlite3.Row - >>> c = conn.cursor() - >>> c.execute('select * from stocks') - - >>> r = c.fetchone() - >>> type(r) - - >>> tuple(r) - ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14) - >>> len(r) - 5 - >>> r[2] - 'RHAT' - >>> r.keys() - ['date', 'trans', 'symbol', 'qty', 'price'] - >>> r['qty'] - 100.0 - >>> for member in r: - ... print(member) - ... - 2006-01-05 - BUY - RHAT - 100.0 - 35.14 + >>> conn.row_factory = sqlite3.Row + >>> c = conn.cursor() + >>> c.execute('select * from stocks') + + >>> r = c.fetchone() + >>> type(r) + + >>> tuple(r) + ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14) + >>> len(r) + 5 + >>> r[2] + 'RHAT' + >>> r.keys() + ['date', 'trans', 'symbol', 'qty', 'price'] + >>> r['qty'] + 100.0 + >>> for member in r: + ... print(member) + ... + 2006-01-05 + BUY + RHAT + 100.0 + 35.14 .. _sqlite3-types: @@ -886,6 +886,7 @@ .. rubric:: Footnotes .. [#f1] The sqlite3 module is not built with loadable extension support by - default, because some platforms (notably Mac OS X) have SQLite libraries which - are compiled without this feature. To get loadable extension support, you must - pass --enable-loadable-sqlite-extensions to configure. + default, because some platforms (notably Mac OS X) have SQLite + libraries which are compiled without this feature. To get loadable + extension support, you must pass --enable-loadable-sqlite-extensions to + configure. diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py --- a/Lib/importlib/test/source/test_file_loader.py +++ b/Lib/importlib/test/source/test_file_loader.py @@ -214,7 +214,7 @@ lambda bc: bc[:8] + b'', del_source=del_source) file_path = mapping['_temp'] if not del_source else bytecode_path - with self.assertRaises(ValueError): + with self.assertRaises(EOFError): self.import_(file_path, '_temp') def _test_bad_magic(self, test, *, del_source=False): diff --git a/Lib/smtplib.py b/Lib/smtplib.py old mode 100755 new mode 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -49,6 +49,7 @@ import email.generator import base64 import hmac +import copy from email.base64mime import body_encode as encode_base64 from sys import stderr @@ -674,7 +675,7 @@ msg may be a string containing characters in the ASCII range, or a byte string. A string is encoded to bytes using the ascii codec, and lone - \r and \n characters are converted to \r\n characters. + \\r and \\n characters are converted to \\r\\n characters. If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first. If the server does ESMTP, message size @@ -757,24 +758,49 @@ """Converts message to a bytestring and passes it to sendmail. The arguments are as for sendmail, except that msg is an - email.message.Message object. If from_addr is None, the from_addr is - taken from the 'From' header of the Message. If to_addrs is None, its - value is composed from the addresses listed in the 'To', 'CC', and - 'Bcc' fields. Regardless of the values of from_addr and to_addr, any - Bcc field in the Message object is deleted. The Message object is then - serialized using email.generator.BytesGenerator and sendmail is called - to transmit the message. + email.message.Message object. If from_addr is None or to_addrs is + None, these arguments are taken from the headers of the Message as + described in RFC 2822 (a ValueError is raised if there is more than + one set of 'Resent-' headers). Regardless of the values of from_addr and + to_addr, any Bcc field (or Resent-Bcc field, when the Message is a + resent) of the Message object won't be transmitted. The Message + object is then serialized using email.generator.BytesGenerator and + sendmail is called to transmit the message. + """ + # 'Resent-Date' is a mandatory field if the Message is resent (RFC 2822 + # Section 3.6.6). In such a case, we use the 'Resent-*' fields. However, + # if there is more than one 'Resent-' block there's no way to + # unambiguously determine which one is the most recent in all cases, + # so rather than guess we raise a ValueError in that case. + # + # TODO implement heuristics to guess the correct Resent-* block with an + # option allowing the user to enable the heuristics. (It should be + # possible to guess correctly almost all of the time.) + resent =msg.get_all('Resent-Date') + if resent is None: + header_prefix = '' + elif len(resent) == 1: + header_prefix = 'Resent-' + else: + raise ValueError("message has more than one 'Resent-' header block") if from_addr is None: - from_addr = msg['From'] + # Prefer the sender field per RFC 2822:3.6.2. + from_addr = (msg[header_prefix+'Sender'] + if (header_prefix+'Sender') in msg + else msg[header_prefix+'From']) if to_addrs is None: - addr_fields = [f for f in (msg['To'], msg['Bcc'], msg['CC']) - if f is not None] + addr_fields = [f for f in (msg[header_prefix+'To'], + msg[header_prefix+'Bcc'], + msg[header_prefix+'Cc']) if f is not None] to_addrs = [a[1] for a in email.utils.getaddresses(addr_fields)] - del msg['Bcc'] + # Make a local copy so we can delete the bcc headers. + msg_copy = copy.copy(msg) + del msg_copy['Bcc'] + del msg_copy['Resent-Bcc'] with io.BytesIO() as bytesmsg: g = email.generator.BytesGenerator(bytesmsg) - g.flatten(msg, linesep='\r\n') + g.flatten(msg_copy, linesep='\r\n') flatmsg = bytesmsg.getvalue() return self.sendmail(from_addr, to_addrs, flatmsg, mail_options, rcpt_options) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -211,6 +211,30 @@ invalid_string = b'l\x02\x00\x00\x00\x00\x00\x00\x00' self.assertRaises(ValueError, marshal.loads, invalid_string) + def test_multiple_dumps_and_loads(self): + # Issue 12291: marshal.load() should be callable multiple times + # with interleaved data written by non-marshal code + # Adapted from a patch by Engelbert Gruber. + data = (1, 'abc', b'def', 1.0, (2, 'a', ['b', b'c'])) + for interleaved in (b'', b'0123'): + ilen = len(interleaved) + positions = [] + try: + with open(support.TESTFN, 'wb') as f: + for d in data: + marshal.dump(d, f) + if ilen: + f.write(interleaved) + positions.append(f.tell()) + with open(support.TESTFN, 'rb') as f: + for i, d in enumerate(data): + self.assertEqual(d, marshal.load(f)) + if ilen: + f.read(ilen) + self.assertEqual(positions[i], f.tell()) + finally: + support.unlink(support.TESTFN) + def test_main(): support.run_unittest(IntTestCase, 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 @@ -320,13 +320,16 @@ # XXX (see comment in testSend) time.sleep(0.01) smtp.quit() + # make sure the Bcc header is still in the message. + self.assertEqual(m['Bcc'], 'John Root , "Dinsdale" ' + '') self.client_evt.set() self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds m['X-Peer'] = socket.gethostbyname('localhost') - # The Bcc header is deleted before serialization. + # The Bcc header should not be transmitted. del m['Bcc'] mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) @@ -365,6 +368,112 @@ re.MULTILINE) self.assertRegex(debugout, to_addr) + def testSendMessageWithSpecifiedAddresses(self): + # Make sure addresses specified in call override those in message. + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John, Dinsdale' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m, from_addr='joe at example.com', to_addrs='foo at example.net') + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: joe at example.com$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('John', 'Dinsdale'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertNotRegex(debugout, to_addr) + recip = re.compile(r"^recips: .*'foo at example.net'.*$", re.MULTILINE) + self.assertRegex(debugout, recip) + + def testSendMessageWithMultipleFrom(self): + # Sender overrides To + m = email.mime.text.MIMEText('A test message') + m['From'] = 'Bernard, Bianca' + m['Sender'] = 'the_rescuers at Rescue-Aid-Society.com' + m['To'] = 'John, Dinsdale' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: the_rescuers at Rescue-Aid-Society.com$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('John', 'Dinsdale'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertRegex(debugout, to_addr) + + def testSendMessageResent(self): + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John' + m['CC'] = 'Sally, Fred' + m['Bcc'] = 'John Root , "Dinsdale" ' + m['Resent-Date'] = 'Thu, 1 Jan 1970 17:42:00 +0000' + m['Resent-From'] = 'holy at grail.net' + m['Resent-To'] = 'Martha , Jeff' + m['Resent-Bcc'] = 'doe at losthope.net' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # The Resent-Bcc headers are deleted before serialization. + del m['Bcc'] + del m['Resent-Bcc'] + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: holy at grail.net$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('my_mom at great.cooker.com', 'Jeff', 'doe at losthope.net'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertRegex(debugout, to_addr) + + def testSendMessageMultipleResentRaises(self): + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John' + m['CC'] = 'Sally, Fred' + m['Bcc'] = 'John Root , "Dinsdale" ' + m['Resent-Date'] = 'Thu, 1 Jan 1970 17:42:00 +0000' + m['Resent-From'] = 'holy at grail.net' + m['Resent-To'] = 'Martha , Jeff' + m['Resent-Bcc'] = 'doe at losthope.net' + m['Resent-Date'] = 'Thu, 2 Jan 1970 17:42:00 +0000' + m['Resent-To'] = 'holy at grail.net' + m['Resent-From'] = 'Martha , Jeff' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + with self.assertRaises(ValueError): + smtp.send_message(m) + smtp.close() class NonConnectingTests(unittest.TestCase): diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -274,7 +274,7 @@ ASDLGEN_FILES= $(srcdir)/Parser/asdl.py $(srcdir)/Parser/asdl_c.py # XXX Note that a build now requires Python exist before the build starts -ASDLGEN= $(srcdir)/Parser/asdl_c.py +ASDLGEN= @DISABLE_ASDLGEN@ $(srcdir)/Parser/asdl_c.py ########################################################################## # Python diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -265,6 +265,7 @@ Ben Escoto Andy Eskilsson Stefan Esser +Nicolas Estibals Stephen D Evans Carey Evans Tim Everett diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ Core and Builtins ----------------- +- Issue #12291: You can now load multiple marshalled objects from a stream, + with other data interleaved between marshalled objects. + - Issue #12084: os.stat on Windows now works properly with relative symbolic links when called from any directory. @@ -42,6 +45,9 @@ Library ------- +- Issue #12147: Adjust the new-in-3.2 smtplib.send_message method for better + conformance to the RFCs: correctly handle Sender and Resent- headers. + - Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -57,6 +57,7 @@ int error; /* see WFERR_* values */ int depth; /* If fp == NULL, the following are valid: */ + PyObject * readable; /* Stream-like object being read from */ PyObject *str; char *ptr; char *end; @@ -466,27 +467,75 @@ #define rs_byte(p) (((p)->ptr < (p)->end) ? (unsigned char)*(p)->ptr++ : EOF) -#define r_byte(p) ((p)->fp ? getc((p)->fp) : rs_byte(p)) - static int r_string(char *s, int n, RFILE *p) { - if (p->fp != NULL) - /* The result fits into int because it must be <=n. */ - return (int)fread(s, 1, n, p->fp); - if (p->end - p->ptr < n) - n = (int)(p->end - p->ptr); - memcpy(s, p->ptr, n); - p->ptr += n; - return n; + char * ptr; + int read, left; + + if (!p->readable) { + if (p->fp != NULL) + /* The result fits into int because it must be <=n. */ + read = (int) fread(s, 1, n, p->fp); + else { + left = (int)(p->end - p->ptr); + read = (left < n) ? left : n; + memcpy(s, p->ptr, read); + p->ptr += read; + } + } + else { + PyObject *data = PyObject_CallMethod(p->readable, "read", "i", n); + read = 0; + if (data != NULL) { + if (!PyBytes_Check(data)) { + PyErr_Format(PyExc_TypeError, + "f.read() returned not bytes but %.100s", + data->ob_type->tp_name); + } + else { + read = PyBytes_GET_SIZE(data); + if (read > 0) { + ptr = PyBytes_AS_STRING(data); + memcpy(s, ptr, read); + } + } + Py_DECREF(data); + } + } + if (!PyErr_Occurred() && (read < n)) { + PyErr_SetString(PyExc_EOFError, "EOF read where not expected"); + } + return read; +} + + +static int +r_byte(RFILE *p) +{ + int c = EOF; + unsigned char ch; + int n; + + if (!p->readable) + c = p->fp ? getc(p->fp) : rs_byte(p); + else { + n = r_string((char *) &ch, 1, p); + if (n > 0) + c = ch; + } + return c; } static int r_short(RFILE *p) { register short x; - x = r_byte(p); - x |= r_byte(p) << 8; + unsigned char buffer[2]; + + r_string((char *) buffer, 2, p); + x = buffer[0]; + x |= buffer[1] << 8; /* Sign-extension, in case short greater than 16 bits */ x |= -(x & 0x8000); return x; @@ -496,19 +545,13 @@ r_long(RFILE *p) { register long x; - register FILE *fp = p->fp; - if (fp) { - x = getc(fp); - x |= (long)getc(fp) << 8; - x |= (long)getc(fp) << 16; - x |= (long)getc(fp) << 24; - } - else { - x = rs_byte(p); - x |= (long)rs_byte(p) << 8; - x |= (long)rs_byte(p) << 16; - x |= (long)rs_byte(p) << 24; - } + unsigned char buffer[4]; + + r_string((char *) buffer, 4, p); + x = buffer[0]; + x |= (long)buffer[1] << 8; + x |= (long)buffer[2] << 16; + x |= (long)buffer[3] << 24; #if SIZEOF_LONG > 4 /* Sign extension for 64-bit machines */ x |= -(x & 0x80000000L); @@ -526,25 +569,30 @@ static PyObject * r_long64(RFILE *p) { + PyObject * result = NULL; long lo4 = r_long(p); long hi4 = r_long(p); + + if (!PyErr_Occurred()) { #if SIZEOF_LONG > 4 - long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); - return PyLong_FromLong(x); + long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); + result = PyLong_FromLong(x); #else - unsigned char buf[8]; - int one = 1; - int is_little_endian = (int)*(char*)&one; - if (is_little_endian) { - memcpy(buf, &lo4, 4); - memcpy(buf+4, &hi4, 4); + unsigned char buf[8]; + int one = 1; + int is_little_endian = (int)*(char*)&one; + if (is_little_endian) { + memcpy(buf, &lo4, 4); + memcpy(buf+4, &hi4, 4); + } + else { + memcpy(buf, &hi4, 4); + memcpy(buf+4, &lo4, 4); + } + result = _PyLong_FromByteArray(buf, 8, is_little_endian, 1); +#endif } - else { - memcpy(buf, &hi4, 4); - memcpy(buf+4, &lo4, 4); - } - return _PyLong_FromByteArray(buf, 8, is_little_endian, 1); -#endif + return result; } static PyObject * @@ -556,6 +604,8 @@ digit d; n = r_long(p); + if (PyErr_Occurred()) + return NULL; if (n == 0) return (PyObject *)_PyLong_New(0); if (n < -INT_MAX || n > INT_MAX) { @@ -575,6 +625,8 @@ d = 0; for (j=0; j < PyLong_MARSHAL_RATIO; j++) { md = r_short(p); + if (PyErr_Occurred()) + break; if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; d += (digit)md << j*PyLong_MARSHAL_SHIFT; @@ -584,6 +636,8 @@ d = 0; for (j=0; j < shorts_in_top_digit; j++) { md = r_short(p); + if (PyErr_Occurred()) + break; if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; /* topmost marshal digit should be nonzero */ @@ -595,6 +649,10 @@ } d += (digit)md << j*PyLong_MARSHAL_SHIFT; } + if (PyErr_Occurred()) { + Py_DECREF(ob); + return NULL; + } /* top digit should be nonzero, else the resulting PyLong won't be normalized */ ob->ob_digit[size-1] = d; @@ -663,7 +721,8 @@ break; case TYPE_INT: - retval = PyLong_FromLong(r_long(p)); + n = r_long(p); + retval = PyErr_Occurred() ? NULL : PyLong_FromLong(n); break; case TYPE_INT64: @@ -773,6 +832,10 @@ case TYPE_STRING: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); retval = NULL; @@ -798,6 +861,10 @@ char *buffer; n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (unicode size out of range)"); retval = NULL; @@ -823,6 +890,10 @@ case TYPE_TUPLE: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (tuple size out of range)"); retval = NULL; @@ -850,6 +921,10 @@ case TYPE_LIST: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (list size out of range)"); retval = NULL; @@ -902,6 +977,10 @@ case TYPE_SET: case TYPE_FROZENSET: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (set size out of range)"); retval = NULL; @@ -955,10 +1034,20 @@ /* XXX ignore long->int overflows for now */ argcount = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; kwonlyargcount = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; nlocals = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; stacksize = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; flags = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; code = r_object(p); if (code == NULL) goto code_error; @@ -1040,6 +1129,7 @@ { RFILE rf; assert(fp); + rf.readable = NULL; rf.fp = fp; rf.strings = NULL; rf.end = rf.ptr = NULL; @@ -1051,6 +1141,7 @@ { RFILE rf; rf.fp = fp; + rf.readable = NULL; rf.strings = NULL; rf.ptr = rf.end = NULL; return r_long(&rf); @@ -1112,6 +1203,7 @@ RFILE rf; PyObject *result; rf.fp = fp; + rf.readable = NULL; rf.strings = PyList_New(0); rf.depth = 0; rf.ptr = rf.end = NULL; @@ -1126,6 +1218,7 @@ RFILE rf; PyObject *result; rf.fp = NULL; + rf.readable = NULL; rf.ptr = str; rf.end = str + len; rf.strings = PyList_New(0); @@ -1142,6 +1235,7 @@ PyObject *res = NULL; wf.fp = NULL; + wf.readable = NULL; wf.str = PyBytes_FromStringAndSize((char *)NULL, 50); if (wf.str == NULL) return NULL; @@ -1219,33 +1313,31 @@ static PyObject * marshal_load(PyObject *self, PyObject *f) { - /* XXX Quick hack -- need to do this differently */ PyObject *data, *result; RFILE rf; - data = PyObject_CallMethod(f, "read", ""); + + /* + * Make a call to the read method, but read zero bytes. + * This is to ensure that the object passed in at least + * has a read method which returns bytes. + */ + data = PyObject_CallMethod(f, "read", "i", 0); if (data == NULL) return NULL; - rf.fp = NULL; - if (PyBytes_Check(data)) { - rf.ptr = PyBytes_AS_STRING(data); - rf.end = rf.ptr + PyBytes_GET_SIZE(data); - } - else if (PyBytes_Check(data)) { - rf.ptr = PyBytes_AS_STRING(data); - rf.end = rf.ptr + PyBytes_GET_SIZE(data); + if (!PyBytes_Check(data)) { + PyErr_Format(PyExc_TypeError, + "f.read() returned not bytes but %.100s", + data->ob_type->tp_name); + result = NULL; } else { - PyErr_Format(PyExc_TypeError, - "f.read() returned neither string " - "nor bytes but %.100s", - data->ob_type->tp_name); - Py_DECREF(data); - return NULL; + rf.strings = PyList_New(0); + rf.depth = 0; + rf.fp = NULL; + rf.readable = f; + result = read_object(&rf); + Py_DECREF(rf.strings); } - rf.strings = PyList_New(0); - rf.depth = 0; - result = read_object(&rf); - Py_DECREF(rf.strings); Py_DECREF(data); return result; } @@ -1296,6 +1388,7 @@ s = p.buf; n = p.len; rf.fp = NULL; + rf.readable = NULL; rf.ptr = s; rf.end = s + n; rf.strings = PyList_New(0); diff --git a/configure b/configure --- a/configure +++ b/configure @@ -644,6 +644,8 @@ INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM +HAS_PYTHON +DISABLE_ASDLGEN HAS_HG HGBRANCH HGTAG @@ -5204,6 +5206,9 @@ + +if test -e $srcdir/.hg/00changelog.i +then # Extract the first word of "hg", so it can be a program name with args. set dummy hg; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -5242,6 +5247,9 @@ fi +else +HAS_HG=no-repository +fi if test $HAS_HG = found then HGVERSION="hg id -i \$(srcdir)" @@ -5253,6 +5261,52 @@ HGBRANCH="" fi + +DISABLE_ASDLGEN="" +# Extract the first word of "python", so it can be a program name with args. +set dummy python; 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_PYTHON+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$HAS_PYTHON"; then + ac_cv_prog_HAS_PYTHON="$HAS_PYTHON" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_HAS_PYTHON="found" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_HAS_PYTHON" && ac_cv_prog_HAS_PYTHON="not-found" +fi +fi +HAS_PYTHON=$ac_cv_prog_HAS_PYTHON +if test -n "$HAS_PYTHON"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAS_PYTHON" >&5 +$as_echo "$HAS_PYTHON" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +if test $HAS_HG != found -o $HAS_PYTHON != found +then + DISABLE_ASDLGEN="@echo hg: $HAS_HG, python: $HAS_PYTHON! cannot run \$(srcdir)/Parser/asdl_c.py #" +fi + + case $MACHDEP in bsdos*|hp*|HP*) # install -d does not work on BSDI or HP-UX diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -832,7 +832,13 @@ AC_SUBST(HGVERSION) AC_SUBST(HGTAG) AC_SUBST(HGBRANCH) + +if test -e $srcdir/.hg/00changelog.i +then AC_CHECK_PROG(HAS_HG, hg, found, not-found) +else +HAS_HG=no-repository +fi if test $HAS_HG = found then HGVERSION="hg id -i \$(srcdir)" @@ -844,6 +850,15 @@ HGBRANCH="" fi +AC_SUBST(DISABLE_ASDLGEN) +DISABLE_ASDLGEN="" +AC_CHECK_PROG(HAS_PYTHON, python, found, not-found) +if test $HAS_HG != found -o $HAS_PYTHON != found +then + DISABLE_ASDLGEN="@echo hg: $HAS_HG, python: $HAS_PYTHON! cannot run \$(srcdir)/Parser/asdl_c.py #" +fi + + case $MACHDEP in bsdos*|hp*|HP*) # install -d does not work on BSDI or HP-UX -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 20:44:36 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 20:44:36 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/65e57bead934 changeset: 71153:65e57bead934 parent: 71150:6c955e38daa5 parent: 71148:a085e755c892 user: Benjamin Peterson date: Sun Jul 03 13:45:33 2011 -0500 summary: merge heads files: Doc/library/smtplib.rst | 27 +- Doc/library/sqlite3.rst | 75 +- Doc/whatsnew/3.3.rst | 2 +- Lib/concurrent/futures/process.py | 42 +- Lib/importlib/test/source/test_file_loader.py | 2 +- Lib/smtplib.py | 52 +- Lib/test/test_concurrent_futures.py | 7 + Lib/test/test_csv.py | 8 +- Lib/test/test_marshal.py | 24 + Lib/test/test_shutil.py | 10 +- Lib/test/test_smtplib.py | 111 +++++- Misc/ACKS | 1 + Misc/NEWS | 6 + Python/marshal.c | 211 +++++++-- Tools/msi/msi.py | 7 +- 15 files changed, 440 insertions(+), 145 deletions(-) diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -348,21 +348,32 @@ .. versionchanged:: 3.2 *msg* may be a byte string. -.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=[], rcpt_options=[]) +.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, \ + mail_options=[], rcpt_options=[]) This is a convenience method for calling :meth:`sendmail` with the message represented by an :class:`email.message.Message` object. The arguments have the same meaning as for :meth:`sendmail`, except that *msg* is a ``Message`` object. - If *from_addr* is ``None``, ``send_message`` sets its value to the value of - the :mailheader:`From` header from *msg*. If *to_addrs* is ``None``, - ``send_message`` combines the values (if any) of the :mailheader:`To`, - :mailheader:`CC`, and :mailheader:`Bcc` fields from *msg*. Regardless of - the values of *from_addr* and *to_addrs*, ``send_message`` deletes any Bcc - field from *msg*. It then serializes *msg* using + If *from_addr* is ``None`` or *to_addrs* is ``None``, ``send_message`` fills + those arguments with addresses extracted from the headers of *msg* as + specified in :rfc:`2822`\: *from_addr* is set to the :mailheader:`Sender` + field if it is present, and otherwise to the :mailheader:`From` field. + *to_adresses* combines the values (if any) of the :mailheader:`To`, + :mailheader:`Cc`, and :mailheader:`Bcc` fields from *msg*. If exactly one + set of :mailheader:`Resent-*` headers appear in the message, the regular + headers are ignored and the :mailheader:`Resent-*` headers are used instead. + If the message contains more than one set of :mailheader:`Resent-*` headers, + a :exc:`ValueError` is raised, since there is no way to unambiguously detect + the most recent set of :mailheader:`Resent-` headers. + + ``send_message`` serializes *msg* using :class:`~email.generator.BytesGenerator` with ``\r\n`` as the *linesep*, and - calls :meth:`sendmail` to transmit the resulting message. + calls :meth:`sendmail` to transmit the resulting message. Regardless of the + values of *from_addr* and *to_addrs*, ``send_message`` does not transmit any + :mailheader:`Bcc` or :mailheader:`Resent-Bcc` headers that may appear + in *msg*. .. versionadded:: 3.2 diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -615,43 +615,43 @@ Let's assume we initialize a table as in the example given above:: - conn = sqlite3.connect(":memory:") - c = conn.cursor() - c.execute('''create table stocks - (date text, trans text, symbol text, - qty real, price real)''') - c.execute("""insert into stocks - values ('2006-01-05','BUY','RHAT',100,35.14)""") - conn.commit() - c.close() + conn = sqlite3.connect(":memory:") + c = conn.cursor() + c.execute('''create table stocks + (date text, trans text, symbol text, + qty real, price real)''') + c.execute("""insert into stocks + values ('2006-01-05','BUY','RHAT',100,35.14)""") + conn.commit() + c.close() Now we plug :class:`Row` in:: - >>> conn.row_factory = sqlite3.Row - >>> c = conn.cursor() - >>> c.execute('select * from stocks') - - >>> r = c.fetchone() - >>> type(r) - - >>> tuple(r) - ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14) - >>> len(r) - 5 - >>> r[2] - 'RHAT' - >>> r.keys() - ['date', 'trans', 'symbol', 'qty', 'price'] - >>> r['qty'] - 100.0 - >>> for member in r: - ... print(member) - ... - 2006-01-05 - BUY - RHAT - 100.0 - 35.14 + >>> conn.row_factory = sqlite3.Row + >>> c = conn.cursor() + >>> c.execute('select * from stocks') + + >>> r = c.fetchone() + >>> type(r) + + >>> tuple(r) + ('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14) + >>> len(r) + 5 + >>> r[2] + 'RHAT' + >>> r.keys() + ['date', 'trans', 'symbol', 'qty', 'price'] + >>> r['qty'] + 100.0 + >>> for member in r: + ... print(member) + ... + 2006-01-05 + BUY + RHAT + 100.0 + 35.14 .. _sqlite3-types: @@ -902,6 +902,7 @@ .. rubric:: Footnotes .. [#f1] The sqlite3 module is not built with loadable extension support by - default, because some platforms (notably Mac OS X) have SQLite libraries which - are compiled without this feature. To get loadable extension support, you must - pass --enable-loadable-sqlite-extensions to configure. + default, because some platforms (notably Mac OS X) have SQLite + libraries which are compiled without this feature. To get loadable + extension support, you must pass --enable-loadable-sqlite-extensions to + configure. 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 @@ -206,7 +206,7 @@ shutil ------ -The :mod:`shutil` module has a new :func:`~shutil.disk_usage` providing total, +The :mod:`shutil` module has a new :func:`~shutil.disk_usage` function providing total, used and free disk space statistics. (Contributed by Giampaolo Rodol? in :issue:`12442`) 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 @@ -50,7 +50,7 @@ from concurrent.futures import _base import queue import multiprocessing -from multiprocessing.queues import SimpleQueue, SentinelReady +from multiprocessing.queues import SimpleQueue, SentinelReady, Full import threading import weakref @@ -195,15 +195,18 @@ result_queue: A multiprocessing.Queue of _ResultItems generated by the process workers. """ + executor = None + + def shutting_down(): + return _shutdown or executor is None or executor._shutdown_thread def shutdown_worker(): # This is an upper bound nb_children_alive = sum(p.is_alive() for p in processes.values()) for i in range(0, nb_children_alive): - call_queue.put(None) + call_queue.put_nowait(None) # If .join() is not called on the created processes then - # some multiprocessing.Queue methods may deadlock on Mac OS - # X. + # some multiprocessing.Queue methods may deadlock on Mac OS X. for p in processes.values(): p.join() @@ -222,7 +225,7 @@ if executor is not None: executor._broken = True executor._shutdown_thread = True - del executor + executor = None # All futures in flight must be marked failed for work_id, work_item in pending_work_items.items(): work_item.future.set_exception( @@ -242,7 +245,11 @@ if isinstance(result_item, int): # Clean shutdown of a worker using its PID # (avoids marking the executor broken) + assert shutting_down() del processes[result_item] + if not processes: + shutdown_worker() + return elif result_item is not None: work_item = pending_work_items.pop(result_item.work_id, None) # work_item can be None if another process terminated (see above) @@ -257,16 +264,21 @@ # - The interpreter is shutting down OR # - The executor that owns this worker has been collected OR # - The executor that owns this worker has been shutdown. - if _shutdown or executor is None or executor._shutdown_thread: - # Since no new work items can be added, it is safe to shutdown - # this thread if there are no pending work items. - if not pending_work_items: - shutdown_worker() - return - else: - # Start shutting down by telling a process it can exit. - call_queue.put(None) - del executor + if shutting_down(): + try: + # Since no new work items can be added, it is safe to shutdown + # this thread if there are no pending work items. + if not pending_work_items: + shutdown_worker() + return + else: + # Start shutting down by telling a process it can exit. + call_queue.put_nowait(None) + except Full: + # This is not a problem: we will eventually be woken up (in + # result_queue.get()) and be able to send a sentinel again. + pass + executor = None _system_limits_checked = False _system_limited = None diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py --- a/Lib/importlib/test/source/test_file_loader.py +++ b/Lib/importlib/test/source/test_file_loader.py @@ -214,7 +214,7 @@ lambda bc: bc[:8] + b'', del_source=del_source) file_path = mapping['_temp'] if not del_source else bytecode_path - with self.assertRaises(ValueError): + with self.assertRaises(EOFError): self.import_(file_path, '_temp') def _test_bad_magic(self, test, *, del_source=False): diff --git a/Lib/smtplib.py b/Lib/smtplib.py old mode 100755 new mode 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -49,6 +49,7 @@ import email.generator import base64 import hmac +import copy from email.base64mime import body_encode as encode_base64 from sys import stderr @@ -676,7 +677,7 @@ msg may be a string containing characters in the ASCII range, or a byte string. A string is encoded to bytes using the ascii codec, and lone - \r and \n characters are converted to \r\n characters. + \\r and \\n characters are converted to \\r\\n characters. If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first. If the server does ESMTP, message size @@ -759,24 +760,49 @@ """Converts message to a bytestring and passes it to sendmail. The arguments are as for sendmail, except that msg is an - email.message.Message object. If from_addr is None, the from_addr is - taken from the 'From' header of the Message. If to_addrs is None, its - value is composed from the addresses listed in the 'To', 'CC', and - 'Bcc' fields. Regardless of the values of from_addr and to_addr, any - Bcc field in the Message object is deleted. The Message object is then - serialized using email.generator.BytesGenerator and sendmail is called - to transmit the message. + email.message.Message object. If from_addr is None or to_addrs is + None, these arguments are taken from the headers of the Message as + described in RFC 2822 (a ValueError is raised if there is more than + one set of 'Resent-' headers). Regardless of the values of from_addr and + to_addr, any Bcc field (or Resent-Bcc field, when the Message is a + resent) of the Message object won't be transmitted. The Message + object is then serialized using email.generator.BytesGenerator and + sendmail is called to transmit the message. + """ + # 'Resent-Date' is a mandatory field if the Message is resent (RFC 2822 + # Section 3.6.6). In such a case, we use the 'Resent-*' fields. However, + # if there is more than one 'Resent-' block there's no way to + # unambiguously determine which one is the most recent in all cases, + # so rather than guess we raise a ValueError in that case. + # + # TODO implement heuristics to guess the correct Resent-* block with an + # option allowing the user to enable the heuristics. (It should be + # possible to guess correctly almost all of the time.) + resent =msg.get_all('Resent-Date') + if resent is None: + header_prefix = '' + elif len(resent) == 1: + header_prefix = 'Resent-' + else: + raise ValueError("message has more than one 'Resent-' header block") if from_addr is None: - from_addr = msg['From'] + # Prefer the sender field per RFC 2822:3.6.2. + from_addr = (msg[header_prefix+'Sender'] + if (header_prefix+'Sender') in msg + else msg[header_prefix+'From']) if to_addrs is None: - addr_fields = [f for f in (msg['To'], msg['Bcc'], msg['CC']) - if f is not None] + addr_fields = [f for f in (msg[header_prefix+'To'], + msg[header_prefix+'Bcc'], + msg[header_prefix+'Cc']) if f is not None] to_addrs = [a[1] for a in email.utils.getaddresses(addr_fields)] - del msg['Bcc'] + # Make a local copy so we can delete the bcc headers. + msg_copy = copy.copy(msg) + del msg_copy['Bcc'] + del msg_copy['Resent-Bcc'] with io.BytesIO() as bytesmsg: g = email.generator.BytesGenerator(bytesmsg) - g.flatten(msg, linesep='\r\n') + g.flatten(msg_copy, linesep='\r\n') flatmsg = bytesmsg.getvalue() return self.sendmail(from_addr, to_addrs, flatmsg, mail_options, rcpt_options) diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -367,6 +367,13 @@ self.assertEqual([None, None], results) + def test_shutdown_race_issue12456(self): + # Issue #12456: race condition at shutdown where trying to post a + # sentinel in the call queue blocks (the queue is full while processes + # have exited). + self.executor.map(str, [2] * (self.worker_count + 1)) + self.executor.shutdown() + class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest): def test_map_submits_without_iteration(self): diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -459,20 +459,20 @@ '5', '6']]) def test_quoted_quote(self): - self.readerAssertEqual('1,2,3,"""I see,"" said the blind man","as he picked up his hammer and saw"', + self.readerAssertEqual('1,2,3,"""I see,"" said the happy man","as he picked up his hammer and saw"', [['1', '2', '3', - '"I see," said the blind man', + '"I see," said the happy man', 'as he picked up his hammer and saw']]) def test_quoted_nl(self): input = '''\ 1,2,3,"""I see,"" -said the blind man","as he picked up his +said the happy man","as he picked up his hammer and saw" 9,8,7,6''' self.readerAssertEqual(input, [['1', '2', '3', - '"I see,"\nsaid the blind man', + '"I see,"\nsaid the happy man', 'as he picked up his\nhammer and saw'], ['9','8','7','6']]) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -228,6 +228,30 @@ invalid_string = b'l\x02\x00\x00\x00\x00\x00\x00\x00' self.assertRaises(ValueError, marshal.loads, invalid_string) + def test_multiple_dumps_and_loads(self): + # Issue 12291: marshal.load() should be callable multiple times + # with interleaved data written by non-marshal code + # Adapted from a patch by Engelbert Gruber. + data = (1, 'abc', b'def', 1.0, (2, 'a', ['b', b'c'])) + for interleaved in (b'', b'0123'): + ilen = len(interleaved) + positions = [] + try: + with open(support.TESTFN, 'wb') as f: + for d in data: + marshal.dump(d, f) + if ilen: + f.write(interleaved) + positions.append(f.tell()) + with open(support.TESTFN, 'rb') as f: + for i, d in enumerate(data): + self.assertEqual(d, marshal.load(f)) + if ilen: + f.read(ilen) + self.assertEqual(positions[i], f.tell()) + finally: + support.unlink(support.TESTFN) + def test_main(): support.run_unittest(IntTestCase, 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 @@ -732,11 +732,11 @@ "disk_usage not available on this platform") def test_disk_usage(self): usage = shutil.disk_usage(os.getcwd()) - self.assertTrue(usage.total > 0) - self.assertTrue(usage.used > 0) - self.assertTrue(usage.free >= 0) - self.assertTrue(usage.total >= usage.used) - self.assertTrue(usage.total > usage.free) + self.assertGreater(usage.total, 0) + self.assertGreater(usage.used, 0) + self.assertGreaterEqual(usage.free, 0) + self.assertGreaterEqual(usage.total, usage.used) + self.assertGreater(usage.total, usage.free) class TestMove(unittest.TestCase): 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 @@ -320,13 +320,16 @@ # XXX (see comment in testSend) time.sleep(0.01) smtp.quit() + # make sure the Bcc header is still in the message. + self.assertEqual(m['Bcc'], 'John Root , "Dinsdale" ' + '') self.client_evt.set() self.serv_evt.wait() self.output.flush() # Add the X-Peer header that DebuggingServer adds m['X-Peer'] = socket.gethostbyname('localhost') - # The Bcc header is deleted before serialization. + # The Bcc header should not be transmitted. del m['Bcc'] mexpect = '%s%s\n%s' % (MSG_BEGIN, m.as_string(), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) @@ -365,6 +368,112 @@ re.MULTILINE) self.assertRegex(debugout, to_addr) + def testSendMessageWithSpecifiedAddresses(self): + # Make sure addresses specified in call override those in message. + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John, Dinsdale' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m, from_addr='joe at example.com', to_addrs='foo at example.net') + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: joe at example.com$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('John', 'Dinsdale'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertNotRegex(debugout, to_addr) + recip = re.compile(r"^recips: .*'foo at example.net'.*$", re.MULTILINE) + self.assertRegex(debugout, recip) + + def testSendMessageWithMultipleFrom(self): + # Sender overrides To + m = email.mime.text.MIMEText('A test message') + m['From'] = 'Bernard, Bianca' + m['Sender'] = 'the_rescuers at Rescue-Aid-Society.com' + m['To'] = 'John, Dinsdale' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: the_rescuers at Rescue-Aid-Society.com$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('John', 'Dinsdale'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertRegex(debugout, to_addr) + + def testSendMessageResent(self): + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John' + m['CC'] = 'Sally, Fred' + m['Bcc'] = 'John Root , "Dinsdale" ' + m['Resent-Date'] = 'Thu, 1 Jan 1970 17:42:00 +0000' + m['Resent-From'] = 'holy at grail.net' + m['Resent-To'] = 'Martha , Jeff' + m['Resent-Bcc'] = 'doe at losthope.net' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.send_message(m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + # The Resent-Bcc headers are deleted before serialization. + del m['Bcc'] + del m['Resent-Bcc'] + # Add the X-Peer header that DebuggingServer adds + 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() + sender = re.compile("^sender: holy at grail.net$", re.MULTILINE) + self.assertRegex(debugout, sender) + for addr in ('my_mom at great.cooker.com', 'Jeff', 'doe at losthope.net'): + to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), + re.MULTILINE) + self.assertRegex(debugout, to_addr) + + def testSendMessageMultipleResentRaises(self): + m = email.mime.text.MIMEText('A test message') + m['From'] = 'foo at bar.com' + m['To'] = 'John' + m['CC'] = 'Sally, Fred' + m['Bcc'] = 'John Root , "Dinsdale" ' + m['Resent-Date'] = 'Thu, 1 Jan 1970 17:42:00 +0000' + m['Resent-From'] = 'holy at grail.net' + m['Resent-To'] = 'Martha , Jeff' + m['Resent-Bcc'] = 'doe at losthope.net' + m['Resent-Date'] = 'Thu, 2 Jan 1970 17:42:00 +0000' + m['Resent-To'] = 'holy at grail.net' + m['Resent-From'] = 'Martha , Jeff' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + with self.assertRaises(ValueError): + smtp.send_message(m) + smtp.close() class NonConnectingTests(unittest.TestCase): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -278,6 +278,7 @@ Andy Eskilsson Andr? Espaze Stefan Esser +Nicolas Estibals Stephen D Evans Carey Evans Tim Everett diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12291: You can now load multiple marshalled objects from a stream, + with other data interleaved between marshalled objects. + - Issue #12356: When required positional or keyword-only arguments are not given, produce a informative error message which includes the name(s) of the missing arguments. @@ -200,6 +203,9 @@ Library ------- +- Issue #12147: Adjust the new-in-3.2 smtplib.send_message method for better + conformance to the RFCs: correctly handle Sender and Resent- headers. + - Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -57,6 +57,7 @@ int error; /* see WFERR_* values */ int depth; /* If fp == NULL, the following are valid: */ + PyObject * readable; /* Stream-like object being read from */ PyObject *str; PyObject *current_filename; char *ptr; @@ -463,27 +464,75 @@ #define rs_byte(p) (((p)->ptr < (p)->end) ? (unsigned char)*(p)->ptr++ : EOF) -#define r_byte(p) ((p)->fp ? getc((p)->fp) : rs_byte(p)) - static int r_string(char *s, int n, RFILE *p) { - if (p->fp != NULL) - /* The result fits into int because it must be <=n. */ - return (int)fread(s, 1, n, p->fp); - if (p->end - p->ptr < n) - n = (int)(p->end - p->ptr); - memcpy(s, p->ptr, n); - p->ptr += n; - return n; + char * ptr; + int read, left; + + if (!p->readable) { + if (p->fp != NULL) + /* The result fits into int because it must be <=n. */ + read = (int) fread(s, 1, n, p->fp); + else { + left = (int)(p->end - p->ptr); + read = (left < n) ? left : n; + memcpy(s, p->ptr, read); + p->ptr += read; + } + } + else { + PyObject *data = PyObject_CallMethod(p->readable, "read", "i", n); + read = 0; + if (data != NULL) { + if (!PyBytes_Check(data)) { + PyErr_Format(PyExc_TypeError, + "f.read() returned not bytes but %.100s", + data->ob_type->tp_name); + } + else { + read = PyBytes_GET_SIZE(data); + if (read > 0) { + ptr = PyBytes_AS_STRING(data); + memcpy(s, ptr, read); + } + } + Py_DECREF(data); + } + } + if (!PyErr_Occurred() && (read < n)) { + PyErr_SetString(PyExc_EOFError, "EOF read where not expected"); + } + return read; +} + + +static int +r_byte(RFILE *p) +{ + int c = EOF; + unsigned char ch; + int n; + + if (!p->readable) + c = p->fp ? getc(p->fp) : rs_byte(p); + else { + n = r_string((char *) &ch, 1, p); + if (n > 0) + c = ch; + } + return c; } static int r_short(RFILE *p) { register short x; - x = r_byte(p); - x |= r_byte(p) << 8; + unsigned char buffer[2]; + + r_string((char *) buffer, 2, p); + x = buffer[0]; + x |= buffer[1] << 8; /* Sign-extension, in case short greater than 16 bits */ x |= -(x & 0x8000); return x; @@ -493,19 +542,13 @@ r_long(RFILE *p) { register long x; - register FILE *fp = p->fp; - if (fp) { - x = getc(fp); - x |= (long)getc(fp) << 8; - x |= (long)getc(fp) << 16; - x |= (long)getc(fp) << 24; - } - else { - x = rs_byte(p); - x |= (long)rs_byte(p) << 8; - x |= (long)rs_byte(p) << 16; - x |= (long)rs_byte(p) << 24; - } + unsigned char buffer[4]; + + r_string((char *) buffer, 4, p); + x = buffer[0]; + x |= (long)buffer[1] << 8; + x |= (long)buffer[2] << 16; + x |= (long)buffer[3] << 24; #if SIZEOF_LONG > 4 /* Sign extension for 64-bit machines */ x |= -(x & 0x80000000L); @@ -523,25 +566,30 @@ static PyObject * r_long64(RFILE *p) { + PyObject * result = NULL; long lo4 = r_long(p); long hi4 = r_long(p); + + if (!PyErr_Occurred()) { #if SIZEOF_LONG > 4 - long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); - return PyLong_FromLong(x); + long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); + result = PyLong_FromLong(x); #else - unsigned char buf[8]; - int one = 1; - int is_little_endian = (int)*(char*)&one; - if (is_little_endian) { - memcpy(buf, &lo4, 4); - memcpy(buf+4, &hi4, 4); + unsigned char buf[8]; + int one = 1; + int is_little_endian = (int)*(char*)&one; + if (is_little_endian) { + memcpy(buf, &lo4, 4); + memcpy(buf+4, &hi4, 4); + } + else { + memcpy(buf, &hi4, 4); + memcpy(buf+4, &lo4, 4); + } + result = _PyLong_FromByteArray(buf, 8, is_little_endian, 1); +#endif } - else { - memcpy(buf, &hi4, 4); - memcpy(buf+4, &lo4, 4); - } - return _PyLong_FromByteArray(buf, 8, is_little_endian, 1); -#endif + return result; } static PyObject * @@ -553,6 +601,8 @@ digit d; n = r_long(p); + if (PyErr_Occurred()) + return NULL; if (n == 0) return (PyObject *)_PyLong_New(0); if (n < -INT_MAX || n > INT_MAX) { @@ -572,6 +622,8 @@ d = 0; for (j=0; j < PyLong_MARSHAL_RATIO; j++) { md = r_short(p); + if (PyErr_Occurred()) + break; if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; d += (digit)md << j*PyLong_MARSHAL_SHIFT; @@ -581,6 +633,8 @@ d = 0; for (j=0; j < shorts_in_top_digit; j++) { md = r_short(p); + if (PyErr_Occurred()) + break; if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; /* topmost marshal digit should be nonzero */ @@ -592,6 +646,10 @@ } d += (digit)md << j*PyLong_MARSHAL_SHIFT; } + if (PyErr_Occurred()) { + Py_DECREF(ob); + return NULL; + } /* top digit should be nonzero, else the resulting PyLong won't be normalized */ ob->ob_digit[size-1] = d; @@ -660,7 +718,8 @@ break; case TYPE_INT: - retval = PyLong_FromLong(r_long(p)); + n = r_long(p); + retval = PyErr_Occurred() ? NULL : PyLong_FromLong(n); break; case TYPE_INT64: @@ -770,6 +829,10 @@ case TYPE_STRING: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); retval = NULL; @@ -795,6 +858,10 @@ char *buffer; n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (unicode size out of range)"); retval = NULL; @@ -820,6 +887,10 @@ case TYPE_TUPLE: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (tuple size out of range)"); retval = NULL; @@ -847,6 +918,10 @@ case TYPE_LIST: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (list size out of range)"); retval = NULL; @@ -899,6 +974,10 @@ case TYPE_SET: case TYPE_FROZENSET: n = r_long(p); + if (PyErr_Occurred()) { + retval = NULL; + break; + } if (n < 0 || n > INT_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (set size out of range)"); retval = NULL; @@ -952,10 +1031,20 @@ /* XXX ignore long->int overflows for now */ argcount = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; kwonlyargcount = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; nlocals = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; stacksize = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; flags = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; code = r_object(p); if (code == NULL) goto code_error; @@ -1049,6 +1138,7 @@ { RFILE rf; assert(fp); + rf.readable = NULL; rf.fp = fp; rf.current_filename = NULL; rf.end = rf.ptr = NULL; @@ -1060,6 +1150,7 @@ { RFILE rf; rf.fp = fp; + rf.readable = NULL; rf.current_filename = NULL; rf.ptr = rf.end = NULL; return r_long(&rf); @@ -1121,6 +1212,7 @@ RFILE rf; PyObject *result; rf.fp = fp; + rf.readable = NULL; rf.current_filename = NULL; rf.depth = 0; rf.ptr = rf.end = NULL; @@ -1134,6 +1226,7 @@ RFILE rf; PyObject *result; rf.fp = NULL; + rf.readable = NULL; rf.current_filename = NULL; rf.ptr = str; rf.end = str + len; @@ -1149,6 +1242,7 @@ PyObject *res = NULL; wf.fp = NULL; + wf.readable = NULL; wf.str = PyBytes_FromStringAndSize((char *)NULL, 50); if (wf.str == NULL) return NULL; @@ -1224,32 +1318,30 @@ static PyObject * marshal_load(PyObject *self, PyObject *f) { - /* XXX Quick hack -- need to do this differently */ PyObject *data, *result; RFILE rf; - data = PyObject_CallMethod(f, "read", ""); + + /* + * Make a call to the read method, but read zero bytes. + * This is to ensure that the object passed in at least + * has a read method which returns bytes. + */ + data = PyObject_CallMethod(f, "read", "i", 0); if (data == NULL) return NULL; - rf.fp = NULL; - rf.current_filename = NULL; - if (PyBytes_Check(data)) { - rf.ptr = PyBytes_AS_STRING(data); - rf.end = rf.ptr + PyBytes_GET_SIZE(data); - } - else if (PyBytes_Check(data)) { - rf.ptr = PyBytes_AS_STRING(data); - rf.end = rf.ptr + PyBytes_GET_SIZE(data); + if (!PyBytes_Check(data)) { + PyErr_Format(PyExc_TypeError, + "f.read() returned not bytes but %.100s", + data->ob_type->tp_name); + result = NULL; } else { - PyErr_Format(PyExc_TypeError, - "f.read() returned neither string " - "nor bytes but %.100s", - data->ob_type->tp_name); - Py_DECREF(data); - return NULL; + rf.depth = 0; + rf.fp = NULL; + rf.readable = f; + rf.current_filename = NULL; + result = read_object(&rf); } - rf.depth = 0; - result = read_object(&rf); Py_DECREF(data); return result; } @@ -1300,6 +1392,7 @@ s = p.buf; n = p.len; rf.fp = NULL; + rf.readable = NULL; rf.current_filename = NULL; rf.ptr = s; rf.end = s + n; diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -119,6 +119,7 @@ "30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}", "31":"{4afcba0b-13e4-47c3-bebe-477428b46913}", "32":"{3ff95315-1096-4d31-bd86-601d5438ad5e}", + "33":"{f7581ca4-d368-4eea-8f82-d48c64c4f047}", } [major+minor] # Compute the name that Sphinx gives to the docfile @@ -1010,6 +1011,8 @@ lib.remove_pyc() # package READMEs if present lib.glob("README") + if dir=='Lib': + lib.add_file("sysconfig.cfg") if dir=='test' and parent.physical=='Lib': lib.add_file("185test.db") lib.add_file("audiotest.au") @@ -1045,7 +1048,7 @@ if dir=="Icons": lib.glob("*.gif") lib.add_file("idle.icns") - if dir=="command" and parent.physical=="distutils": + if dir=="command" and parent.physical in ("distutils", "packaging"): lib.glob("wininst*.exe") lib.add_file("command_template") if dir=="lib2to3": @@ -1156,6 +1159,8 @@ lib.add_file("README.txt", src="README") if f == 'Scripts': lib.add_file("2to3.py", src="2to3") + lib.add_file("pydoc3.py", src="pydoc3") + lib.add_file("pysetup3.py", src="pysetup3") if have_tcl: lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw") lib.add_file("pydocgui.pyw") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 20:44:36 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 20:44:36 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiBtZXJnZSAzLjIgKCMxMjQ3NSk=?= Message-ID: http://hg.python.org/cpython/rev/33dca840938d changeset: 71154:33dca840938d parent: 71153:65e57bead934 parent: 71152:36bc49565281 user: Benjamin Peterson date: Sun Jul 03 13:48:36 2011 -0500 summary: merge 3.2 (#12475) files: Lib/test/test_exceptions.py | 15 +++++++++++++++ Misc/NEWS | 3 +++ Python/ceval.c | 9 +++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -567,6 +567,21 @@ del g self.assertEqual(sys.exc_info()[0], TypeError) + def test_generator_leaking2(self): + # See issue 12475. + def g(): + yield + try: + raise RuntimeError + except RuntimeError: + it = g() + next(it) + try: + next(it) + except StopIteration: + pass + self.assertEqual(sys.exc_info(), (None, None, None)) + def test_generator_finalizing_and_exc_info(self): # See #7173 def simple_gen(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12475: Prevent generators from leaking their exception state into the + callers frame as they return for the last time. + - Issue #12291: You can now load multiple marshalled objects from a stream, with other data interleaved between marshalled objects. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1865,10 +1865,6 @@ retval = POP(); f->f_stacktop = stack_pointer; why = WHY_YIELD; - /* Put aside the current exception state and restore - that of the calling frame. This only serves when - "yield" is used inside an except handler. */ - SWAP_EXC_STATE(); goto fast_yield; TARGET(POP_EXCEPT) @@ -3005,6 +3001,11 @@ retval = NULL; fast_yield: + if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) + /* Put aside the current exception state and restore that of the + calling frame. */ + SWAP_EXC_STATE(); + if (tstate->use_tracing) { if (tstate->c_tracefunc) { if (why == WHY_RETURN || why == WHY_YIELD) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 20:46:08 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 20:46:08 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogYWRkICc=?= Message-ID: http://hg.python.org/cpython/rev/733cb6f42217 changeset: 71155:733cb6f42217 branch: 3.2 parent: 71152:36bc49565281 user: Benjamin Peterson date: Sun Jul 03 13:49:59 2011 -0500 summary: add ' 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 @@ -11,7 +11,7 @@ ----------------- - Issue #12475: Prevent generators from leaking their exception state into the - callers frame as they return for the last time. + caller's frame as they return for the last time. Library ------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 20:46:09 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 20:46:09 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/ff74d3e238ea changeset: 71156:ff74d3e238ea parent: 71154:33dca840938d parent: 71155:733cb6f42217 user: Benjamin Peterson date: Sun Jul 03 13:50:16 2011 -0500 summary: merge 3.2 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 @@ -11,7 +11,7 @@ ----------------- - Issue #12475: Prevent generators from leaking their exception state into the - callers frame as they return for the last time. + caller's frame as they return for the last time. - Issue #12291: You can now load multiple marshalled objects from a stream, with other data interleaved between marshalled objects. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 23:23:34 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 23:23:34 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_never_retain_a_?= =?utf8?q?generator=27s_caller=27s_exception_state_on_the_generator_after_?= =?utf8?q?a?= Message-ID: http://hg.python.org/cpython/rev/419871c62bb3 changeset: 71157:419871c62bb3 branch: 3.2 parent: 71155:733cb6f42217 user: Benjamin Peterson date: Sun Jul 03 16:25:11 2011 -0500 summary: never retain a generator's caller's exception state on the generator after a yield/return This requires some trickery to properly save the exception state if the generator creates its own exception state. files: Lib/test/test_exceptions.py | 12 +++++++ Misc/NEWS | 3 + Python/ceval.c | 40 ++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -581,6 +581,18 @@ pass self.assertEqual(sys.exc_info(), (None, None, None)) + def test_generator_doesnt_retain_old_exc(self): + def g(): + self.assertIsInstance(sys.exc_info()[1], RuntimeError) + yield + self.assertEqual(sys.exc_info(), (None, None, None)) + it = g() + try: + raise RuntimeError + except RuntimeError: + next(it) + self.assertRaises(StopIteration, next, it) + def test_generator_finalizing_and_exc_info(self): # See #7173 def simple_gen(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- When a generator yields, do not retain the caller's exception state on the + generator. + - Issue #12475: Prevent generators from leaking their exception state into the caller's frame as they return for the last time. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1145,6 +1145,23 @@ f->f_exc_traceback = tmp; \ } +#define RESTORE_AND_CLEAR_EXC_STATE() \ + { \ + PyObject *type, *value, *tb; \ + type = tstate->exc_type; \ + value = tstate->exc_value; \ + tb = tstate->exc_traceback; \ + tstate->exc_type = f->f_exc_type; \ + tstate->exc_value = f->f_exc_value; \ + tstate->exc_traceback = f->f_exc_traceback; \ + f->f_exc_type = NULL; \ + f->f_exc_value = NULL; \ + f->f_exc_traceback = NULL; \ + Py_XDECREF(type); \ + Py_XDECREF(value); \ + Py_XDECREF(tb); \ + } + /* Start of code */ if (f == NULL) @@ -3017,10 +3034,25 @@ retval = NULL; fast_yield: - if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) - /* Put aside the current exception state and restore that of the - calling frame. */ - SWAP_EXC_STATE(); + if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) { + /* The purpose of this block is to put aside the generator's exception + state and restore that of the calling frame. If the current + exception state is from the caller, we clear the exception values + on the generator frame, so they are not swapped back in latter. The + origin of the current exception state is determined by checking for + except handler blocks, which we must be in iff a new exception + state came into existence in this frame. (An uncaught exception + would have why == WHY_EXCEPTION, and we wouldn't be here). */ + int i; + for (i = 0; i < f->f_iblock; i++) + if (f->f_blockstack[i].b_type == EXCEPT_HANDLER) + break; + if (i == f->f_iblock) + /* We did not create this exception. */ + RESTORE_AND_CLEAR_EXC_STATE() + else + SWAP_EXC_STATE() + } if (tstate->use_tracing) { if (tstate->c_tracefunc) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 3 23:23:35 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 03 Jul 2011 23:23:35 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/2613b8d32149 changeset: 71158:2613b8d32149 parent: 71156:ff74d3e238ea parent: 71157:419871c62bb3 user: Benjamin Peterson date: Sun Jul 03 16:27:41 2011 -0500 summary: merge 3.2 files: Lib/test/test_exceptions.py | 12 +++++++ Misc/NEWS | 3 + Python/ceval.c | 40 ++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -582,6 +582,18 @@ pass self.assertEqual(sys.exc_info(), (None, None, None)) + def test_generator_doesnt_retain_old_exc(self): + def g(): + self.assertIsInstance(sys.exc_info()[1], RuntimeError) + yield + self.assertEqual(sys.exc_info(), (None, None, None)) + it = g() + try: + raise RuntimeError + except RuntimeError: + next(it) + self.assertRaises(StopIteration, next, it) + def test_generator_finalizing_and_exc_info(self): # See #7173 def simple_gen(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- When a generator yields, do not retain the caller's exception state on the + generator. + - Issue #12475: Prevent generators from leaking their exception state into the caller's frame as they return for the last time. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1141,6 +1141,23 @@ f->f_exc_traceback = tmp; \ } +#define RESTORE_AND_CLEAR_EXC_STATE() \ + { \ + PyObject *type, *value, *tb; \ + type = tstate->exc_type; \ + value = tstate->exc_value; \ + tb = tstate->exc_traceback; \ + tstate->exc_type = f->f_exc_type; \ + tstate->exc_value = f->f_exc_value; \ + tstate->exc_traceback = f->f_exc_traceback; \ + f->f_exc_type = NULL; \ + f->f_exc_value = NULL; \ + f->f_exc_traceback = NULL; \ + Py_XDECREF(type); \ + Py_XDECREF(value); \ + Py_XDECREF(tb); \ + } + /* Start of code */ if (f == NULL) @@ -3001,10 +3018,25 @@ retval = NULL; fast_yield: - if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) - /* Put aside the current exception state and restore that of the - calling frame. */ - SWAP_EXC_STATE(); + if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) { + /* The purpose of this block is to put aside the generator's exception + state and restore that of the calling frame. If the current + exception state is from the caller, we clear the exception values + on the generator frame, so they are not swapped back in latter. The + origin of the current exception state is determined by checking for + except handler blocks, which we must be in iff a new exception + state came into existence in this frame. (An uncaught exception + would have why == WHY_EXCEPTION, and we wouldn't be here). */ + int i; + for (i = 0; i < f->f_iblock; i++) + if (f->f_blockstack[i].b_type == EXCEPT_HANDLER) + break; + if (i == f->f_iblock) + /* We did not create this exception. */ + RESTORE_AND_CLEAR_EXC_STATE() + else + SWAP_EXC_STATE() + } if (tstate->use_tracing) { if (tstate->c_tracefunc) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 00:02:33 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 04 Jul 2011 00:02:33 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_convert_generator_exc_state?= =?utf8?q?_functions_into_static_functions?= Message-ID: http://hg.python.org/cpython/rev/95784a617d05 changeset: 71159:95784a617d05 user: Benjamin Peterson date: Sun Jul 03 16:48:31 2011 -0500 summary: convert generator exc state functions into static functions files: Python/ceval.c | 116 +++++++++++++++++++----------------- 1 files changed, 62 insertions(+), 54 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -749,6 +749,9 @@ WHY_SILENCED = 0x0080 /* Exception silenced by 'with' */ }; +static void save_exc_state(PyThreadState *, PyFrameObject *); +static void swap_exc_state(PyThreadState *, PyFrameObject *); +static void restore_and_clear_exc_state(PyThreadState *, PyFrameObject *); static enum why_code do_raise(PyObject *, PyObject *); static int unpack_iterable(PyObject *, int, int, PyObject **); @@ -1110,54 +1113,6 @@ Py_XDECREF(traceback); \ } -#define SAVE_EXC_STATE() \ - { \ - PyObject *type, *value, *traceback; \ - Py_XINCREF(tstate->exc_type); \ - Py_XINCREF(tstate->exc_value); \ - Py_XINCREF(tstate->exc_traceback); \ - type = f->f_exc_type; \ - value = f->f_exc_value; \ - traceback = f->f_exc_traceback; \ - f->f_exc_type = tstate->exc_type; \ - f->f_exc_value = tstate->exc_value; \ - f->f_exc_traceback = tstate->exc_traceback; \ - Py_XDECREF(type); \ - Py_XDECREF(value); \ - Py_XDECREF(traceback); \ - } - -#define SWAP_EXC_STATE() \ - { \ - PyObject *tmp; \ - tmp = tstate->exc_type; \ - tstate->exc_type = f->f_exc_type; \ - f->f_exc_type = tmp; \ - tmp = tstate->exc_value; \ - tstate->exc_value = f->f_exc_value; \ - f->f_exc_value = tmp; \ - tmp = tstate->exc_traceback; \ - tstate->exc_traceback = f->f_exc_traceback; \ - f->f_exc_traceback = tmp; \ - } - -#define RESTORE_AND_CLEAR_EXC_STATE() \ - { \ - PyObject *type, *value, *tb; \ - type = tstate->exc_type; \ - value = tstate->exc_value; \ - tb = tstate->exc_traceback; \ - tstate->exc_type = f->f_exc_type; \ - tstate->exc_value = f->f_exc_value; \ - tstate->exc_traceback = f->f_exc_traceback; \ - f->f_exc_type = NULL; \ - f->f_exc_value = NULL; \ - f->f_exc_traceback = NULL; \ - Py_XDECREF(type); \ - Py_XDECREF(value); \ - Py_XDECREF(tb); \ - } - /* Start of code */ if (f == NULL) @@ -1236,11 +1191,10 @@ /* We were in an except handler when we left, restore the exception state which was put aside (see YIELD_VALUE). */ - SWAP_EXC_STATE(); + swap_exc_state(tstate, f); } - else { - SAVE_EXC_STATE(); - } + else + save_exc_state(tstate, f); } #ifdef LLTRACE @@ -3033,9 +2987,9 @@ break; if (i == f->f_iblock) /* We did not create this exception. */ - RESTORE_AND_CLEAR_EXC_STATE() + restore_and_clear_exc_state(tstate, f); else - SWAP_EXC_STATE() + swap_exc_state(tstate, f); } if (tstate->use_tracing) { @@ -3453,6 +3407,60 @@ } +/* These 3 functions deal with the exception state of generators. */ + +static void +save_exc_state(PyThreadState *tstate, PyFrameObject *f) +{ + PyObject *type, *value, *traceback; + Py_XINCREF(tstate->exc_type); + Py_XINCREF(tstate->exc_value); + Py_XINCREF(tstate->exc_traceback); + type = f->f_exc_type; + value = f->f_exc_value; + traceback = f->f_exc_traceback; + f->f_exc_type = tstate->exc_type; + f->f_exc_value = tstate->exc_value; + f->f_exc_traceback = tstate->exc_traceback; + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); +} + +static void +swap_exc_state(PyThreadState *tstate, PyFrameObject *f) +{ + PyObject *tmp; + tmp = tstate->exc_type; + tstate->exc_type = f->f_exc_type; + f->f_exc_type = tmp; + tmp = tstate->exc_value; + tstate->exc_value = f->f_exc_value; + f->f_exc_value = tmp; + tmp = tstate->exc_traceback; + tstate->exc_traceback = f->f_exc_traceback; + f->f_exc_traceback = tmp; +} + +static void +restore_and_clear_exc_state(PyThreadState *tstate, PyFrameObject *f) +{ + PyObject *type, *value, *tb; + type = tstate->exc_type; + value = tstate->exc_value; + tb = tstate->exc_traceback; + tstate->exc_type = f->f_exc_type; + tstate->exc_value = f->f_exc_value; + tstate->exc_traceback = f->f_exc_traceback; + f->f_exc_type = NULL; + f->f_exc_value = NULL; + f->f_exc_traceback = NULL; + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(tb); +} + + /* Logic for the raise statement (too complicated for inlining). This *consumes* a reference count to each of its arguments. */ static enum why_code -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 00:02:33 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 04 Jul 2011 00:02:33 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_no_one_passes_NULL_here_=28?= =?utf8?q?or_should_anyway=29?= Message-ID: http://hg.python.org/cpython/rev/bbbeddafeec0 changeset: 71160:bbbeddafeec0 user: Benjamin Peterson date: Sun Jul 03 17:06:32 2011 -0500 summary: no one passes NULL here (or should anyway) files: Python/ceval.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1115,9 +1115,6 @@ /* Start of code */ - if (f == NULL) - return NULL; - /* push frame */ if (Py_EnterRecursiveCall("")) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 00:19:15 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 04 Jul 2011 00:19:15 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_this_is_expressed_better_as?= =?utf8?q?_a_for_loop?= Message-ID: http://hg.python.org/cpython/rev/36df19f9e94b changeset: 71161:36df19f9e94b user: Benjamin Peterson date: Sun Jul 03 17:23:22 2011 -0500 summary: this is expressed better as a for loop files: Objects/genobject.c | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -395,15 +395,13 @@ int i; PyFrameObject *f = gen->gi_frame; - if (f == NULL || f->f_stacktop == NULL || f->f_iblock <= 0) + if (f == NULL || f->f_stacktop == NULL) return 0; /* no frame or empty blockstack == no finalization */ /* Any block type besides a loop requires cleanup. */ - i = f->f_iblock; - while (--i >= 0) { + for (i = 0; i < f->f_iblock; i++) if (f->f_blockstack[i].b_type != SETUP_LOOP) return 1; - } /* No blocks except loops, it's safe to skip finalization. */ return 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 01:29:12 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 01:29:12 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDUx?= =?utf8?q?=3A_xml=2Edom=2Epulldom=3A_parse=28=29_now_opens_files_in_binary?= =?utf8?q?_mode_instead?= Message-ID: http://hg.python.org/cpython/rev/81424281ee59 changeset: 71162:81424281ee59 branch: 3.2 parent: 71157:419871c62bb3 user: Victor Stinner date: Mon Jul 04 01:25:55 2011 +0200 summary: Issue #12451: xml.dom.pulldom: parse() now opens files in binary mode instead of the text mode (using the locale encoding) to avoid encoding issues. files: Lib/xml/dom/pulldom.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/xml/dom/pulldom.py b/Lib/xml/dom/pulldom.py --- a/Lib/xml/dom/pulldom.py +++ b/Lib/xml/dom/pulldom.py @@ -326,7 +326,7 @@ if bufsize is None: bufsize = default_bufsize if isinstance(stream_or_string, str): - stream = open(stream_or_string) + stream = open(stream_or_string, 'rb') else: stream = stream_or_string if not parser: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,9 @@ Library ------- +- Issue #12451: xml.dom.pulldom: parse() now opens files in binary mode instead + of the text mode (using the locale encoding) to avoid encoding issues. + C-API ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 01:29:13 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 01:29:13 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiAobWVyZ2UgMy4yKSBJc3N1ZSAjMTI0NTE6IHhtbC5kb20ucHVsbGRvbTogcGFy?= =?utf8?q?se=28=29_now_opens_files_in_binary?= Message-ID: http://hg.python.org/cpython/rev/c039c6b58907 changeset: 71163:c039c6b58907 parent: 71161:36df19f9e94b parent: 71162:81424281ee59 user: Victor Stinner date: Mon Jul 04 01:27:37 2011 +0200 summary: (merge 3.2) Issue #12451: xml.dom.pulldom: parse() now opens files in binary mode instead of the text mode (using the locale encoding) to avoid encoding issues. files: Lib/xml/dom/pulldom.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/xml/dom/pulldom.py b/Lib/xml/dom/pulldom.py --- a/Lib/xml/dom/pulldom.py +++ b/Lib/xml/dom/pulldom.py @@ -326,7 +326,7 @@ if bufsize is None: bufsize = default_bufsize if isinstance(stream_or_string, str): - stream = open(stream_or_string) + stream = open(stream_or_string, 'rb') else: stream = stream_or_string if not parser: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -209,6 +209,9 @@ Library ------- +- Issue #12451: xml.dom.pulldom: parse() now opens files in binary mode instead + of the text mode (using the locale encoding) to avoid encoding issues. + - Issue #12147: Adjust the new-in-3.2 smtplib.send_message method for better conformance to the RFCs: correctly handle Sender and Resent- headers. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 01:47:59 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 01:47:59 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDUx?= =?utf8?q?=3A_runpy=3A_run=5Fpath=28=29_now_opens_the_Python_script_in_bin?= =?utf8?q?ary_mode=2C?= Message-ID: http://hg.python.org/cpython/rev/cd1759711357 changeset: 71164:cd1759711357 branch: 3.2 parent: 71162:81424281ee59 user: Victor Stinner date: Mon Jul 04 01:45:39 2011 +0200 summary: Issue #12451: runpy: run_path() now opens the Python script in binary mode, instead of text mode using the locale encoding, to support other encodings than UTF-8 (scripts using the coding cookie). files: Lib/runpy.py | 2 +- Lib/test/test_runpy.py | 10 ++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 15 insertions(+), 1 deletions(-) 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, "rb") as f: code = compile(f.read(), fname, 'exec') return code diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -405,6 +405,16 @@ msg = "recursion depth exceeded" self.assertRaisesRegex(RuntimeError, msg, run_path, zip_name) + def test_encoding(self): + with temp_dir() as script_dir: + filename = os.path.join(script_dir, 'script.py') + with open(filename, 'w', encoding='latin1') as f: + f.write(""" +#coding:latin1 +"non-ASCII: h\xe9" +""") + result = run_path(filename) + self.assertEqual(result['__doc__'], "non-ASCII: h\xe9") def test_main(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,10 @@ Library ------- +- Issue #12451: runpy: run_path() now opens the Python script in binary mode, + instead of text mode using the locale encoding, to support other encodings + than UTF-8 (scripts using the coding cookie). + - Issue #12451: xml.dom.pulldom: parse() now opens files in binary mode instead of the text mode (using the locale encoding) to avoid encoding issues. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 01:47:59 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 01:47:59 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiAobWVyZ2UgMy4yKSBJc3N1ZSAjMTI0NTE6IHJ1bnB5OiBydW5fcGF0aCgpIG5v?= =?utf8?q?w_opens_the_Python_script_in?= Message-ID: http://hg.python.org/cpython/rev/e240af1f0ae1 changeset: 71165:e240af1f0ae1 parent: 71163:c039c6b58907 parent: 71164:cd1759711357 user: Victor Stinner date: Mon Jul 04 01:47:40 2011 +0200 summary: (merge 3.2) Issue #12451: runpy: run_path() now opens the Python script in binary mode, instead of text mode using the locale encoding, to support other encodings than UTF-8 (scripts using the coding cookie). files: Lib/runpy.py | 2 +- Lib/test/test_runpy.py | 10 ++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 15 insertions(+), 1 deletions(-) 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, "r") as f: + with open(fname, "rb") as f: code = compile(f.read(), fname, 'exec') return code diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -405,6 +405,16 @@ msg = "recursion depth exceeded" self.assertRaisesRegex(RuntimeError, msg, run_path, zip_name) + def test_encoding(self): + with temp_dir() as script_dir: + filename = os.path.join(script_dir, 'script.py') + with open(filename, 'w', encoding='latin1') as f: + f.write(""" +#coding:latin1 +"non-ASCII: h\xe9" +""") + result = run_path(filename) + self.assertEqual(result['__doc__'], "non-ASCII: h\xe9") def test_main(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -209,6 +209,10 @@ Library ------- +- Issue #12451: runpy: run_path() now opens the Python script in binary mode, + instead of text mode using the locale encoding, to support other encodings + than UTF-8 (scripts using the coding cookie). + - Issue #12451: xml.dom.pulldom: parse() now opens files in binary mode instead of the text mode (using the locale encoding) to avoid encoding issues. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 02:14:56 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 02:14:56 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDUx?= =?utf8?q?=3A_pydoc=3A_importfile=28=29_now_opens_the_Python_script_in_bin?= =?utf8?q?ary_mode=2C?= Message-ID: http://hg.python.org/cpython/rev/a1b4f1716b73 changeset: 71166:a1b4f1716b73 branch: 3.2 parent: 71164:cd1759711357 user: Victor Stinner date: Mon Jul 04 02:08:50 2011 +0200 summary: Issue #12451: pydoc: importfile() now opens the Python script in binary mode, instead of text mode using the locale encoding, to avoid encoding issues. files: Lib/pydoc.py | 26 ++++++++++++-------------- Misc/NEWS | 3 +++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -256,20 +256,18 @@ def importfile(path): """Import a Python source file or compiled file given its path.""" magic = imp.get_magic() - file = open(path, 'r') - if file.read(len(magic)) == magic: - kind = imp.PY_COMPILED - else: - kind = imp.PY_SOURCE - file.close() - filename = os.path.basename(path) - name, ext = os.path.splitext(filename) - file = open(path, 'r') - try: - module = imp.load_module(name, file, path, (ext, 'r', kind)) - except: - raise ErrorDuringImport(path, sys.exc_info()) - file.close() + with open(path, 'rb') as file: + if file.read(len(magic)) == magic: + kind = imp.PY_COMPILED + else: + kind = imp.PY_SOURCE + file.seek(0) + filename = os.path.basename(path) + name, ext = os.path.splitext(filename) + try: + module = imp.load_module(name, file, path, (ext, 'r', kind)) + except: + raise ErrorDuringImport(path, sys.exc_info()) return module def safeimport(path, forceload=0, cache={}): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,9 @@ Library ------- +- Issue #12451: pydoc: importfile() now opens the Python script in binary mode, + instead of text mode using the locale encoding, to avoid encoding issues. + - Issue #12451: runpy: run_path() now opens the Python script in binary mode, instead of text mode using the locale encoding, to support other encodings than UTF-8 (scripts using the coding cookie). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 02:14:56 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 02:14:56 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiAobWVyZ2UgMy4yKSBJc3N1ZSAjMTI0NTE6IHB5ZG9jOiBpbXBvcnRmaWxlKCkg?= =?utf8?q?now_opens_the_Python_script_in?= Message-ID: http://hg.python.org/cpython/rev/5ca136dccbf7 changeset: 71167:5ca136dccbf7 parent: 71165:e240af1f0ae1 parent: 71166:a1b4f1716b73 user: Victor Stinner date: Mon Jul 04 02:09:44 2011 +0200 summary: (merge 3.2) Issue #12451: pydoc: importfile() now opens the Python script in binary mode, instead of text mode using the locale encoding, to avoid encoding issues. files: Lib/pydoc.py | 26 ++++++++++++-------------- Misc/NEWS | 3 +++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -250,20 +250,18 @@ def importfile(path): """Import a Python source file or compiled file given its path.""" magic = imp.get_magic() - file = open(path, 'r') - if file.read(len(magic)) == magic: - kind = imp.PY_COMPILED - else: - kind = imp.PY_SOURCE - file.close() - filename = os.path.basename(path) - name, ext = os.path.splitext(filename) - file = open(path, 'r') - try: - module = imp.load_module(name, file, path, (ext, 'r', kind)) - except: - raise ErrorDuringImport(path, sys.exc_info()) - file.close() + with open(path, 'rb') as file: + if file.read(len(magic)) == magic: + kind = imp.PY_COMPILED + else: + kind = imp.PY_SOURCE + file.seek(0) + filename = os.path.basename(path) + name, ext = os.path.splitext(filename) + try: + module = imp.load_module(name, file, path, (ext, 'r', kind)) + except: + raise ErrorDuringImport(path, sys.exc_info()) return module def safeimport(path, forceload=0, cache={}): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -209,6 +209,9 @@ Library ------- +- Issue #12451: pydoc: importfile() now opens the Python script in binary mode, + instead of text mode using the locale encoding, to avoid encoding issues. + - Issue #12451: runpy: run_path() now opens the Python script in binary mode, instead of text mode using the locale encoding, to support other encodings than UTF-8 (scripts using the coding cookie). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 02:21:57 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 02:21:57 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_closes_issu?= =?utf8?q?e12432_-_remove_the_unused_sys_from_glob=2Epy?= Message-ID: http://hg.python.org/cpython/rev/6886e0bf29bc changeset: 71168:6886e0bf29bc branch: 3.2 parent: 71166:a1b4f1716b73 user: Senthil Kumaran date: Sun Jul 03 17:21:05 2011 -0700 summary: Fix closes issue12432 - remove the unused sys from glob.py files: Lib/glob.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/glob.py b/Lib/glob.py --- a/Lib/glob.py +++ b/Lib/glob.py @@ -1,6 +1,5 @@ """Filename globbing utility.""" -import sys import os import re import fnmatch -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 02:21:57 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 02:21:57 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_from_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/fbb1504a9275 changeset: 71169:fbb1504a9275 parent: 71167:5ca136dccbf7 parent: 71168:6886e0bf29bc user: Senthil Kumaran date: Sun Jul 03 17:21:44 2011 -0700 summary: merge from 3.2 files: Lib/glob.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/glob.py b/Lib/glob.py --- a/Lib/glob.py +++ b/Lib/glob.py @@ -1,6 +1,5 @@ """Filename globbing utility.""" -import sys import os import re import fnmatch -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 02:40:56 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 02:40:56 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_closes_issu?= =?utf8?q?e12438__-_idlelib=2EPyShell=27s_showformatwarning_method_was_pas?= =?utf8?q?sing?= Message-ID: http://hg.python.org/cpython/rev/c9f69b28c4d1 changeset: 71170:c9f69b28c4d1 branch: 2.7 parent: 71145:08400969067e user: Senthil Kumaran date: Sun Jul 03 17:38:53 2011 -0700 summary: Fix closes issue12438 - idlelib.PyShell's showformatwarning method was passing an incorrect arg. files: Lib/idlelib/PyShell.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -61,7 +61,7 @@ file = warning_stream try: file.write(warnings.formatwarning(message, category, filename, - lineno, file=file, line=line)) + lineno, line=line)) except IOError: pass ## file (probably __stderr__) is invalid, warning dropped. warnings.showwarning = idle_showwarning -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 02:40:56 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 02:40:56 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_closes_issu?= =?utf8?q?e12438__-_idlelib=2EPyShell=27s_showformatwarning_method_was_pas?= =?utf8?q?sing?= Message-ID: http://hg.python.org/cpython/rev/e9c406a53972 changeset: 71171:e9c406a53972 branch: 3.2 parent: 71168:6886e0bf29bc user: Senthil Kumaran date: Sun Jul 03 17:39:20 2011 -0700 summary: Fix closes issue12438 - idlelib.PyShell's showformatwarning method was passing an incorrect arg. files: Lib/idlelib/PyShell.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -59,7 +59,7 @@ file = warning_stream try: file.write(warnings.formatwarning(message, category, filename, - lineno, file=file, line=line)) + lineno, line=line)) except IOError: pass ## file (probably __stderr__) is invalid, warning dropped. warnings.showwarning = idle_showwarning -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 02:40:57 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 02:40:57 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_from_3=2E2=2E__=27idle=5Fformatwarning=27_is_the_corre?= =?utf8?q?ct_method_name=2E?= Message-ID: http://hg.python.org/cpython/rev/0159624b1824 changeset: 71172:0159624b1824 parent: 71169:fbb1504a9275 parent: 71171:e9c406a53972 user: Senthil Kumaran date: Sun Jul 03 17:40:39 2011 -0700 summary: Merge from 3.2. 'idle_formatwarning' is the correct method name. files: Lib/idlelib/PyShell.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -59,7 +59,7 @@ file = warning_stream try: file.write(warnings.formatwarning(message, category, filename, - lineno, file=file, line=line)) + lineno, line=line)) except IOError: pass ## file (probably __stderr__) is invalid, warning dropped. warnings.showwarning = idle_showwarning -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 02:57:06 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 02:57:06 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDY3?= =?utf8?q?=3A_warnings=3A_fix_a_race_condition_if_a_warning_is_emitted_at?= Message-ID: http://hg.python.org/cpython/rev/ac18e70cbe7e changeset: 71173:ac18e70cbe7e branch: 3.2 parent: 71171:e9c406a53972 user: Victor Stinner date: Mon Jul 04 02:43:09 2011 +0200 summary: Issue #12467: warnings: fix a race condition if a warning is emitted at shutdown, if globals()['__file__'] is None. files: Lib/test/test_warnings.py | 12 ++++++++++++ Misc/NEWS | 3 +++ Python/_warnings.c | 2 +- 3 files changed, 16 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -542,6 +542,18 @@ assert expected_line self.assertEqual(second_line, expected_line) + def test_filename_none(self): + # issue #12467: race condition if a warning is emitted at shutdown + globals_dict = globals() + oldfile = globals_dict['__file__'] + try: + with original_warnings.catch_warnings(module=self.module) as w: + self.module.filterwarnings("always", category=UserWarning) + globals_dict['__file__'] = None + original_warnings.warn('test', UserWarning) + finally: + globals_dict['__file__'] = oldfile + class WarningsDisplayTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,9 @@ Library ------- +- Issue #12467: warnings: fix a race condition if a warning is emitted at + shutdown, if globals()['__file__'] is None. + - Issue #12451: pydoc: importfile() now opens the Python script in binary mode, instead of text mode using the locale encoding, to avoid encoding issues. diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -496,7 +496,7 @@ /* Setup filename. */ *filename = PyDict_GetItemString(globals, "__file__"); - if (*filename != NULL) { + if (*filename != NULL && PyUnicode_Check(*filename)) { Py_ssize_t len = PyUnicode_GetSize(*filename); Py_UNICODE *unicode = PyUnicode_AS_UNICODE(*filename); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 02:57:06 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 02:57:06 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28merge_3=2E2=29_Issue_=2312467=3A_warnings=3A_fix_a_race_c?= =?utf8?q?ondition_if_a_warning_is?= Message-ID: http://hg.python.org/cpython/rev/5133fee2433e changeset: 71174:5133fee2433e parent: 71172:0159624b1824 parent: 71173:ac18e70cbe7e user: Victor Stinner date: Mon Jul 04 02:56:10 2011 +0200 summary: (merge 3.2) Issue #12467: warnings: fix a race condition if a warning is emitted at shutdown, if globals()['__file__'] is None. files: Lib/test/test_warnings.py | 12 ++++++++++++ Misc/NEWS | 3 +++ Python/_warnings.c | 2 +- 3 files changed, 16 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -542,6 +542,18 @@ assert expected_line self.assertEqual(second_line, expected_line) + def test_filename_none(self): + # issue #12467: race condition if a warning is emitted at shutdown + globals_dict = globals() + oldfile = globals_dict['__file__'] + try: + with original_warnings.catch_warnings(module=self.module) as w: + self.module.filterwarnings("always", category=UserWarning) + globals_dict['__file__'] = None + original_warnings.warn('test', UserWarning) + finally: + globals_dict['__file__'] = oldfile + class WarningsDisplayTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -209,6 +209,9 @@ Library ------- +- Issue #12467: warnings: fix a race condition if a warning is emitted at + shutdown, if globals()['__file__'] is None. + - Issue #12451: pydoc: importfile() now opens the Python script in binary mode, instead of text mode using the locale encoding, to avoid encoding issues. diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -496,7 +496,7 @@ /* Setup filename. */ *filename = PyDict_GetItemString(globals, "__file__"); - if (*filename != NULL) { + if (*filename != NULL && PyUnicode_Check(*filename)) { Py_ssize_t len = PyUnicode_GetSize(*filename); Py_UNICODE *unicode = PyUnicode_AS_UNICODE(*filename); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 03:05:45 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 03:05:45 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyNDY3?= =?utf8?q?=3A_warnings=3A_fix_a_race_condition_if_a_warning_is_emitted_at?= Message-ID: http://hg.python.org/cpython/rev/fc46acf7a645 changeset: 71175:fc46acf7a645 branch: 2.7 parent: 71170:c9f69b28c4d1 user: Victor Stinner date: Mon Jul 04 03:05:37 2011 +0200 summary: Issue #12467: warnings: fix a race condition if a warning is emitted at shutdown, if globals()['__file__'] is None. files: Lib/test/test_warnings.py | 12 ++++++++++++ Misc/NEWS | 3 +++ Python/_warnings.c | 2 +- 3 files changed, 16 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -530,6 +530,18 @@ assert expected_line self.assertEqual(second_line, expected_line) + def test_filename_none(self): + # issue #12467: race condition if a warning is emitted at shutdown + globals_dict = globals() + oldfile = globals_dict['__file__'] + try: + with original_warnings.catch_warnings(module=self.module) as w: + self.module.filterwarnings("always", category=UserWarning) + globals_dict['__file__'] = None + self.module.warn('test', UserWarning) + finally: + globals_dict['__file__'] = oldfile + class WarningsDisplayTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #12467: warnings: fix a race condition if a warning is emitted at + shutdown, if globals()['__file__'] is None. + - Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -491,7 +491,7 @@ /* Setup filename. */ *filename = PyDict_GetItemString(globals, "__file__"); - if (*filename != NULL) { + if (*filename != NULL && PyString_Check(*filename)) { Py_ssize_t len = PyString_Size(*filename); const char *file_str = PyString_AsString(*filename); if (file_str == NULL || (len < 0 && PyErr_Occurred())) -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Mon Jul 4 03:20:03 2011 From: ncoghlan at gmail.com (Nick Coghlan) Date: Mon, 4 Jul 2011 11:20:03 +1000 Subject: [Python-checkins] cpython: no one passes NULL here (or should anyway) In-Reply-To: References: Message-ID: On Mon, Jul 4, 2011 at 8:02 AM, benjamin.peterson wrote: > http://hg.python.org/cpython/rev/bbbeddafeec0 > changeset: ? 71160:bbbeddafeec0 > user: ? ? ? ?Benjamin Peterson > date: ? ? ? ?Sun Jul 03 17:06:32 2011 -0500 > summary: > ?no one passes NULL here (or should anyway) > > files: > ?Python/ceval.c | ?3 --- > ?1 files changed, 0 insertions(+), 3 deletions(-) > > > diff --git a/Python/ceval.c b/Python/ceval.c > --- a/Python/ceval.c > +++ b/Python/ceval.c > @@ -1115,9 +1115,6 @@ > > ?/* Start of code */ > > - ? ?if (f == NULL) > - ? ? ? ?return NULL; > - May need to replace that with an assert(f != NULL) to keep static analysers happy. Cheers, Nick. -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From python-checkins at python.org Mon Jul 4 03:22:24 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 03:22:24 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_closes_issu?= =?utf8?q?e_issue12470_-_check_for_utime_for_the_skipUnless_condition=2E?= Message-ID: http://hg.python.org/cpython/rev/301c008dd58d changeset: 71176:301c008dd58d branch: 3.2 parent: 71173:ac18e70cbe7e user: Senthil Kumaran date: Sun Jul 03 18:21:38 2011 -0700 summary: Fix closes issue issue12470 - check for utime for the skipUnless condition. files: Lib/test/test_shutil.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -427,7 +427,7 @@ self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode) @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod') - @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.utime') + @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime') def test_copy2(self): # Ensure that the copied file exists and has the same mode and # modification time bits. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 03:22:25 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 03:22:25 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_from_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/53fc0c475260 changeset: 71177:53fc0c475260 parent: 71174:5133fee2433e parent: 71176:301c008dd58d user: Senthil Kumaran date: Sun Jul 03 18:22:14 2011 -0700 summary: merge from 3.2 files: Lib/test/test_shutil.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -421,7 +421,7 @@ self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode) @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod') - @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.utime') + @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime') def test_copy2(self): # Ensure that the copied file exists and has the same mode and # modification time bits. -- Repository URL: http://hg.python.org/cpython From benjamin at python.org Mon Jul 4 04:54:23 2011 From: benjamin at python.org (Benjamin Peterson) Date: Sun, 3 Jul 2011 21:54:23 -0500 Subject: [Python-checkins] cpython: no one passes NULL here (or should anyway) In-Reply-To: References: Message-ID: 2011/7/3 Nick Coghlan : > On Mon, Jul 4, 2011 at 8:02 AM, benjamin.peterson > wrote: >> http://hg.python.org/cpython/rev/bbbeddafeec0 >> changeset: ? 71160:bbbeddafeec0 >> user: ? ? ? ?Benjamin Peterson >> date: ? ? ? ?Sun Jul 03 17:06:32 2011 -0500 >> summary: >> ?no one passes NULL here (or should anyway) >> >> files: >> ?Python/ceval.c | ?3 --- >> ?1 files changed, 0 insertions(+), 3 deletions(-) >> >> >> diff --git a/Python/ceval.c b/Python/ceval.c >> --- a/Python/ceval.c >> +++ b/Python/ceval.c >> @@ -1115,9 +1115,6 @@ >> >> ?/* Start of code */ >> >> - ? ?if (f == NULL) >> - ? ? ? ?return NULL; >> - > > May need to replace that with an assert(f != NULL) to keep static > analysers happy. Surely static analyzers don't assume every argument passed in is NULL? -- Regards, Benjamin From solipsis at pitrou.net Mon Jul 4 05:08:26 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 04 Jul 2011 05:08:26 +0200 Subject: [Python-checkins] Daily reference leaks (53fc0c475260): sum=-288 Message-ID: results for 53fc0c475260 on branch "default" -------------------------------------------- test_concurrent_futures leaked [-108, 108, -585] references, sum=-585 test_packaging leaked [100, 100, 100] references, sum=300 test_warnings leaked [-1, -1, -1] references, sum=-3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogGUTzjX', '-x'] From python-checkins at python.org Mon Jul 4 05:15:22 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 04 Jul 2011 05:15:22 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_plug_refleak?= Message-ID: http://hg.python.org/cpython/rev/f0382acebfe6 changeset: 71178:f0382acebfe6 branch: 3.2 parent: 71176:301c008dd58d user: Benjamin Peterson date: Sun Jul 03 22:18:34 2011 -0500 summary: plug refleak files: Python/_warnings.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -517,6 +517,7 @@ } else { const char *module_str = _PyUnicode_AsString(*module); + Py_XDECREF(*filename); if (module_str == NULL) goto handle_error; if (strcmp(module_str, "__main__") == 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 05:15:23 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 04 Jul 2011 05:15:23 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_plug_refleak?= Message-ID: http://hg.python.org/cpython/rev/a2944dd4ba7b changeset: 71179:a2944dd4ba7b branch: 2.7 parent: 71175:fc46acf7a645 user: Benjamin Peterson date: Sun Jul 03 22:18:34 2011 -0500 summary: plug refleak files: Python/_warnings.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -514,6 +514,7 @@ } else { const char *module_str = PyString_AsString(*module); + Py_XDECREF(*filename); if (module_str && strcmp(module_str, "__main__") == 0) { PyObject *argv = PySys_GetObject("argv"); if (argv != NULL && PyList_Size(argv) > 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 05:15:23 2011 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 04 Jul 2011 05:15:23 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/078d91fc6b3b changeset: 71180:078d91fc6b3b parent: 71177:53fc0c475260 parent: 71178:f0382acebfe6 user: Benjamin Peterson date: Sun Jul 03 22:19:29 2011 -0500 summary: merge 3.2 files: Python/_warnings.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -517,6 +517,7 @@ } else { const char *module_str = _PyUnicode_AsString(*module); + Py_XDECREF(*filename); if (module_str == NULL) goto handle_error; if (strcmp(module_str, "__main__") == 0) { -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Mon Jul 4 05:44:59 2011 From: ncoghlan at gmail.com (Nick Coghlan) Date: Mon, 4 Jul 2011 13:44:59 +1000 Subject: [Python-checkins] cpython: no one passes NULL here (or should anyway) In-Reply-To: References: Message-ID: On Mon, Jul 4, 2011 at 12:54 PM, Benjamin Peterson wrote: > 2011/7/3 Nick Coghlan : >> May need to replace that with an assert(f != NULL) to keep static >> analysers happy. > > Surely static analyzers don't assume every argument passed in is NULL? I didn't check - was this change in a static function? For those, I think they can figure it out. For functions exposed to the linker, I think they demand an explicit check for a non-NULL pointer (which may be in the form of an assertion). Cheers, Nick. -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From python-checkins at python.org Mon Jul 4 06:05:36 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 06:05:36 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_closes_issu?= =?utf8?q?e12471_-_wrong_TypeError_message_when_=27=25i=27_format_spec_was?= =?utf8?q?_used=2E?= Message-ID: http://hg.python.org/cpython/rev/97707459bb5a changeset: 71181:97707459bb5a branch: 3.2 parent: 71178:f0382acebfe6 user: Senthil Kumaran date: Sun Jul 03 21:03:16 2011 -0700 summary: Fix closes issue12471 - wrong TypeError message when '%i' format spec was used. files: Lib/test/test_unicode.py | 1 + Objects/unicodeobject.c | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -788,6 +788,7 @@ self.assertEqual('%c' % '\U00021483', '\U00021483') self.assertRaises(TypeError, "%c".__mod__, "aa") self.assertRaises(ValueError, "%.1\u1032f".__mod__, (1.0/3)) + self.assertRaises(TypeError, "%i".__mod__, "aa") # formatting jobs delegated from the string implementation: self.assertEqual('...%(foo)s...' % {'foo':"abc"}, '...abc...') diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9689,8 +9689,6 @@ case 'o': case 'x': case 'X': - if (c == 'i') - c = 'd'; isnumok = 0; if (PyNumber_Check(v)) { PyObject *iobj=NULL; @@ -9705,7 +9703,7 @@ if (iobj!=NULL) { if (PyLong_Check(iobj)) { isnumok = 1; - temp = formatlong(iobj, flags, prec, c); + temp = formatlong(iobj, flags, prec, (c == 'i'? 'd': c)); Py_DECREF(iobj); if (!temp) goto onError; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 06:05:37 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 06:05:37 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_from_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/7ac6397a6308 changeset: 71182:7ac6397a6308 parent: 71180:078d91fc6b3b parent: 71181:97707459bb5a user: Senthil Kumaran date: Sun Jul 03 21:05:25 2011 -0700 summary: merge from 3.2 files: Lib/test/test_unicode.py | 1 + Objects/unicodeobject.c | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -788,6 +788,7 @@ self.assertEqual('%c' % '\U00021483', '\U00021483') self.assertRaises(TypeError, "%c".__mod__, "aa") self.assertRaises(ValueError, "%.1\u1032f".__mod__, (1.0/3)) + self.assertRaises(TypeError, "%i".__mod__, "aa") # formatting jobs delegated from the string implementation: self.assertEqual('...%(foo)s...' % {'foo':"abc"}, '...abc...') diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9761,8 +9761,6 @@ case 'o': case 'x': case 'X': - if (c == 'i') - c = 'd'; isnumok = 0; if (PyNumber_Check(v)) { PyObject *iobj=NULL; @@ -9777,7 +9775,7 @@ if (iobj!=NULL) { if (PyLong_Check(iobj)) { isnumok = 1; - temp = formatlong(iobj, flags, prec, c); + temp = formatlong(iobj, flags, prec, (c == 'i'? 'd': c)); Py_DECREF(iobj); if (!temp) goto onError; -- Repository URL: http://hg.python.org/cpython From benjamin at python.org Mon Jul 4 06:15:53 2011 From: benjamin at python.org (Benjamin Peterson) Date: Sun, 3 Jul 2011 23:15:53 -0500 Subject: [Python-checkins] cpython: no one passes NULL here (or should anyway) In-Reply-To: References: Message-ID: 2011/7/3 Nick Coghlan : > On Mon, Jul 4, 2011 at 12:54 PM, Benjamin Peterson wrote: >> 2011/7/3 Nick Coghlan : >>> May need to replace that with an assert(f != NULL) to keep static >>> analysers happy. >> >> Surely static analyzers don't assume every argument passed in is NULL? > > I didn't check - was this change in a static function? For those, I > think they can figure it out. For functions exposed to the linker, I > think they demand an explicit check for a non-NULL pointer (which may > be in the form of an assertion). If someone's static analysis tool starts complaining about it, I'd be happy to consider adding an assert... -- Regards, Benjamin From python-checkins at python.org Mon Jul 4 06:38:26 2011 From: python-checkins at python.org (ned.deily) Date: Mon, 04 Jul 2011 06:38:26 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEwNzM0?= =?utf8?q?=3A_Temporarily_disable_test=5Fttk_test=5Fheading=5Fcallback_on_?= =?utf8?q?2=2E7_as_well=2E?= Message-ID: http://hg.python.org/cpython/rev/8dde71899733 changeset: 71183:8dde71899733 branch: 2.7 parent: 71179:a2944dd4ba7b user: Ned Deily date: Sun Jul 03 21:37:03 2011 -0700 summary: Issue #10734: Temporarily disable test_ttk test_heading_callback on 2.7 as well. files: Lib/lib-tk/test/test_ttk/test_widgets.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/lib-tk/test/test_ttk/test_widgets.py b/Lib/lib-tk/test/test_ttk/test_widgets.py --- a/Lib/lib-tk/test/test_ttk/test_widgets.py +++ b/Lib/lib-tk/test/test_ttk/test_widgets.py @@ -937,7 +937,8 @@ self.assertRaises(Tkinter.TclError, self.tv.heading, '#0', anchor=1) - + # XXX skipping for now; should be fixed to work with newer ttk + @unittest.skip("skipping pending resolution of Issue #10734") def test_heading_callback(self): def simulate_heading_click(x, y): support.simulate_mouse_click(self.tv, x, y) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 07:31:29 2011 From: python-checkins at python.org (ned.deily) Date: Mon, 04 Jul 2011 07:31:29 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzg3MTY6?= =?utf8?q?_Avoid_crashes_caused_by_Aqua_Tk_on_OSX_when_attempting_to_run?= Message-ID: http://hg.python.org/cpython/rev/ea02eca122b5 changeset: 71184:ea02eca122b5 branch: 2.7 user: Ned Deily date: Sun Jul 03 21:52:35 2011 -0700 summary: Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run test_tk or test_ttk_guionly under a username that is not currently logged in to the console windowserver (as may be the case under buildbot or ssh). files: Lib/lib-tk/test/runtktests.py | 32 +++++++++++++++++++++++ Lib/test/test_tk.py | 12 ++------ Lib/test/test_ttk_guionly.py | 17 +++++++----- Misc/NEWS | 4 ++ 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/Lib/lib-tk/test/runtktests.py b/Lib/lib-tk/test/runtktests.py --- a/Lib/lib-tk/test/runtktests.py +++ b/Lib/lib-tk/test/runtktests.py @@ -10,10 +10,42 @@ import sys import unittest import importlib +import subprocess import test.test_support this_dir_path = os.path.abspath(os.path.dirname(__file__)) +_tk_available = None + +def check_tk_availability(): + """Check that Tk is installed and available.""" + global _tk_available + + if _tk_available is not None: + return + + if sys.platform == 'darwin': + # The Aqua Tk implementations on OS X can abort the process if + # being called in an environment where a window server connection + # cannot be made, for instance when invoked by a buildbot or ssh + # process not running under the same user id as the current console + # user. Instead, try to initialize Tk under a subprocess. + p = subprocess.Popen( + [sys.executable, '-c', 'import Tkinter; Tkinter.Button()'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stderr = test.test_support.strip_python_stderr(p.communicate()[1]) + if stderr or p.returncode: + raise unittest.SkipTest("tk cannot be initialized: %s" % stderr) + else: + try: + Tkinter.Button() + except tkinter.TclError as msg: + # assuming tk is not available + raise unittest.SkipTest("tk not available: %s" % msg) + + _tk_available = True + return + def is_package(path): for name in os.listdir(path): if name in ('__init__.py', '__init__.pyc', '__init.pyo'): diff --git a/Lib/test/test_tk.py b/Lib/test/test_tk.py --- a/Lib/test/test_tk.py +++ b/Lib/test/test_tk.py @@ -1,18 +1,9 @@ import os -import unittest from test import test_support # Skip test if _tkinter wasn't built. test_support.import_module('_tkinter') -import Tkinter - -try: - Tkinter.Button() -except Tkinter.TclError, msg: - # assuming tk is not available - raise unittest.SkipTest("tk not available: %s" % msg) - this_dir = os.path.dirname(os.path.abspath(__file__)) lib_tk_test = os.path.abspath(os.path.join(this_dir, os.path.pardir, 'lib-tk', 'test')) @@ -20,6 +11,9 @@ with test_support.DirsOnSysPath(lib_tk_test): import runtktests +# Skip test if tk cannot be initialized. +runtktests.check_tk_availability() + def test_main(enable_gui=False): if enable_gui: if test_support.use_resources is None: diff --git a/Lib/test/test_ttk_guionly.py b/Lib/test/test_ttk_guionly.py --- a/Lib/test/test_ttk_guionly.py +++ b/Lib/test/test_ttk_guionly.py @@ -5,6 +5,16 @@ # Skip this test if _tkinter wasn't built. test_support.import_module('_tkinter') +this_dir = os.path.dirname(os.path.abspath(__file__)) +lib_tk_test = os.path.abspath(os.path.join(this_dir, os.path.pardir, + 'lib-tk', 'test')) + +with test_support.DirsOnSysPath(lib_tk_test): + import runtktests + +# Skip test if tk cannot be initialized. +runtktests.check_tk_availability() + import ttk from _tkinter import TclError @@ -14,13 +24,6 @@ # assuming ttk is not available raise unittest.SkipTest("ttk not available: %s" % msg) -this_dir = os.path.dirname(os.path.abspath(__file__)) -lib_tk_test = os.path.abspath(os.path.join(this_dir, os.path.pardir, - 'lib-tk', 'test')) - -with test_support.DirsOnSysPath(lib_tk_test): - import runtktests - def test_main(enable_gui=False): if enable_gui: if test_support.use_resources is None: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,10 @@ Tests ----- +- Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run + test_tk or test_ttk_guionly under a username that is not currently logged + in to the console windowserver (as may be the case under buildbot or ssh). + - Issue #12141: Install a copy of template C module file so that test_build_ext of test_distutils is no longer silently skipped when run outside of a build directory. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 07:31:30 2011 From: python-checkins at python.org (ned.deily) Date: Mon, 04 Jul 2011 07:31:30 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzg3MTY6?= =?utf8?q?_Avoid_crashes_caused_by_Aqua_Tk_on_OSX_when_attempting_to_run?= Message-ID: http://hg.python.org/cpython/rev/279488f5a171 changeset: 71185:279488f5a171 branch: 3.2 parent: 71181:97707459bb5a user: Ned Deily date: Sun Jul 03 21:56:48 2011 -0700 summary: Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run test_tk or test_ttk_guionly under a username that is not currently logged in to the console windowserver (as may be the case under buildbot or ssh). files: Lib/test/test_tk.py | 12 ++----- Lib/test/test_ttk_guionly.py | 4 ++ Lib/tkinter/test/support.py | 36 ++++++++++++++++++++++++ Misc/NEWS | 8 +++++ 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_tk.py b/Lib/test/test_tk.py --- a/Lib/test/test_tk.py +++ b/Lib/test/test_tk.py @@ -2,15 +2,11 @@ # Skip test if _tkinter wasn't built. support.import_module('_tkinter') -import tkinter +# Skip test if tk cannot be initialized. +from tkinter.test.support import check_tk_availability +check_tk_availability() + from tkinter.test import runtktests -import unittest - -try: - tkinter.Button() -except tkinter.TclError as msg: - # assuming tk is not available - raise unittest.SkipTest("tk not available: %s" % msg) def test_main(enable_gui=False): if enable_gui: diff --git a/Lib/test/test_ttk_guionly.py b/Lib/test/test_ttk_guionly.py --- a/Lib/test/test_ttk_guionly.py +++ b/Lib/test/test_ttk_guionly.py @@ -5,6 +5,10 @@ # Skip this test if _tkinter wasn't built. support.import_module('_tkinter') +# Skip test if tk cannot be initialized. +from tkinter.test.support import check_tk_availability +check_tk_availability() + from _tkinter import TclError from tkinter import ttk from tkinter.test import runtktests diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -1,6 +1,42 @@ +import subprocess +import sys +from test import support import tkinter +import unittest + +_tk_available = None + +def check_tk_availability(): + """Check that Tk is installed and available.""" + global _tk_available + + if _tk_available is not None: + return + + if sys.platform == 'darwin': + # The Aqua Tk implementations on OS X can abort the process if + # being called in an environment where a window server connection + # cannot be made, for instance when invoked by a buildbot or ssh + # process not running under the same user id as the current console + # user. Instead, try to initialize Tk under a subprocess. + p = subprocess.Popen( + [sys.executable, '-c', 'import tkinter; tkinter.Button()'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stderr = support.strip_python_stderr(p.communicate()[1]) + if stderr or p.returncode: + raise unittest.SkipTest("tk cannot be initialized: %s" % stderr) + else: + try: + tkinter.Button() + except tkinter.TclError as msg: + # assuming tk is not available + raise unittest.SkipTest("tk not available: %s" % msg) + + _tk_available = True + return def get_tk_root(): + check_tk_availability() # raise exception if tk unavailable try: root = tkinter._default_root except AttributeError: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,14 @@ C-API ----- +Tests +----- + +- Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run + test_tk or test_ttk_guionly under a username that is not currently logged + in to the console windowserver (as may be the case under buildbot or ssh). + + What's New in Python 3.2.1 release candidate 2? =============================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 07:31:31 2011 From: python-checkins at python.org (ned.deily) Date: Mon, 04 Jul 2011 07:31:31 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=238716=3A_Avoid_crashes_caused_by_Aqua_Tk_on_OSX_when?= =?utf8?q?_attempting_to_run?= Message-ID: http://hg.python.org/cpython/rev/5b5a33196916 changeset: 71186:5b5a33196916 parent: 71182:7ac6397a6308 parent: 71185:279488f5a171 user: Ned Deily date: Sun Jul 03 22:27:16 2011 -0700 summary: Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run test_tk or test_ttk_guionly under a username that is not currently logged in to the console windowserver (as may be the case under buildbot or ssh). files: Lib/test/test_tk.py | 12 ++----- Lib/test/test_ttk_guionly.py | 4 ++ Lib/tkinter/test/support.py | 36 ++++++++++++++++++++++++ Misc/NEWS | 4 ++ 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_tk.py b/Lib/test/test_tk.py --- a/Lib/test/test_tk.py +++ b/Lib/test/test_tk.py @@ -2,15 +2,11 @@ # Skip test if _tkinter wasn't built. support.import_module('_tkinter') -import tkinter +# Skip test if tk cannot be initialized. +from tkinter.test.support import check_tk_availability +check_tk_availability() + from tkinter.test import runtktests -import unittest - -try: - tkinter.Button() -except tkinter.TclError as msg: - # assuming tk is not available - raise unittest.SkipTest("tk not available: %s" % msg) def test_main(enable_gui=False): if enable_gui: diff --git a/Lib/test/test_ttk_guionly.py b/Lib/test/test_ttk_guionly.py --- a/Lib/test/test_ttk_guionly.py +++ b/Lib/test/test_ttk_guionly.py @@ -5,6 +5,10 @@ # Skip this test if _tkinter wasn't built. support.import_module('_tkinter') +# Skip test if tk cannot be initialized. +from tkinter.test.support import check_tk_availability +check_tk_availability() + from _tkinter import TclError from tkinter import ttk from tkinter.test import runtktests diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -1,6 +1,42 @@ +import subprocess +import sys +from test import support import tkinter +import unittest + +_tk_available = None + +def check_tk_availability(): + """Check that Tk is installed and available.""" + global _tk_available + + if _tk_available is not None: + return + + if sys.platform == 'darwin': + # The Aqua Tk implementations on OS X can abort the process if + # being called in an environment where a window server connection + # cannot be made, for instance when invoked by a buildbot or ssh + # process not running under the same user id as the current console + # user. Instead, try to initialize Tk under a subprocess. + p = subprocess.Popen( + [sys.executable, '-c', 'import tkinter; tkinter.Button()'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stderr = support.strip_python_stderr(p.communicate()[1]) + if stderr or p.returncode: + raise unittest.SkipTest("tk cannot be initialized: %s" % stderr) + else: + try: + tkinter.Button() + except tkinter.TclError as msg: + # assuming tk is not available + raise unittest.SkipTest("tk not available: %s" % msg) + + _tk_available = True + return def get_tk_root(): + check_tk_availability() # raise exception if tk unavailable try: root = tkinter._default_root except AttributeError: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -973,6 +973,10 @@ Tests ----- +- Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run + test_tk or test_ttk_guionly under a username that is not currently logged + in to the console windowserver (as may be the case under buildbot or ssh). + - Issue #12407: Explicitly skip test_capi.EmbeddingTest under Windows. - Issue #12400: regrtest -W doesn't rerun the tests twice anymore, but captures -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 08:17:38 2011 From: python-checkins at python.org (ned.deily) Date: Mon, 04 Jul 2011 08:17:38 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzg3MTY6?= =?utf8?q?_Fix_errors_in_the_non-OS_X_path_of_the_27_backport=2E?= Message-ID: http://hg.python.org/cpython/rev/06cb0d602468 changeset: 71187:06cb0d602468 branch: 2.7 parent: 71184:ea02eca122b5 user: Ned Deily date: Sun Jul 03 23:16:49 2011 -0700 summary: Issue #8716: Fix errors in the non-OS X path of the 27 backport. files: Lib/lib-tk/test/runtktests.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/lib-tk/test/runtktests.py b/Lib/lib-tk/test/runtktests.py --- a/Lib/lib-tk/test/runtktests.py +++ b/Lib/lib-tk/test/runtktests.py @@ -37,9 +37,10 @@ if stderr or p.returncode: raise unittest.SkipTest("tk cannot be initialized: %s" % stderr) else: + import Tkinter try: Tkinter.Button() - except tkinter.TclError as msg: + except Tkinter.TclError as msg: # assuming tk is not available raise unittest.SkipTest("tk not available: %s" % msg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 11:52:29 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 11:52:29 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyNDI5?= =?utf8?q?=3A_Skip_interrupted_write_tests_on_FreeBSD_=3C=3D_7?= Message-ID: http://hg.python.org/cpython/rev/a624b86264a4 changeset: 71188:a624b86264a4 branch: 2.7 user: Victor Stinner date: Mon Jul 04 11:44:46 2011 +0200 summary: Issue #12429: Skip interrupted write tests on FreeBSD <= 7 On FreeBSD, the SIGALRM signal is sometimes received by the reader thread. files: Lib/test/test_io.py | 2 ++ 1 files changed, 2 insertions(+), 0 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 @@ -2557,6 +2557,8 @@ 1 // 0 @unittest.skipUnless(threading, 'Threading required for this test.') + @unittest.skipIf(sys.platform in ('freebsd5', 'freebsd6', 'freebsd7'), + 'issue #12429: skip test on FreeBSD <= 7') def check_interrupted_write(self, item, bytes, **fdopen_kwargs): """Check that a partial write, when it gets interrupted, properly invokes the signal handler, and bubbles up the exception raised -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 11:52:31 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 11:52:31 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDI5?= =?utf8?q?=3A_Skip_interrupted_write_tests_on_FreeBSD_=3C=3D_7?= Message-ID: http://hg.python.org/cpython/rev/e924e51e9447 changeset: 71189:e924e51e9447 branch: 3.2 parent: 71185:279488f5a171 user: Victor Stinner date: Mon Jul 04 11:48:17 2011 +0200 summary: Issue #12429: Skip interrupted write tests on FreeBSD <= 7 On FreeBSD, the SIGALRM signal is sometimes received by the reader thread. files: Lib/test/test_io.py | 2 ++ 1 files changed, 2 insertions(+), 0 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 @@ -2651,6 +2651,8 @@ 1/0 @unittest.skipUnless(threading, 'Threading required for this test.') + @unittest.skipIf(sys.platform in ('freebsd5', 'freebsd6', 'freebsd7'), + 'issue #12429: skip test on FreeBSD <= 7') def check_interrupted_write(self, item, bytes, **fdopen_kwargs): """Check that a partial write, when it gets interrupted, properly invokes the signal handler, and bubbles up the exception raised -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 11:52:31 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 11:52:31 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_null_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/79d7bcbe88f6 changeset: 71190:79d7bcbe88f6 parent: 71186:5b5a33196916 parent: 71189:e924e51e9447 user: Victor Stinner date: Mon Jul 04 11:51:21 2011 +0200 summary: null merge 3.2 Python 3.3 has the correct fix for #12429, use pthread_sigmask(). files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 13:49:04 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 13:49:04 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=239642=3A_Fix_filesy?= =?utf8?q?stem_encoding_initialization=3A_use_the_ANSI_code_page_on?= Message-ID: http://hg.python.org/cpython/rev/7ce685cda0ae changeset: 71191:7ce685cda0ae user: Victor Stinner date: Mon Jul 04 13:48:30 2011 +0200 summary: Issue #9642: Fix filesystem encoding initialization: use the ANSI code page on Windows if the mbcs codec is not available, and fail with a fatal error if we cannot get the locale encoding (if nl_langinfo(CODESET) is not available) instead of using UTF-8. files: Misc/NEWS | 5 +++++ Python/bltinmodule.c | 5 +---- Python/pythonrun.c | 28 ++++++++++++++-------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #9642: Fix filesystem encoding initialization: use the ANSI code page + on Windows if the mbcs codec is not available, and fail with a fatal error if + we cannot get the locale encoding (if nl_langinfo(CODESET) is not available) + instead of using UTF-8. + - When a generator yields, do not retain the caller's exception state on the generator. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -24,12 +24,9 @@ #elif defined(__APPLE__) const char *Py_FileSystemDefaultEncoding = "utf-8"; int Py_HasFileSystemDefaultEncoding = 1; -#elif defined(HAVE_LANGINFO_H) && defined(CODESET) +#else const char *Py_FileSystemDefaultEncoding = NULL; /* set by initfsencoding() */ int Py_HasFileSystemDefaultEncoding = 0; -#else -const char *Py_FileSystemDefaultEncoding = "utf-8"; -int Py_HasFileSystemDefaultEncoding = 1; #endif static PyObject * diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -168,18 +168,25 @@ return NULL; } -#if defined(HAVE_LANGINFO_H) && defined(CODESET) static char* -get_codeset(void) +get_locale_encoding(void) { +#ifdef MS_WINDOWS + char codepage[100]; + PyOS_snprintf(codepage, sizeof(codepage), "cp%d", GetACP()); + return get_codec_name(codepage); +#elif defined(HAVE_LANGINFO_H) && defined(CODESET) char* codeset = nl_langinfo(CODESET); if (!codeset || codeset[0] == '\0') { PyErr_SetString(PyExc_ValueError, "CODESET is not set or empty"); return NULL; } return get_codec_name(codeset); +#else + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; +#endif } -#endif void Py_InitializeEx(int install_sigs) @@ -746,24 +753,17 @@ initfsencoding(PyInterpreterState *interp) { PyObject *codec; -#if defined(HAVE_LANGINFO_H) && defined(CODESET) - char *codeset = NULL; - if (Py_FileSystemDefaultEncoding == NULL) { - /* On Unix, set the file system encoding according to the - user's preference, if the CODESET names a well-known - Python codec, and Py_FileSystemDefaultEncoding isn't - initialized by other means. */ - codeset = get_codeset(); - if (codeset == NULL) + if (Py_FileSystemDefaultEncoding == NULL) + { + Py_FileSystemDefaultEncoding = get_locale_encoding(); + if (Py_FileSystemDefaultEncoding == NULL) Py_FatalError("Py_Initialize: Unable to get the locale encoding"); - Py_FileSystemDefaultEncoding = codeset; Py_HasFileSystemDefaultEncoding = 0; interp->fscodec_initialized = 1; return 0; } -#endif /* the encoding is mbcs, utf-8 or ascii */ codec = _PyCodec_Lookup(Py_FileSystemDefaultEncoding); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 14:03:52 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 14:03:52 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=239642=3A_Fix_the_de?= =?utf8?q?finition_of_time=2Eclock=28=29_on_Windows?= Message-ID: http://hg.python.org/cpython/rev/75b18b10064f changeset: 71192:75b18b10064f user: Victor Stinner date: Mon Jul 04 13:55:40 2011 +0200 summary: Issue #9642: Fix the definition of time.clock() on Windows Don't unset and set againt the HAVE_CLOCK define, reorder the #if tests instead. Fix also the definition of the timezone encoding. files: Modules/timemodule.c | 54 ++++++++++++++----------------- 1 files changed, 25 insertions(+), 29 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -3,8 +3,6 @@ #include "Python.h" #include "_time.h" -#define TZNAME_ENCODING "utf-8" - #include #ifdef HAVE_SYS_TYPES_H @@ -45,12 +43,11 @@ #endif /* MS_WINDOWS */ #endif /* !__WATCOMC__ || __QNX__ */ -#if defined(MS_WINDOWS) && !defined(__BORLANDC__) -/* Win32 has better clock replacement; we have our own version below. */ -#undef HAVE_CLOCK -#undef TZNAME_ENCODING -#define TZNAME_ENCODING "mbcs" -#endif /* MS_WINDOWS && !defined(__BORLANDC__) */ +#if defined(MS_WINDOWS) +# define TZNAME_ENCODING "mbcs" +#else +# define TZNAME_ENCODING "utf-8" +#endif #if defined(PYOS_OS2) #define INCL_DOS @@ -84,25 +81,9 @@ Return the current time in seconds since the Epoch.\n\ Fractions of a second may be present if the system clock provides them."); -#ifdef HAVE_CLOCK - -#ifndef CLOCKS_PER_SEC -#ifdef CLK_TCK -#define CLOCKS_PER_SEC CLK_TCK -#else -#define CLOCKS_PER_SEC 1000000 -#endif -#endif - -static PyObject * -time_clock(PyObject *self, PyObject *unused) -{ - return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC); -} -#endif /* HAVE_CLOCK */ - #if defined(MS_WINDOWS) && !defined(__BORLANDC__) -/* Due to Mark Hammond and Tim Peters */ +/* Win32 has better clock replacement; we have our own version, due to Mark + Hammond and Tim Peters */ static PyObject * time_clock(PyObject *self, PyObject *unused) { @@ -127,8 +108,23 @@ return PyFloat_FromDouble(diff / divisor); } -#define HAVE_CLOCK /* So it gets included in the methods */ -#endif /* MS_WINDOWS && !defined(__BORLANDC__) */ +#elif defined(HAVE_CLOCK) + +#ifndef CLOCKS_PER_SEC +#ifdef CLK_TCK +#define CLOCKS_PER_SEC CLK_TCK +#else +#define CLOCKS_PER_SEC 1000000 +#endif +#endif + +static PyObject * +time_clock(PyObject *self, PyObject *unused) +{ + return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC); +} +#endif /* HAVE_CLOCK */ + #ifdef HAVE_CLOCK PyDoc_STRVAR(clock_doc, @@ -784,7 +780,7 @@ static PyMethodDef time_methods[] = { {"time", time_time, METH_NOARGS, time_doc}, -#ifdef HAVE_CLOCK +#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) || defined(HAVE_CLOCK) {"clock", time_clock, METH_NOARGS, clock_doc}, #endif {"sleep", time_sleep, METH_VARARGS, sleep_doc}, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 14:25:56 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 14:25:56 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=239642=3A_Uniformize?= =?utf8?q?_the_tests_on_the_availability_of_the_mbcs_codec?= Message-ID: http://hg.python.org/cpython/rev/13e6d3cb2ecd changeset: 71193:13e6d3cb2ecd user: Victor Stinner date: Mon Jul 04 14:23:54 2011 +0200 summary: Issue #9642: Uniformize the tests on the availability of the mbcs codec Add a new HAVE_MBCS define. files: Include/unicodeobject.h | 8 ++++++-- Misc/NEWS | 3 +++ Modules/_codecsmodule.c | 10 +++++----- Modules/timemodule.c | 2 +- Objects/unicodeobject.c | 12 ++++++------ Python/bltinmodule.c | 2 +- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -109,6 +109,10 @@ # endif #endif +#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +# define HAVE_MBCS +#endif + #ifdef HAVE_WCHAR_H /* Work around a cosmetic bug in BSDI 4.x wchar.h; thanks to Thomas Wouters */ # ifdef _HAVE_BSDI @@ -1162,7 +1166,7 @@ ); #endif -#ifdef MS_WIN32 +#ifdef HAVE_MBCS /* --- MBCS codecs for Windows -------------------------------------------- */ @@ -1191,7 +1195,7 @@ ); #endif -#endif /* MS_WIN32 */ +#endif /* HAVE_MBCS */ /* --- Decimal Encoder ---------------------------------------------------- */ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #9642: Uniformize the tests on the availability of the mbcs codec, add + a new HAVE_MBCS define. + - Issue #9642: Fix filesystem encoding initialization: use the ANSI code page on Windows if the mbcs codec is not available, and fail with a fatal error if we cannot get the locale encoding (if nl_langinfo(CODESET) is not available) diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -588,7 +588,7 @@ return codec_tuple(unicode, pbuf.len); } -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +#ifdef HAVE_MBCS static PyObject * mbcs_decode(PyObject *self, @@ -613,7 +613,7 @@ return codec_tuple(decoded, consumed); } -#endif /* MS_WINDOWS */ +#endif /* HAVE_MBCS */ /* --- Encoder ------------------------------------------------------------ */ @@ -989,7 +989,7 @@ return PyUnicode_BuildEncodingMap(map); } -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +#ifdef HAVE_MBCS static PyObject * mbcs_encode(PyObject *self, @@ -1014,7 +1014,7 @@ return v; } -#endif /* MS_WINDOWS */ +#endif /* HAVE_MBCS */ /* --- Error handler registry --------------------------------------------- */ @@ -1101,7 +1101,7 @@ {"charmap_decode", charmap_decode, METH_VARARGS}, {"charmap_build", charmap_build, METH_VARARGS}, {"readbuffer_encode", readbuffer_encode, METH_VARARGS}, -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +#ifdef HAVE_MBCS {"mbcs_encode", mbcs_encode, METH_VARARGS}, {"mbcs_decode", mbcs_decode, METH_VARARGS}, #endif diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -43,7 +43,7 @@ #endif /* MS_WINDOWS */ #endif /* !__WATCOMC__ || __QNX__ */ -#if defined(MS_WINDOWS) +#if defined(HAVE_MBCS) # define TZNAME_ENCODING "mbcs" #else # define TZNAME_ENCODING "utf-8" diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1506,7 +1506,7 @@ (strcmp(lower, "latin1") == 0) || (strcmp(lower, "iso-8859-1") == 0)) return PyUnicode_DecodeLatin1(s, size, errors); -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +#ifdef HAVE_MBCS else if (strcmp(lower, "mbcs") == 0) return PyUnicode_DecodeMBCS(s, size, errors); #endif @@ -1644,7 +1644,7 @@ PyObject * PyUnicode_EncodeFSDefault(PyObject *unicode) { -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +#ifdef HAVE_MBCS return PyUnicode_EncodeMBCS(PyUnicode_AS_UNICODE(unicode), PyUnicode_GET_SIZE(unicode), NULL); @@ -1746,7 +1746,7 @@ return PyUnicode_EncodeLatin1(PyUnicode_AS_UNICODE(unicode), PyUnicode_GET_SIZE(unicode), errors); -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +#ifdef HAVE_MBCS else if (strcmp(lower, "mbcs") == 0) return PyUnicode_EncodeMBCS(PyUnicode_AS_UNICODE(unicode), PyUnicode_GET_SIZE(unicode), @@ -1848,7 +1848,7 @@ PyObject* PyUnicode_DecodeFSDefaultAndSize(const char *s, Py_ssize_t size) { -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +#ifdef HAVE_MBCS return PyUnicode_DecodeMBCS(s, size, NULL); #elif defined(__APPLE__) return PyUnicode_DecodeUTF8(s, size, "surrogateescape"); @@ -4942,7 +4942,7 @@ NULL); } -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +#ifdef HAVE_MBCS /* --- MBCS codecs for Windows -------------------------------------------- */ @@ -5229,7 +5229,7 @@ #undef NEED_RETRY -#endif /* MS_WINDOWS */ +#endif /* HAVE_MBCS */ /* --- Character Mapping Codec -------------------------------------------- */ diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -18,7 +18,7 @@ Don't forget to modify PyUnicode_DecodeFSDefault() if you touch any of the values for Py_FileSystemDefaultEncoding! */ -#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +#ifdef HAVE_MBCS const char *Py_FileSystemDefaultEncoding = "mbcs"; int Py_HasFileSystemDefaultEncoding = 1; #elif defined(__APPLE__) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 14:28:50 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 14:28:50 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312452=3A_Plist_and?= =?utf8?q?_Dict_are_now_deprecated?= Message-ID: http://hg.python.org/cpython/rev/4f14050a963f changeset: 71194:4f14050a963f user: Victor Stinner date: Mon Jul 04 14:28:45 2011 +0200 summary: Issue #12452: Plist and Dict are now deprecated Replace PendingDeprecationWarning warnings by DeprecationWarning. files: Lib/plistlib.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/plistlib.py b/Lib/plistlib.py --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -266,13 +266,13 @@ raise AttributeError(attr) from warnings import warn warn("Attribute access from plist dicts is deprecated, use d[key] " - "notation instead", PendingDeprecationWarning, 2) + "notation instead", DeprecationWarning, 2) return value def __setattr__(self, attr, value): from warnings import warn warn("Attribute access from plist dicts is deprecated, use d[key] " - "notation instead", PendingDeprecationWarning, 2) + "notation instead", DeprecationWarning, 2) self[attr] = value def __delattr__(self, attr): @@ -282,14 +282,14 @@ raise AttributeError(attr) from warnings import warn warn("Attribute access from plist dicts is deprecated, use d[key] " - "notation instead", PendingDeprecationWarning, 2) + "notation instead", DeprecationWarning, 2) class Dict(_InternalDict): def __init__(self, **kwargs): from warnings import warn warn("The plistlib.Dict class is deprecated, use builtin dict instead", - PendingDeprecationWarning, 2) + DeprecationWarning, 2) super().__init__(**kwargs) @@ -302,7 +302,7 @@ def __init__(self, **kwargs): from warnings import warn warn("The Plist class is deprecated, use the readPlist() and " - "writePlist() functions instead", PendingDeprecationWarning, 2) + "writePlist() functions instead", DeprecationWarning, 2) super().__init__(**kwargs) def fromFile(cls, pathOrFile): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 17:49:49 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 17:49:49 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDY5?= =?utf8?q?=3A_Run_=22wakeup=22_signal_tests_in_subprocess_to_run_the_test_?= =?utf8?q?in_a?= Message-ID: http://hg.python.org/cpython/rev/e07b331bf489 changeset: 71195:e07b331bf489 branch: 3.2 parent: 71189:e924e51e9447 user: Victor Stinner date: Mon Jul 04 17:35:10 2011 +0200 summary: Issue #12469: Run "wakeup" signal tests in subprocess to run the test in a fresh process with only one thread and to not change signal handling of the parent process. files: Lib/test/test_signal.py | 105 ++++++++++++++++++--------- Misc/NEWS | 4 + 2 files changed, 72 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 @@ -11,7 +11,7 @@ import unittest from test import support from contextlib import closing -from test.script_helper import spawn_python +from test.script_helper import assert_python_ok, spawn_python if sys.platform in ('os2', 'riscos'): raise unittest.SkipTest("Can't test signal on %s" % sys.platform) @@ -233,49 +233,80 @@ @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class WakeupSignalTests(unittest.TestCase): - TIMEOUT_FULL = 10 - TIMEOUT_HALF = 5 + def check_wakeup(self, test_body): + # use a subprocess to have only one thread and to not change signal + # handling of the parent process + code = """if 1: + import fcntl + import os + import signal + + def handler(signum, frame): + pass + + {} + + signal.signal(signal.SIGALRM, handler) + read, write = os.pipe() + flags = fcntl.fcntl(write, fcntl.F_GETFL, 0) + flags = flags | os.O_NONBLOCK + fcntl.fcntl(write, fcntl.F_SETFL, flags) + signal.set_wakeup_fd(write) + + test() + + os.close(read) + os.close(write) + """.format(test_body) + + assert_python_ok('-c', code) def test_wakeup_fd_early(self): - import select + self.check_wakeup("""def test(): + import select + import time - signal.alarm(1) - before_time = time.time() - # We attempt to get a signal during the sleep, - # before select is called - time.sleep(self.TIMEOUT_FULL) - mid_time = time.time() - self.assertTrue(mid_time - before_time < self.TIMEOUT_HALF) - select.select([self.read], [], [], self.TIMEOUT_FULL) - after_time = time.time() - self.assertTrue(after_time - mid_time < self.TIMEOUT_HALF) + TIMEOUT_FULL = 10 + TIMEOUT_HALF = 5 + + signal.alarm(1) + before_time = time.time() + # We attempt to get a signal during the sleep, + # before select is called + time.sleep(TIMEOUT_FULL) + mid_time = time.time() + dt = mid_time - before_time + if dt >= TIMEOUT_HALF: + raise Exception("%s >= %s" % (dt, TIMEOUT_HALF)) + select.select([read], [], [], TIMEOUT_FULL) + after_time = time.time() + dt = after_time - mid_time + if dt >= TIMEOUT_HALF: + raise Exception("%s >= %s" % (dt, TIMEOUT_HALF)) + """) def test_wakeup_fd_during(self): - import select + self.check_wakeup("""def test(): + import select + import time - signal.alarm(1) - before_time = time.time() - # We attempt to get a signal during the select call - self.assertRaises(select.error, select.select, - [self.read], [], [], self.TIMEOUT_FULL) - after_time = time.time() - self.assertTrue(after_time - before_time < self.TIMEOUT_HALF) + TIMEOUT_FULL = 10 + TIMEOUT_HALF = 5 - def setUp(self): - import fcntl - - self.alrm = signal.signal(signal.SIGALRM, lambda x,y:None) - self.read, self.write = os.pipe() - flags = fcntl.fcntl(self.write, fcntl.F_GETFL, 0) - flags = flags | os.O_NONBLOCK - fcntl.fcntl(self.write, fcntl.F_SETFL, flags) - self.old_wakeup = signal.set_wakeup_fd(self.write) - - def tearDown(self): - signal.set_wakeup_fd(self.old_wakeup) - os.close(self.read) - os.close(self.write) - signal.signal(signal.SIGALRM, self.alrm) + signal.alarm(1) + before_time = time.time() + # We attempt to get a signal during the select call + try: + select.select([read], [], [], TIMEOUT_FULL) + except select.error: + pass + else: + raise Exception("select.error not raised") + after_time = time.time() + dt = after_time - before_time + if dt >= TIMEOUT_HALF: + raise Exception("%s >= %s" % (dt, TIMEOUT_HALF)) + """) @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class SiginterruptTest(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,10 @@ Tests ----- +- Issue #12469: Run "wakeup" signal tests in subprocess to run the test in a + fresh process with only one thread and to not change signal handling of the + parent process. + - Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run test_tk or test_ttk_guionly under a username that is not currently logged in to the console windowserver (as may be the case under buildbot or ssh). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 17:49:50 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 17:49:50 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28merge_3=2E2=29_Issue_=2312469=3A_Run_wakeup_and_pending_s?= =?utf8?q?ignal_tests_in_a_subprocess?= Message-ID: http://hg.python.org/cpython/rev/b9de5e55f798 changeset: 71196:b9de5e55f798 parent: 71194:4f14050a963f parent: 71195:e07b331bf489 user: Victor Stinner date: Mon Jul 04 17:49:40 2011 +0200 summary: (merge 3.2) Issue #12469: Run wakeup and pending signal tests in a subprocess to run the test in a fresh process with only one thread and to not change signal handling of the parent process. files: Lib/test/test_signal.py | 496 ++++++++++++++------------- Misc/NEWS | 4 + 2 files changed, 261 insertions(+), 239 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 @@ -224,117 +224,115 @@ @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class WakeupSignalTests(unittest.TestCase): - TIMEOUT_FULL = 10 - TIMEOUT_HALF = 5 + def check_wakeup(self, test_body, *signals): + # use a subprocess to have only one thread + code = """if 1: + import fcntl + import os + import signal + import struct - def handler(self, signum, frame): - pass + signals = {!r} - def check_signum(self, *signals): - data = os.read(self.read, len(signals)+1) - raised = struct.unpack('%uB' % len(data), data) - # We don't care of the signal delivery order (it's not portable or - # reliable) - raised = set(raised) - signals = set(signals) - self.assertEqual(raised, signals) + def handler(signum, frame): + pass + + def check_signum(signals): + data = os.read(read, len(signals)+1) + raised = struct.unpack('%uB' % len(data), data) + # We don't care of the signal delivery order (it's not portable or + # reliable) + raised = set(raised) + signals = set(signals) + assert raised == signals, "%r != %r" % (raised, signals) + + {} + + signal.signal(signal.SIGALRM, handler) + read, write = os.pipe() + for fd in (read, write): + flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0) + flags = flags | os.O_NONBLOCK + fcntl.fcntl(fd, fcntl.F_SETFL, flags) + signal.set_wakeup_fd(write) + + test() + check_signum(signals) + + os.close(read) + os.close(write) + """.format(signals, test_body) + + assert_python_ok('-c', code) def test_wakeup_fd_early(self): - import select + self.check_wakeup("""def test(): + import select + import time - signal.alarm(1) - before_time = time.time() - # We attempt to get a signal during the sleep, - # before select is called - time.sleep(self.TIMEOUT_FULL) - mid_time = time.time() - self.assertTrue(mid_time - before_time < self.TIMEOUT_HALF) - 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) + TIMEOUT_FULL = 10 + TIMEOUT_HALF = 5 + + signal.alarm(1) + before_time = time.time() + # We attempt to get a signal during the sleep, + # before select is called + time.sleep(TIMEOUT_FULL) + mid_time = time.time() + dt = mid_time - before_time + assert dt < TIMEOUT_HALF, dt + select.select([read], [], [], TIMEOUT_FULL) + after_time = time.time() + dt = after_time - mid_time + assert dt < TIMEOUT_HALF, dt + """, signal.SIGALRM) def test_wakeup_fd_during(self): - import select + self.check_wakeup("""def test(): + import select + import time - signal.alarm(1) - before_time = time.time() - # We attempt to get a signal during the select call - self.assertRaises(select.error, select.select, - [self.read], [], [], self.TIMEOUT_FULL) - after_time = time.time() - self.assertTrue(after_time - before_time < self.TIMEOUT_HALF) - self.check_signum(signal.SIGALRM) + TIMEOUT_FULL = 10 + TIMEOUT_HALF = 5 + + signal.alarm(1) + before_time = time.time() + # We attempt to get a signal during the select call + try: + select.select([read], [], [], TIMEOUT_FULL) + except select.error: + pass + else: + raise Exception("select.error not raised") + after_time = time.time() + dt = after_time - before_time + assert dt < TIMEOUT_HALF, dt + """, signal.SIGALRM) def test_signum(self): - old_handler = signal.signal(signal.SIGUSR1, self.handler) - 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) + self.check_wakeup("""def test(): + signal.signal(signal.SIGUSR1, handler) + os.kill(os.getpid(), signal.SIGUSR1) + os.kill(os.getpid(), signal.SIGALRM) + """, signal.SIGUSR1, signal.SIGALRM) @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), 'need signal.pthread_sigmask()') - @unittest.skipUnless(hasattr(signal, 'pthread_kill'), - 'need signal.pthread_kill()') def test_pending(self): - signum1 = signal.SIGUSR1 - signum2 = signal.SIGUSR2 - tid = threading.current_thread().ident + self.check_wakeup("""def test(): + signum1 = signal.SIGUSR1 + signum2 = signal.SIGUSR2 - old_handler = signal.signal(signum1, self.handler) - self.addCleanup(signal.signal, signum1, old_handler) - old_handler = signal.signal(signum2, self.handler) - self.addCleanup(signal.signal, signum2, old_handler) + signal.signal(signum1, handler) + signal.signal(signum2, handler) - signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2)) - signal.pthread_kill(tid, signum1) - signal.pthread_kill(tid, signum2) - # Unblocking the 2 signals calls the C signal handler twice - signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2)) + signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2)) + os.kill(os.getpid(), signum1) + os.kill(os.getpid(), signum2) + # Unblocking the 2 signals calls the C signal handler twice + signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2)) + """, signal.SIGUSR1, signal.SIGUSR2) - self.check_signum(signum1, signum2) - - @unittest.skipUnless(hasattr(signal, 'pthread_kill'), - 'need signal.pthread_kill()') - def test_pthread_kill_main_thread(self): - # Test that a signal can be sent to the main thread with pthread_kill() - # before any other thread has been created (see issue #12392). - code = """if True: - import threading - import signal - import sys - - def handler(signum, frame): - sys.exit(3) - - signal.signal(signal.SIGUSR1, handler) - signal.pthread_kill(threading.get_ident(), signal.SIGUSR1) - sys.exit(1) - """ - - with spawn_python('-c', code) as process: - stdout, stderr = process.communicate() - exitcode = process.wait() - if exitcode != 3: - raise Exception("Child error (exit code %s): %s" % - (exitcode, stdout)) - - def setUp(self): - import fcntl - - self.alrm = signal.signal(signal.SIGALRM, self.handler) - self.read, self.write = os.pipe() - flags = fcntl.fcntl(self.write, fcntl.F_GETFL, 0) - flags = flags | os.O_NONBLOCK - fcntl.fcntl(self.write, fcntl.F_SETFL, flags) - self.old_wakeup = signal.set_wakeup_fd(self.write) - - def tearDown(self): - signal.set_wakeup_fd(self.old_wakeup) - os.close(self.read) - os.close(self.write) - signal.signal(signal.SIGALRM, self.alrm) @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class SiginterruptTest(unittest.TestCase): @@ -519,60 +517,6 @@ 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 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). - - 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. - 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 '_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.get_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): @@ -583,70 +527,103 @@ @unittest.skipUnless(hasattr(signal, 'sigpending'), 'need signal.sigpending()') def test_sigpending(self): - self.can_test_blocked_signals(True) + code = """if 1: + import os + import signal - signum = signal.SIGUSR1 - old_handler = signal.signal(signum, self.handler) - self.addCleanup(signal.signal, signum, old_handler) + def handler(signum, frame): + 1/0 - 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]) + signum = signal.SIGUSR1 + signal.signal(signum, handler) + + signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) + os.kill(os.getpid(), signum) + pending = signal.sigpending() + assert pending == {signum}, '%s != {%s}' % (pending, signum) + try: + signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + except ZeroDivisionError: + pass + else: + raise Exception("ZeroDivisionError not raised") + """ + assert_python_ok('-c', code) @unittest.skipUnless(hasattr(signal, 'pthread_kill'), 'need signal.pthread_kill()') def test_pthread_kill(self): - signum = signal.SIGUSR1 - current = threading.get_ident() + code = """if 1: + import signal + import threading + import sys - old_handler = signal.signal(signum, self.handler) - self.addCleanup(signal.signal, signum, old_handler) + signum = signal.SIGUSR1 - with self.assertRaises(ZeroDivisionError): - signal.pthread_kill(current, signum) + def handler(signum, frame): + 1/0 + + signal.signal(signum, handler) + + if sys.platform == 'freebsd6': + # Issue #12392 and #12469: send a signal to the main thread + # doesn't work before the creation of the first thread on + # FreeBSD 6 + def noop(): + pass + thread = threading.Thread(target=noop) + thread.start() + thread.join() + + tid = threading.get_ident() + try: + signal.pthread_kill(tid, signum) + except ZeroDivisionError: + pass + else: + raise Exception("ZeroDivisionError not raised") + """ + assert_python_ok('-c', code) @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), 'need signal.pthread_sigmask()') - def wait_helper(self, test, blocked): + def wait_helper(self, blocked, test): """ test: body of the "def test(signum):" function. blocked: number of the blocked signal """ - code = ''' -import signal -import sys + code = '''if 1: + import signal + import sys -def handler(signum, frame): - 1/0 + def handler(signum, frame): + 1/0 -def test(signum): -%s + %s -blocked = %s -signum = signal.SIGALRM + blocked = %s + signum = signal.SIGALRM -# child: block and wait the signal -try: - signal.signal(signum, handler) - signal.pthread_sigmask(signal.SIG_BLOCK, [blocked]) + # child: block and wait the signal + try: + signal.signal(signum, handler) + signal.pthread_sigmask(signal.SIG_BLOCK, [blocked]) - # Do the tests - test(signum) + # Do the tests + test(signum) - # The handler must not be called on unblock - try: - signal.pthread_sigmask(signal.SIG_UNBLOCK, [blocked]) - except ZeroDivisionError: - print("the signal handler has been called", - file=sys.stderr) - sys.exit(1) -except BaseException as err: - print("error: {}".format(err), file=sys.stderr) - sys.stderr.flush() - sys.exit(1) -''' % (test, blocked) + # The handler must not be called on unblock + try: + signal.pthread_sigmask(signal.SIG_UNBLOCK, [blocked]) + except ZeroDivisionError: + print("the signal handler has been called", + file=sys.stderr) + sys.exit(1) + except BaseException as err: + print("error: {}".format(err), file=sys.stderr) + sys.stderr.flush() + sys.exit(1) + ''' % (test.strip(), blocked) # sig*wait* must be called with the signal blocked: since the current # process might have several threads running, use a subprocess to have @@ -656,61 +633,56 @@ @unittest.skipUnless(hasattr(signal, 'sigwait'), 'need signal.sigwait()') def test_sigwait(self): - test = ''' + self.wait_helper(signal.SIGALRM, ''' + def test(signum): signal.alarm(1) received = signal.sigwait([signum]) assert received == signum , 'received %s, not %s' % (received, signum) - ''' - - self.wait_helper(test, signal.SIGALRM) + ''') @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'), 'need signal.sigwaitinfo()') def test_sigwaitinfo(self): - test = ''' + self.wait_helper(signal.SIGALRM, ''' + def test(signum): signal.alarm(1) info = signal.sigwaitinfo([signum]) assert info.si_signo == signum, "info.si_signo != %s" % signum - ''' - - self.wait_helper(test, signal.SIGALRM) + ''') @unittest.skipUnless(hasattr(signal, 'sigtimedwait'), 'need signal.sigtimedwait()') def test_sigtimedwait(self): - test = ''' + self.wait_helper(signal.SIGALRM, ''' + def test(signum): signal.alarm(1) info = signal.sigtimedwait([signum], (10, 1000)) assert info.si_signo == signum, 'info.si_signo != %s' % signum - ''' - - self.wait_helper(test, signal.SIGALRM) + ''') @unittest.skipUnless(hasattr(signal, 'sigtimedwait'), 'need signal.sigtimedwait()') # issue #12303: sigtimedwait() takes 30 seconds on FreeBSD 6 (kernel bug) @unittest.skipIf(sys.platform =='freebsd6', - 'sigtimedwait() with a null timeout doens\'t work on FreeBSD 6') + "sigtimedwait() with a null timeout doens't work on FreeBSD 6") def test_sigtimedwait_poll(self): # check that polling with sigtimedwait works - test = ''' + self.wait_helper(signal.SIGALRM, ''' + def test(signum): import os os.kill(os.getpid(), signum) info = signal.sigtimedwait([signum], (0, 0)) assert info.si_signo == signum, 'info.si_signo != %s' % signum - ''' - - self.wait_helper(test, signal.SIGALRM) + ''') @unittest.skipUnless(hasattr(signal, 'sigtimedwait'), 'need signal.sigtimedwait()') def test_sigtimedwait_timeout(self): - test = ''' + self.wait_helper(signal.SIGALRM, ''' + def test(signum): received = signal.sigtimedwait([signum], (1, 0)) assert received is None, "received=%r" % (received,) - ''' - - self.wait_helper(test, signal.SIGALRM) + ''') @unittest.skipUnless(hasattr(signal, 'sigtimedwait'), 'need signal.sigtimedwait()') @@ -723,7 +695,8 @@ @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'), 'need signal.sigwaitinfo()') def test_sigwaitinfo_interrupted(self): - test = ''' + self.wait_helper(signal.SIGUSR1, ''' + def test(signum): import errno hndl_called = True @@ -741,9 +714,7 @@ raise Exception("Expected EINTR to be raised by sigwaitinfo") else: raise Exception("Expected EINTR to be raised by sigwaitinfo") - ''' - - self.wait_helper(test, signal.SIGUSR1) + ''') @unittest.skipUnless(hasattr(signal, 'sigwait'), 'need signal.sigwait()') @@ -791,46 +762,93 @@ @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), 'need signal.pthread_sigmask()') def test_pthread_sigmask(self): - test_blocked_signals = self.can_test_blocked_signals(False) + code = """if 1: + import signal + import os; import threading + + def handler(signum, frame): + 1/0 + + def kill(signum): + os.kill(os.getpid(), signum) + + def read_sigmask(): + return signal.pthread_sigmask(signal.SIG_BLOCK, []) + signum = signal.SIGUSR1 # Install our signal handler - old_handler = signal.signal(signum, self.handler) - self.addCleanup(signal.signal, signum, old_handler) + old_handler = signal.signal(signum, 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) - with self.assertRaises(ZeroDivisionError): - self.kill(signum) + try: + kill(signum) + except ZeroDivisionError: + pass + else: + raise Exception("ZeroDivisionError not raised") # 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 test_blocked_signals: - self.kill(signum) + kill(signum) # Check the new mask - blocked = self.read_sigmask() - self.assertIn(signum, blocked) - self.assertEqual(old_mask ^ blocked, {signum}) + blocked = read_sigmask() + assert signum in blocked, "%s not in %s" % (signum, blocked) + assert old_mask ^ blocked == {signum}, "%s ^ %s != {%s}" % (old_mask, blocked, signum) # Unblock SIGUSR1 - if test_blocked_signals: - with self.assertRaises(ZeroDivisionError): - # unblock the pending signal calls immediatly the signal handler - signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + try: + # unblock the pending signal calls immediatly the signal handler + signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + except ZeroDivisionError: + pass else: - signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) - with self.assertRaises(ZeroDivisionError): - self.kill(signum) + raise Exception("ZeroDivisionError not raised") + try: + kill(signum) + except ZeroDivisionError: + pass + else: + raise Exception("ZeroDivisionError not raised") # Check the new mask - unblocked = self.read_sigmask() - self.assertNotIn(signum, unblocked) - self.assertEqual(blocked ^ unblocked, {signum}) - self.assertSequenceEqual(old_mask, unblocked) - # Finally, restore the previous signal handler and the signal mask + unblocked = read_sigmask() + assert signum not in unblocked, "%s in %s" % (signum, unblocked) + assert blocked ^ unblocked == {signum}, "%s ^ %s != {%s}" % (blocked, unblocked, signum) + assert old_mask == unblocked, "%s != %s" % (old_mask, unblocked) + """ + assert_python_ok('-c', code) + + @unittest.skipIf(sys.platform == 'freebsd6', + "issue #12392: send a signal to the main thread doesn't work " + "before the creation of the first thread on FreeBSD 6") + @unittest.skipUnless(hasattr(signal, 'pthread_kill'), + 'need signal.pthread_kill()') + def test_pthread_kill_main_thread(self): + # Test that a signal can be sent to the main thread with pthread_kill() + # before any other thread has been created (see issue #12392). + code = """if True: + import threading + import signal + import sys + + def handler(signum, frame): + sys.exit(3) + + signal.signal(signal.SIGUSR1, handler) + signal.pthread_kill(threading.get_ident(), signal.SIGUSR1) + sys.exit(2) + """ + + with spawn_python('-c', code) as process: + stdout, stderr = process.communicate() + exitcode = process.wait() + if exitcode != 3: + raise Exception("Child error (exit code %s): %s" % + (exitcode, stdout)) def test_main(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -981,6 +981,10 @@ Tests ----- +- Issue #12469: Run wakeup and pending signal tests in a subprocess to run the + test in a fresh process with only one thread and to not change signal + handling of the parent process. + - Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run test_tk or test_ttk_guionly under a username that is not currently logged in to the console windowserver (as may be the case under buildbot or ssh). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 18:06:53 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 18:06:53 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312469=3A_replace_a?= =?utf8?q?ssertions_by_explicit_if+raise?= Message-ID: http://hg.python.org/cpython/rev/7eef821ab20d changeset: 71197:7eef821ab20d user: Victor Stinner date: Mon Jul 04 18:06:35 2011 +0200 summary: Issue #12469: replace assertions by explicit if+raise files: Lib/test/test_signal.py | 48 +++++++++++++++++++--------- 1 files changed, 32 insertions(+), 16 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 @@ -244,7 +244,8 @@ # reliable) raised = set(raised) signals = set(signals) - assert raised == signals, "%r != %r" % (raised, signals) + if raised != signals: + raise Exception("%r != %r" % (raised, signals)) {} @@ -280,11 +281,13 @@ time.sleep(TIMEOUT_FULL) mid_time = time.time() dt = mid_time - before_time - assert dt < TIMEOUT_HALF, dt + if dt >= TIMEOUT_HALF: + raise Exception("%s >= %s" % (dt, TIMEOUT_HALF)) select.select([read], [], [], TIMEOUT_FULL) after_time = time.time() dt = after_time - mid_time - assert dt < TIMEOUT_HALF, dt + if dt >= TIMEOUT_HALF: + raise Exception("%s >= %s" % (dt, TIMEOUT_HALF)) """, signal.SIGALRM) def test_wakeup_fd_during(self): @@ -306,7 +309,8 @@ raise Exception("select.error not raised") after_time = time.time() dt = after_time - before_time - assert dt < TIMEOUT_HALF, dt + if dt >= TIMEOUT_HALF: + raise Exception("%s >= %s" % (dt, TIMEOUT_HALF)) """, signal.SIGALRM) def test_signum(self): @@ -540,7 +544,8 @@ signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) os.kill(os.getpid(), signum) pending = signal.sigpending() - assert pending == {signum}, '%s != {%s}' % (pending, signum) + if pending != {signum}: + raise Exception('%s != {%s}' % (pending, signum)) try: signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) except ZeroDivisionError: @@ -637,7 +642,8 @@ def test(signum): signal.alarm(1) received = signal.sigwait([signum]) - assert received == signum , 'received %s, not %s' % (received, signum) + if received != signum: + raise Exception('received %s, not %s' % (received, signum)) ''') @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'), @@ -647,7 +653,8 @@ def test(signum): signal.alarm(1) info = signal.sigwaitinfo([signum]) - assert info.si_signo == signum, "info.si_signo != %s" % signum + if info.si_signo != signum: + raise Exception("info.si_signo != %s" % signum) ''') @unittest.skipUnless(hasattr(signal, 'sigtimedwait'), @@ -657,7 +664,8 @@ def test(signum): signal.alarm(1) info = signal.sigtimedwait([signum], (10, 1000)) - assert info.si_signo == signum, 'info.si_signo != %s' % signum + if info.si_signo != signum: + raise Exception('info.si_signo != %s' % signum) ''') @unittest.skipUnless(hasattr(signal, 'sigtimedwait'), @@ -672,7 +680,8 @@ import os os.kill(os.getpid(), signum) info = signal.sigtimedwait([signum], (0, 0)) - assert info.si_signo == signum, 'info.si_signo != %s' % signum + if info.si_signo != signum: + raise Exception('info.si_signo != %s' % signum) ''') @unittest.skipUnless(hasattr(signal, 'sigtimedwait'), @@ -681,7 +690,8 @@ self.wait_helper(signal.SIGALRM, ''' def test(signum): received = signal.sigtimedwait([signum], (1, 0)) - assert received is None, "received=%r" % (received,) + if received is not None: + raise Exception("received=%r" % (received,)) ''') @unittest.skipUnless(hasattr(signal, 'sigtimedwait'), @@ -709,7 +719,8 @@ signal.sigwaitinfo([signal.SIGUSR1]) except OSError as e: if e.errno == errno.EINTR: - assert hndl_called, "SIGALRM handler not called" + if not hndl_called: + raise Exception("SIGALRM handler not called") else: raise Exception("Expected EINTR to be raised by sigwaitinfo") else: @@ -796,8 +807,10 @@ # Check the new mask blocked = read_sigmask() - assert signum in blocked, "%s not in %s" % (signum, blocked) - assert old_mask ^ blocked == {signum}, "%s ^ %s != {%s}" % (old_mask, blocked, signum) + if signum not in blocked: + raise Exception("%s not in %s" % (signum, blocked)) + if old_mask ^ blocked != {signum}: + raise Exception("%s ^ %s != {%s}" % (old_mask, blocked, signum)) # Unblock SIGUSR1 try: @@ -816,9 +829,12 @@ # Check the new mask unblocked = read_sigmask() - assert signum not in unblocked, "%s in %s" % (signum, unblocked) - assert blocked ^ unblocked == {signum}, "%s ^ %s != {%s}" % (blocked, unblocked, signum) - assert old_mask == unblocked, "%s != %s" % (old_mask, unblocked) + if signum in unblocked: + raise Exception("%s in %s" % (signum, unblocked)) + if blocked ^ unblocked != {signum}: + raise Exception("%s ^ %s != {%s}" % (blocked, unblocked, signum)) + if old_mask != unblocked: + raise Exception("%s != %s" % (old_mask, unblocked)) """ assert_python_ok('-c', code) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:54:51 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:54:51 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_target_path?= =?utf8?q?_in_message=2E?= Message-ID: http://hg.python.org/cpython/rev/8acdaf766644 changeset: 71198:8acdaf766644 branch: 3.2 parent: 71141:2a3563bc9fcb user: Georg Brandl date: Sun Jul 03 09:30:42 2011 +0200 summary: Fix target path in message. files: Doc/Makefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -113,7 +113,7 @@ pydoc-topics: BUILDER = pydoc-topics pydoc-topics: build @echo "Building finished; now copy build/pydoc-topics/topics.py" \ - "to Lib/pydoc_data/topics.py" + "to ../Lib/pydoc_data/topics.py" htmlview: html $(PYTHON) -c "import webbrowser; webbrowser.open('build/html/index.html')" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:54:51 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:54:51 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Update_pydoc_to?= =?utf8?q?pics=2E?= Message-ID: http://hg.python.org/cpython/rev/1cf59e5149ca changeset: 71199:1cf59e5149ca branch: 3.2 user: Georg Brandl date: Sun Jul 03 09:31:04 2011 +0200 summary: Update pydoc topics. files: Lib/pydoc_data/topics.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) 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 Sun May 15 17:48:55 2011 +# Autogenerated by Sphinx on Sun Jul 3 09:27:35 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', @@ -16,9 +16,9 @@ 'break': '\nThe ``break`` statement\n***********************\n\n break_stmt ::= "break"\n\n``break`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition\nwithin that loop.\n\nIt terminates the nearest enclosing loop, skipping the optional\n``else`` clause if the loop has one.\n\nIf a ``for`` loop is terminated by ``break``, the loop control target\nkeeps its current value.\n\nWhen ``break`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the loop.\n', 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n', 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to a sequence. Elements from this\nsequence are treated as if they were additional positional arguments;\nif there are positional arguments *x1*,..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', 'continue': '\nThe ``continue`` statement\n**************************\n\n continue_stmt ::= "continue"\n\n``continue`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition or\n``finally`` clause within that loop. It continues with the next cycle\nof the nearest enclosing loop.\n\nWhen ``continue`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nstarting the next loop cycle.\n', 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the other\n is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:54:52 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:54:52 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_bad_markup?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/13c9b93e97ad changeset: 71200:13c9b93e97ad branch: 3.2 user: Georg Brandl date: Sun Jul 03 09:39:49 2011 +0200 summary: Fix bad markup. files: Doc/library/curses.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -566,7 +566,7 @@ Instantiate the string *str* with the supplied parameters, where *str* should be a parameterized string obtained from the terminfo database. E.g. - ``tparm(tigetstr("cup"), 5, 3)`` could result in x``'\033[6;4H'``, the exact + ``tparm(tigetstr("cup"), 5, 3)`` could result in ``'\033[6;4H'``, the exact result depending on terminal type. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:54:54 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:54:54 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogQnVtcCB0byAzLjIu?= =?utf8?q?1rc2=2E?= Message-ID: http://hg.python.org/cpython/rev/4360a6c70205 changeset: 71201:4360a6c70205 branch: 3.2 user: Georg Brandl date: Sun Jul 03 09:41:27 2011 +0200 summary: Bump to 3.2.1rc2. files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 2 +- Misc/RPM/python-3.2.spec | 2 +- README | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 2 #define PY_MICRO_VERSION 1 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.2.1rc1+" +#define PY_VERSION "3.2.1rc2" /*--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.1rc1" +__version__ = "3.2.1rc2" #--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.1rc1" +IDLE_VERSION = "3.2.1rc2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,7 +5,7 @@ What's New in Python 3.2.1 release candidate 2? =============================================== -*Release date: XX-XXX-2011* +*Release date: 03-Jul-2011* Core and Builtins ----------------- 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.1rc1 +%define version 3.2.1rc2 %define libvers 3.2 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.2.1 release candidate 1 +This is Python version 3.2.1 release candidate 2 ================================================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:54:54 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:54:54 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogTkVXUyByZXdyYXAu?= Message-ID: http://hg.python.org/cpython/rev/5df549718fb4 changeset: 71202:5df549718fb4 branch: 3.2 tag: v3.2.1rc2 user: Georg Brandl date: Sun Jul 03 09:42:43 2011 +0200 summary: NEWS rewrap. files: Misc/NEWS | 67 +++++++++++++++++++++--------------------- 1 files changed, 33 insertions(+), 34 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,8 +10,8 @@ Core and Builtins ----------------- -- Issue #12291: You can now load multiple marshalled objects from a stream, - with other data interleaved between marshalled objects. +- Issue #12291: You can now load multiple marshalled objects from a stream, with + other data interleaved between marshalled objects. - Issue #12084: os.stat on Windows now works properly with relative symbolic links when called from any directory. @@ -20,30 +20,29 @@ the following case: sys.stdin.read() stopped with CTRL+d (end of file), raw_input() interrupted by CTRL+c. -- Issue #9670: Increase the default stack size for secondary threads on - Mac OS X and FreeBSD to reduce the chances of a crash instead of a - "maximum recursion depth" RuntimeError exception. - (patch by Ronald Oussoren) +- Issue #9670: Increase the default stack size for secondary threads on Mac OS X + and FreeBSD to reduce the chances of a crash instead of a "maximum recursion + depth" RuntimeError exception (patch by Ronald Oussoren). Library ------- - Issue #12147: Adjust the new-in-3.2 smtplib.send_message method for better - conformance to the RFCs: correctly handle Sender and Resent- headers. + conformance to the RFCs: correctly handle Sender and Resent headers. - Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. - Issue #12451: The XInclude default loader of xml.etree now decodes files from UTF-8 instead of the locale encoding if the encoding is not specified. It now - also opens XML files for the parser in binary mode instead of the text mode + also opens XML files for the parser in binary mode instead of the text mode to + avoid encoding issues. + +- Issue #12451: doctest.debug_script() doesn't create a temporary file anymore to avoid encoding issues. -- Issue #12451: doctest.debug_script() doesn't create a temporary file - anymore to avoid encoding issues. - -- Issue #12451: pydoc.synopsis() now reads the encoding cookie if available, - to read the Python script from the right encoding. +- Issue #12451: pydoc.synopsis() now reads the encoding cookie if available, to + read the Python script from the right encoding. - Issue #12451: distutils now opens the setup script in binary mode to read the encoding cookie, instead of opening it in UTF-8. @@ -65,9 +64,9 @@ - Issue #12383: Fix subprocess module with env={}: don't copy the environment variables, start with an empty environment. -- Issue #11584: email.header.decode_header no longer fails if the header - passed to it is a Header object, and Header/make_header no longer fail - if given binary unknown-8bit input. +- Issue #11584: email.header.decode_header no longer fails if the header passed + to it is a Header object, and Header/make_header no longer fail if given + binary unknown-8bit input. - Issue #11700: mailbox proxy object close methods can now be called multiple times without error. @@ -99,8 +98,8 @@ constructor has failed, e.g. because of an undeclared keyword argument. Patch written by Oleg Oshmyan. -- Issue #985064: Make plistlib more resilient to faulty input plists. - Patch by Mher Movsisyan. +- Issue #985064: Make plistlib more resilient to faulty input plists. Patch by + Mher Movsisyan. - Issue #12175: RawIOBase.readall() now returns None if read() returns None. @@ -134,13 +133,13 @@ ----- - Issue #8746: Correct faulty configure checks so that os.chflags() and - os.lchflags() are once again built on systems that support these - functions (*BSD and OS X). Also add new stat file flags for OS X - (UF_HIDDEN and UF_COMPRESSED). - -- Issue #11217: For 64-bit/32-bit Mac OS X universal framework builds, - ensure "make install" creates symlinks in --prefix bin for the "-32" - files in the framework bin directory like the installer does. + os.lchflags() are once again built on systems that support these functions + (*BSD and OS X). Also add new stat file flags for OS X (UF_HIDDEN and + UF_COMPRESSED). + +- Issue #11217: For 64-bit/32-bit Mac OS X universal framework builds, ensure + "make install" creates symlinks in --prefix bin for the "-32" files in the + framework bin directory like the installer does. Tests ----- @@ -151,15 +150,15 @@ the output and displays it on failure instead. regrtest -v doesn't print the error twice anymore if there is only one error. -- Issue #12141: Install a copy of template C module file so that - test_build_ext of test_distutils is no longer silently skipped when - run outside of a build directory. - -- Issue #8746: Add additional tests for os.chflags() and os.lchflags(). - Patch by Garrett Cooper. - -- Issue #10736: Fix test_ttk test_widgets failures with Cocoa Tk 8.5.9 - on Mac OS X. (Patch by Ronald Oussoren) +- Issue #12141: Install a copy of template C module file so that test_build_ext + of test_distutils is no longer silently skipped when run outside of a build + directory. + +- Issue #8746: Add additional tests for os.chflags() and os.lchflags(). Patch + by Garrett Cooper. + +- Issue #10736: Fix test_ttk test_widgets failures with Cocoa Tk 8.5.9 on Mac + OS X. (Patch by Ronald Oussoren) - Issue #12057: Add tests for ISO 2022 codecs (iso2022_jp, iso2022_jp_2, iso2022_kr). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:54:55 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:54:55 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Added_tag_v3=2E?= =?utf8?q?2=2E1rc2_for_changeset_5df549718fb4?= Message-ID: http://hg.python.org/cpython/rev/788fa7533c95 changeset: 71203:788fa7533c95 branch: 3.2 user: Georg Brandl date: Sun Jul 03 11:54:09 2011 +0200 summary: Added tag v3.2.1rc2 for changeset 5df549718fb4 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -89,3 +89,4 @@ a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 cfa9364997c7f2e67b9cbb45c3a5fa3bba4e4999 v3.2.1rc1 +5df549718fb4841ff521fe051f6b54f290fad5d8 v3.2.1rc2 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:54:56 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:54:56 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Post-release_st?= =?utf8?q?eps=2E?= Message-ID: http://hg.python.org/cpython/rev/a8ebea1da4d8 changeset: 71204:a8ebea1da4d8 branch: 3.2 user: Georg Brandl date: Mon Jul 04 08:20:48 2011 +0200 summary: Post-release steps. files: Include/patchlevel.h | 2 +- Misc/NEWS | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.2.1rc2" +#define PY_VERSION "3.2.1rc2+" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,18 @@ Python News +++++++++++ +What's New in Python 3.2.1? +=========================== + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.2.1 release candidate 2? =============================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:54:56 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:54:56 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDY3?= =?utf8?q?=3A_warnings=3A_fix_a_race_condition_if_a_warning_is_emitted_at?= Message-ID: http://hg.python.org/cpython/rev/861b483e88d9 changeset: 71205:861b483e88d9 branch: 3.2 user: Victor Stinner date: Mon Jul 04 02:43:09 2011 +0200 summary: Issue #12467: warnings: fix a race condition if a warning is emitted at shutdown, if globals()['__file__'] is None. files: Lib/test/test_warnings.py | 12 ++++++++++++ Misc/NEWS | 3 +++ Python/_warnings.c | 2 +- 3 files changed, 16 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -542,6 +542,18 @@ assert expected_line self.assertEqual(second_line, expected_line) + def test_filename_none(self): + # issue #12467: race condition if a warning is emitted at shutdown + globals_dict = globals() + oldfile = globals_dict['__file__'] + try: + with original_warnings.catch_warnings(module=self.module) as w: + self.module.filterwarnings("always", category=UserWarning) + globals_dict['__file__'] = None + original_warnings.warn('test', UserWarning) + finally: + globals_dict['__file__'] = oldfile + class WarningsDisplayTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #12467: warnings: fix a race condition if a warning is emitted at + shutdown, if globals()['__file__'] is None. + What's New in Python 3.2.1 release candidate 2? =============================================== diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -496,7 +496,7 @@ /* Setup filename. */ *filename = PyDict_GetItemString(globals, "__file__"); - if (*filename != NULL) { + if (*filename != NULL && PyUnicode_Check(*filename)) { Py_ssize_t len = PyUnicode_GetSize(*filename); Py_UNICODE *unicode = PyUnicode_AS_UNICODE(*filename); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:54:58 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:54:58 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_Merge_3=2E2=2E1_release_clone_changes_into_main_3=2E2_branch_af?= =?utf8?q?ter_3=2E2=2E1rc2_release=2E?= Message-ID: http://hg.python.org/cpython/rev/ab22ffd905b3 changeset: 71206:ab22ffd905b3 branch: 3.2 parent: 71195:e07b331bf489 parent: 71205:861b483e88d9 user: Georg Brandl date: Mon Jul 04 19:55:22 2011 +0200 summary: Merge 3.2.1 release clone changes into main 3.2 branch after 3.2.1rc2 release. files: .hgtags | 1 + Doc/Makefile | 2 +- Doc/library/curses.rst | 2 +- Include/patchlevel.h | 4 +- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Lib/pydoc_data/topics.py | 6 +- Misc/NEWS | 84 +++++++++++++++----------- Misc/RPM/python-3.2.spec | 2 +- README | 2 +- 10 files changed, 61 insertions(+), 46 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -89,3 +89,4 @@ a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 cfa9364997c7f2e67b9cbb45c3a5fa3bba4e4999 v3.2.1rc1 +5df549718fb4841ff521fe051f6b54f290fad5d8 v3.2.1rc2 diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -113,7 +113,7 @@ pydoc-topics: BUILDER = pydoc-topics pydoc-topics: build @echo "Building finished; now copy build/pydoc-topics/topics.py" \ - "to Lib/pydoc_data/topics.py" + "to ../Lib/pydoc_data/topics.py" htmlview: html $(PYTHON) -c "import webbrowser; webbrowser.open('build/html/index.html')" diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -566,7 +566,7 @@ Instantiate the string *str* with the supplied parameters, where *str* should be a parameterized string obtained from the terminfo database. E.g. - ``tparm(tigetstr("cup"), 5, 3)`` could result in x``'\033[6;4H'``, the exact + ``tparm(tigetstr("cup"), 5, 3)`` could result in ``'\033[6;4H'``, the exact result depending on terminal type. diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 2 #define PY_MICRO_VERSION 1 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.2.1rc1+" +#define PY_VERSION "3.2.1rc2+" /*--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.1rc1" +__version__ = "3.2.1rc2" #--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.1rc1" +IDLE_VERSION = "3.2.1rc2" 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 Sun May 15 17:48:55 2011 +# Autogenerated by Sphinx on Sun Jul 3 09:27:35 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', @@ -16,9 +16,9 @@ 'break': '\nThe ``break`` statement\n***********************\n\n break_stmt ::= "break"\n\n``break`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition\nwithin that loop.\n\nIt terminates the nearest enclosing loop, skipping the optional\n``else`` clause if the loop has one.\n\nIf a ``for`` loop is terminated by ``break``, the loop control target\nkeeps its current value.\n\nWhen ``break`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the loop.\n', 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n', 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to a sequence. Elements from this\nsequence are treated as if they were additional positional arguments;\nif there are positional arguments *x1*,..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', 'continue': '\nThe ``continue`` statement\n**************************\n\n continue_stmt ::= "continue"\n\n``continue`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition or\n``finally`` clause within that loop. It continues with the next cycle\nof the nearest enclosing loop.\n\nWhen ``continue`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nstarting the next loop cycle.\n', 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the other\n is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,16 +47,31 @@ in to the console windowserver (as may be the case under buildbot or ssh). +What's New in Python 3.2.1? +=========================== + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +Library +------- + +- Issue #12467: warnings: fix a race condition if a warning is emitted at + shutdown, if globals()['__file__'] is None. + + What's New in Python 3.2.1 release candidate 2? =============================================== -*Release date: XX-XXX-2011* +*Release date: 03-Jul-2011* Core and Builtins ----------------- -- Issue #12291: You can now load multiple marshalled objects from a stream, - with other data interleaved between marshalled objects. +- Issue #12291: You can now load multiple marshalled objects from a stream, with + other data interleaved between marshalled objects. - Issue #12084: os.stat on Windows now works properly with relative symbolic links when called from any directory. @@ -65,30 +80,29 @@ the following case: sys.stdin.read() stopped with CTRL+d (end of file), raw_input() interrupted by CTRL+c. -- Issue #9670: Increase the default stack size for secondary threads on - Mac OS X and FreeBSD to reduce the chances of a crash instead of a - "maximum recursion depth" RuntimeError exception. - (patch by Ronald Oussoren) +- Issue #9670: Increase the default stack size for secondary threads on Mac OS X + and FreeBSD to reduce the chances of a crash instead of a "maximum recursion + depth" RuntimeError exception (patch by Ronald Oussoren). Library ------- - Issue #12147: Adjust the new-in-3.2 smtplib.send_message method for better - conformance to the RFCs: correctly handle Sender and Resent- headers. + conformance to the RFCs: correctly handle Sender and Resent headers. - Issue #12352: Fix a deadlock in multiprocessing.Heap when a block is freed by the garbage collector while the Heap lock is held. - Issue #12451: The XInclude default loader of xml.etree now decodes files from UTF-8 instead of the locale encoding if the encoding is not specified. It now - also opens XML files for the parser in binary mode instead of the text mode + also opens XML files for the parser in binary mode instead of the text mode to + avoid encoding issues. + +- Issue #12451: doctest.debug_script() doesn't create a temporary file anymore to avoid encoding issues. -- Issue #12451: doctest.debug_script() doesn't create a temporary file - anymore to avoid encoding issues. - -- Issue #12451: pydoc.synopsis() now reads the encoding cookie if available, - to read the Python script from the right encoding. +- Issue #12451: pydoc.synopsis() now reads the encoding cookie if available, to + read the Python script from the right encoding. - Issue #12451: distutils now opens the setup script in binary mode to read the encoding cookie, instead of opening it in UTF-8. @@ -110,9 +124,9 @@ - Issue #12383: Fix subprocess module with env={}: don't copy the environment variables, start with an empty environment. -- Issue #11584: email.header.decode_header no longer fails if the header - passed to it is a Header object, and Header/make_header no longer fail - if given binary unknown-8bit input. +- Issue #11584: email.header.decode_header no longer fails if the header passed + to it is a Header object, and Header/make_header no longer fail if given + binary unknown-8bit input. - Issue #11700: mailbox proxy object close methods can now be called multiple times without error. @@ -144,8 +158,8 @@ constructor has failed, e.g. because of an undeclared keyword argument. Patch written by Oleg Oshmyan. -- Issue #985064: Make plistlib more resilient to faulty input plists. - Patch by Mher Movsisyan. +- Issue #985064: Make plistlib more resilient to faulty input plists. Patch by + Mher Movsisyan. - Issue #12175: RawIOBase.readall() now returns None if read() returns None. @@ -179,13 +193,13 @@ ----- - Issue #8746: Correct faulty configure checks so that os.chflags() and - os.lchflags() are once again built on systems that support these - functions (*BSD and OS X). Also add new stat file flags for OS X - (UF_HIDDEN and UF_COMPRESSED). - -- Issue #11217: For 64-bit/32-bit Mac OS X universal framework builds, - ensure "make install" creates symlinks in --prefix bin for the "-32" - files in the framework bin directory like the installer does. + os.lchflags() are once again built on systems that support these functions + (*BSD and OS X). Also add new stat file flags for OS X (UF_HIDDEN and + UF_COMPRESSED). + +- Issue #11217: For 64-bit/32-bit Mac OS X universal framework builds, ensure + "make install" creates symlinks in --prefix bin for the "-32" files in the + framework bin directory like the installer does. Tests ----- @@ -196,15 +210,15 @@ the output and displays it on failure instead. regrtest -v doesn't print the error twice anymore if there is only one error. -- Issue #12141: Install a copy of template C module file so that - test_build_ext of test_distutils is no longer silently skipped when - run outside of a build directory. - -- Issue #8746: Add additional tests for os.chflags() and os.lchflags(). - Patch by Garrett Cooper. - -- Issue #10736: Fix test_ttk test_widgets failures with Cocoa Tk 8.5.9 - on Mac OS X. (Patch by Ronald Oussoren) +- Issue #12141: Install a copy of template C module file so that test_build_ext + of test_distutils is no longer silently skipped when run outside of a build + directory. + +- Issue #8746: Add additional tests for os.chflags() and os.lchflags(). Patch + by Garrett Cooper. + +- Issue #10736: Fix test_ttk test_widgets failures with Cocoa Tk 8.5.9 on Mac + OS X. (Patch by Ronald Oussoren) - Issue #12057: Add tests for ISO 2022 codecs (iso2022_jp, iso2022_jp_2, iso2022_kr). 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.1rc1 +%define version 3.2.1rc2 %define libvers 3.2 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.2.1 release candidate 1 +This is Python version 3.2.1 release candidate 2 ================================================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 19:57:39 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 04 Jul 2011 19:57:39 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_with_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/24297278c78d changeset: 71207:24297278c78d parent: 71197:7eef821ab20d parent: 71206:ab22ffd905b3 user: Georg Brandl date: Mon Jul 04 19:58:12 2011 +0200 summary: Merge with 3.2. files: .hgtags | 1 + Doc/Makefile | 2 +- Doc/library/curses.rst | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -89,3 +89,4 @@ a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 cfa9364997c7f2e67b9cbb45c3a5fa3bba4e4999 v3.2.1rc1 +5df549718fb4841ff521fe051f6b54f290fad5d8 v3.2.1rc2 diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -113,7 +113,7 @@ pydoc-topics: BUILDER = pydoc-topics pydoc-topics: build @echo "Building finished; now copy build/pydoc-topics/topics.py" \ - "to Lib/pydoc_data/topics.py" + "to ../Lib/pydoc_data/topics.py" htmlview: html $(PYTHON) -c "import webbrowser; webbrowser.open('build/html/index.html')" diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -566,7 +566,7 @@ Instantiate the string *str* with the supplied parameters, where *str* should be a parameterized string obtained from the terminfo database. E.g. - ``tparm(tigetstr("cup"), 5, 3)`` could result in x``'\033[6;4H'``, the exact + ``tparm(tigetstr("cup"), 5, 3)`` could result in ``'\033[6;4H'``, the exact result depending on terminal type. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 20:44:31 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 20:44:31 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_issue10403_-_Le?= =?utf8?q?t=27s_not_use_members_anymore=2E_Use_=27attribute=27_where_it_de?= =?utf8?q?notes?= Message-ID: http://hg.python.org/cpython/rev/d442c313536b changeset: 71208:d442c313536b branch: 3.2 parent: 71206:ab22ffd905b3 user: Senthil Kumaran date: Mon Jul 04 11:28:30 2011 -0700 summary: issue10403 - Let's not use members anymore. Use 'attribute' where it denotes attribute and 'methods' where it denotes methods. Context should clarify usage. files: Doc/library/cmd.rst | 2 +- Doc/library/curses.rst | 4 +- Doc/library/datetime.rst | 133 ++++++++++---------- Doc/library/decimal.rst | 2 +- Doc/library/doctest.rst | 19 +- Doc/library/gzip.rst | 2 +- Doc/library/html.entities.rst | 2 +- Doc/library/http.cookies.rst | 2 +- Doc/library/io.rst | 4 +- Doc/library/nntplib.rst | 2 +- Doc/library/os.rst | 11 +- Doc/library/pyclbr.rst | 4 +- Doc/library/reprlib.rst | 2 +- Doc/library/shlex.rst | 12 +- Doc/library/socketserver.rst | 2 +- Doc/library/stdtypes.rst | 2 +- Doc/library/subprocess.rst | 29 ++-- Doc/library/tempfile.rst | 4 +- Doc/library/urllib.request.rst | 4 +- Doc/library/xdrlib.rst | 2 +- Doc/library/xmlrpc.client.rst | 6 +- Doc/whatsnew/2.5.rst | 2 +- 22 files changed, 127 insertions(+), 125 deletions(-) diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst --- a/Doc/library/cmd.rst +++ b/Doc/library/cmd.rst @@ -50,7 +50,7 @@ the line as argument. The optional argument is a banner or intro string to be issued before the first - prompt (this overrides the :attr:`intro` class member). + prompt (this overrides the :attr:`intro` class attribute). If the :mod:`readline` module is loaded, input will automatically inherit :program:`bash`\ -like history-list editing (e.g. :kbd:`Control-P` scrolls back diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1639,7 +1639,7 @@ each keystroke entered with the keystroke as a parameter; command dispatch is done on the result. This method returns the window contents as a string; whether blanks in the window are included is affected by the - :attr:`stripspaces` member. + :attr:`stripspaces` attribute. .. method:: do_command(ch) @@ -1711,7 +1711,7 @@ .. attribute:: stripspaces - This data member is a flag which controls the interpretation of blanks in + This attribute is a flag which controls the interpretation of blanks in the window. When it is on, trailing blanks on each line are ignored; any cursor motion that would land the cursor on a trailing blank goes to the end of that line instead, and trailing blanks are stripped when the window diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -11,7 +11,7 @@ The :mod:`datetime` module supplies classes for manipulating dates and times in both simple and complex ways. While date and time arithmetic is supported, the -focus of the implementation is on efficient member extraction for output +focus of the implementation is on efficient attribute extraction for output formatting and manipulation. For related functionality, see also the :mod:`time` and :mod:`calendar` modules. @@ -25,7 +25,7 @@ work with, at the cost of ignoring some aspects of reality. For applications requiring more, :class:`datetime` and :class:`time` objects -have an optional time zone information member, :attr:`tzinfo`, that can contain +have an optional time zone information attribute, :attr:`tzinfo`, that can contain an instance of a subclass of the abstract :class:`tzinfo` class. These :class:`tzinfo` objects capture information about the offset from UTC time, the time zone name, and whether Daylight Saving Time is in effect. Note that only @@ -499,9 +499,9 @@ .. method:: date.replace(year, month, day) - Return a date with the same value, except for those members given new values by - whichever keyword arguments are specified. For example, if ``d == date(2002, - 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. + Return a date with the same value, except for those parameters given new + values by whichever keyword arguments are specified. For example, if ``d == + date(2002, 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. .. method:: date.timetuple() @@ -732,11 +732,11 @@ .. classmethod:: datetime.combine(date, time) - Return a new :class:`datetime` object whose date members are equal to the given - :class:`date` object's, and whose time and :attr:`tzinfo` members are equal to - the given :class:`time` object's. For any :class:`datetime` object *d*, ``d == - datetime.combine(d.date(), d.timetz())``. If date is a :class:`datetime` - object, its time and :attr:`tzinfo` members are ignored. + Return a new :class:`datetime` object whose date attributes are equal to the + given :class:`date` object's, and whose time and :attr:`tzinfo` attributes are + equal to the given :class:`time` object's. For any :class:`datetime` object + *d*, ``d == datetime.combine(d.date(), d.timetz())``. If date is a + :class:`datetime` object, its time and :attr:`tzinfo` attributes are ignored. .. classmethod:: datetime.strptime(date_string, format) @@ -830,43 +830,44 @@ (1) datetime2 is a duration of timedelta removed from datetime1, moving forward in time if ``timedelta.days`` > 0, or backward if ``timedelta.days`` < 0. The - result has the same :attr:`tzinfo` member as the input datetime, and datetime2 - - datetime1 == timedelta after. :exc:`OverflowError` is raised if datetime2.year - would be smaller than :const:`MINYEAR` or larger than :const:`MAXYEAR`. Note - that no time zone adjustments are done even if the input is an aware object. + result has the same :attr:`tzinfo` attribute as the input datetime, and + datetime2 - datetime1 == timedelta after. :exc:`OverflowError` is raised if + datetime2.year would be smaller than :const:`MINYEAR` or larger than + :const:`MAXYEAR`. Note that no time zone adjustments are done even if the + input is an aware object. (2) Computes the datetime2 such that datetime2 + timedelta == datetime1. As for - addition, the result has the same :attr:`tzinfo` member as the input datetime, - and no time zone adjustments are done even if the input is aware. This isn't - quite equivalent to datetime1 + (-timedelta), because -timedelta in isolation - can overflow in cases where datetime1 - timedelta does not. + addition, the result has the same :attr:`tzinfo` attribute as the input + datetime, and no time zone adjustments are done even if the input is aware. + This isn't quite equivalent to datetime1 + (-timedelta), because -timedelta + in isolation can overflow in cases where datetime1 - timedelta does not. (3) Subtraction of a :class:`datetime` from a :class:`datetime` is defined only if both operands are naive, or if both are aware. If one is aware and the other is naive, :exc:`TypeError` is raised. - If both are naive, or both are aware and have the same :attr:`tzinfo` member, - the :attr:`tzinfo` members are ignored, and the result is a :class:`timedelta` + If both are naive, or both are aware and have the same :attr:`tzinfo` attribute, + the :attr:`tzinfo` attributes are ignored, and the result is a :class:`timedelta` object *t* such that ``datetime2 + t == datetime1``. No time zone adjustments are done in this case. - If both are aware and have different :attr:`tzinfo` members, ``a-b`` acts as if - *a* and *b* were first converted to naive UTC datetimes first. The result is - ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - - b.utcoffset())`` except that the implementation never overflows. + If both are aware and have different :attr:`tzinfo` attributes, ``a-b`` acts + as if *a* and *b* were first converted to naive UTC datetimes first. The + result is ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) + - b.utcoffset())`` except that the implementation never overflows. (4) *datetime1* is considered less than *datetime2* when *datetime1* precedes *datetime2* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. - If both comparands are aware, and have the same :attr:`tzinfo` member, the - common :attr:`tzinfo` member is ignored and the base datetimes are compared. If - both comparands are aware and have different :attr:`tzinfo` members, the - comparands are first adjusted by subtracting their UTC offsets (obtained from - ``self.utcoffset()``). + If both comparands are aware, and have the same :attr:`tzinfo` attribute, the + common :attr:`tzinfo` attribute is ignored and the base datetimes are + compared. If both comparands are aware and have different :attr:`tzinfo` + attributes, the comparands are first adjusted by subtracting their UTC + offsets (obtained from ``self.utcoffset()``). .. note:: @@ -899,22 +900,22 @@ .. method:: datetime.timetz() Return :class:`time` object with same hour, minute, second, microsecond, and - tzinfo members. See also method :meth:`time`. + tzinfo attributes. See also method :meth:`time`. .. method:: datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]]) - Return a datetime with the same members, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive datetime from an aware datetime with no - conversion of date and time members. + Return a datetime with the same attributes, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive datetime from an aware + datetime with no conversion of date and time attributes. .. method:: datetime.astimezone(tz) - Return a :class:`datetime` object with new :attr:`tzinfo` member *tz*, adjusting - the date and time members so the result is the same UTC time as *self*, but in - *tz*'s local time. + Return a :class:`datetime` object with new :attr:`tzinfo` attribute *tz*, + adjusting the date and time attributes so the result is the same UTC time as + *self*, but in *tz*'s local time. *tz* must be an instance of a :class:`tzinfo` subclass, and its :meth:`utcoffset` and :meth:`dst` methods must not return ``None``. *self* must @@ -922,18 +923,18 @@ not return ``None``). If ``self.tzinfo`` is *tz*, ``self.astimezone(tz)`` is equal to *self*: no - adjustment of date or time members is performed. Else the result is local time - in time zone *tz*, representing the same UTC time as *self*: after ``astz = - dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have the same date - and time members as ``dt - dt.utcoffset()``. The discussion of class - :class:`tzinfo` explains the cases at Daylight Saving Time transition boundaries - where this cannot be achieved (an issue only if *tz* models both standard and - daylight time). + adjustment of date or time attributes is performed. Else the result is local + time in time zone *tz*, representing the same UTC time as *self*: after + ``astz = dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have + the same date and time attributes as ``dt - dt.utcoffset()``. The discussion + of class :class:`tzinfo` explains the cases at Daylight Saving Time transition + boundaries where this cannot be achieved (an issue only if *tz* models both + standard and daylight time). If you merely want to attach a time zone object *tz* to a datetime *dt* without - adjustment of date and time members, use ``dt.replace(tzinfo=tz)``. If you + adjustment of date and time attributes, use ``dt.replace(tzinfo=tz)``. If you merely want to remove the time zone object from an aware datetime *dt* without - conversion of date and time members, use ``dt.replace(tzinfo=None)``. + conversion of date and time attributes, use ``dt.replace(tzinfo=None)``. Note that the default :meth:`tzinfo.fromutc` method can be overridden in a :class:`tzinfo` subclass to affect the result returned by :meth:`astimezone`. @@ -1244,14 +1245,14 @@ * comparison of :class:`time` to :class:`time`, where *a* is considered less than *b* when *a* precedes *b* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. If both comparands are aware, and have - the same :attr:`tzinfo` member, the common :attr:`tzinfo` member is ignored and - the base times are compared. If both comparands are aware and have different - :attr:`tzinfo` members, the comparands are first adjusted by subtracting their - UTC offsets (obtained from ``self.utcoffset()``). In order to stop mixed-type - comparisons from falling back to the default comparison by object address, when - a :class:`time` object is compared to an object of a different type, - :exc:`TypeError` is raised unless the comparison is ``==`` or ``!=``. The - latter cases return :const:`False` or :const:`True`, respectively. + the same :attr:`tzinfo` attribute, the common :attr:`tzinfo` attribute is + ignored and the base times are compared. If both comparands are aware and + have different :attr:`tzinfo` attributes, the comparands are first adjusted by + subtracting their UTC offsets (obtained from ``self.utcoffset()``). In order + to stop mixed-type comparisons from falling back to the default comparison by + object address, when a :class:`time` object is compared to an object of a + different type, :exc:`TypeError` is raised unless the comparison is ``==`` or + ``!=``. The latter cases return :const:`False` or :const:`True`, respectively. * hash, use as dict key @@ -1266,10 +1267,10 @@ .. method:: time.replace([hour[, minute[, second[, microsecond[, tzinfo]]]]]) - Return a :class:`time` with the same value, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive :class:`time` from an aware :class:`time`, - without conversion of the time members. + Return a :class:`time` with the same value, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive :class:`time` from an + aware :class:`time`, without conversion of the time attributes. .. method:: time.isoformat() @@ -1354,7 +1355,7 @@ An instance of (a concrete subclass of) :class:`tzinfo` can be passed to the constructors for :class:`datetime` and :class:`time` objects. The latter objects -view their members as being in local time, and the :class:`tzinfo` object +view their attributes as being in local time, and the :class:`tzinfo` object supports methods revealing offset of local time from UTC, the name of the time zone, and DST offset, all relative to a date or time object passed to them. @@ -1399,9 +1400,9 @@ already been added to the UTC offset returned by :meth:`utcoffset`, so there's no need to consult :meth:`dst` unless you're interested in obtaining DST info separately. For example, :meth:`datetime.timetuple` calls its :attr:`tzinfo` - member's :meth:`dst` method to determine how the :attr:`tm_isdst` flag should be - set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for DST changes - when crossing time zones. + attribute's :meth:`dst` method to determine how the :attr:`tm_isdst` flag + should be set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for + DST changes when crossing time zones. An instance *tz* of a :class:`tzinfo` subclass that models both standard and daylight times must be consistent in this sense: @@ -1477,10 +1478,10 @@ .. method:: tzinfo.fromutc(dt) This is called from the default :class:`datetime.astimezone()` implementation. - When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time members - are to be viewed as expressing a UTC time. The purpose of :meth:`fromutc` is to - adjust the date and time members, returning an equivalent datetime in *self*'s - local time. + When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time + attributes are to be viewed as expressing a UTC time. The purpose of + :meth:`fromutc` is to adjust the date and time attributes, returning an + equivalent datetime in *self*'s local time. Most :class:`tzinfo` subclasses should be able to inherit the default :meth:`fromutc` implementation without problems. It's strong enough to handle diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -654,7 +654,7 @@ Normalize the number by stripping the rightmost trailing zeros and converting any result equal to :const:`Decimal('0')` to - :const:`Decimal('0e0')`. Used for producing canonical values for members + :const:`Decimal('0e0')`. Used for producing canonical values for attributes of an equivalence class. For example, ``Decimal('32.100')`` and ``Decimal('0.321000e+2')`` both normalize to the equivalent value ``Decimal('32.1')``. diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1127,11 +1127,10 @@ .. class:: DocTest(examples, globs, name, filename, lineno, docstring) A collection of doctest examples that should be run in a single namespace. The - constructor arguments are used to initialize the member variables of the same - names. + constructor arguments are used to initialize the attributes of the same names. - :class:`DocTest` defines the following member variables. They are initialized by + :class:`DocTest` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1184,11 +1183,11 @@ .. class:: Example(source, want, exc_msg=None, lineno=0, indent=0, options=None) A single interactive example, consisting of a Python statement and its expected - output. The constructor arguments are used to initialize the member variables - of the same names. + output. The constructor arguments are used to initialize the attributes of + the same names. - :class:`Example` defines the following member variables. They are initialized by + :class:`Example` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1675,9 +1674,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example's actual output did not match its expected output. The constructor arguments are - used to initialize the member variables of the same names. + used to initialize the attributes of the same names. -:exc:`DocTestFailure` defines the following member variables: +:exc:`DocTestFailure` defines the following attributes: .. attribute:: DocTestFailure.test @@ -1699,9 +1698,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example raised an unexpected exception. The constructor arguments are used - to initialize the member variables of the same names. + to initialize the attributes of the same names. -:exc:`UnexpectedException` defines the following member variables: +:exc:`UnexpectedException` defines the following attributes: .. attribute:: UnexpectedException.test diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -61,7 +61,7 @@ time is used. This module ignores the timestamp when decompressing; however, some programs, such as :program:`gunzip`\ , make use of it. The format of the timestamp is the same as that of the return value of - ``time.time()`` and of the ``st_mtime`` member of the object returned + ``time.time()`` and of the ``st_mtime`` attribute of the object returned by ``os.stat()``. Calling a :class:`GzipFile` object's :meth:`close` method does not close diff --git a/Doc/library/html.entities.rst b/Doc/library/html.entities.rst --- a/Doc/library/html.entities.rst +++ b/Doc/library/html.entities.rst @@ -11,7 +11,7 @@ This module defines three dictionaries, ``name2codepoint``, ``codepoint2name``, and ``entitydefs``. ``entitydefs`` is used to provide the :attr:`entitydefs` -member of the :class:`html.parser.HTMLParser` class. The definition provided +attribute of the :class:`html.parser.HTMLParser` class. The definition provided here contains all the entities defined by XHTML 1.0 that can be handled using simple textual substitution in the Latin-1 character set (ISO-8859-1). diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst --- a/Doc/library/http.cookies.rst +++ b/Doc/library/http.cookies.rst @@ -152,7 +152,7 @@ .. method:: Morsel.set(key, value, coded_value) - Set the *key*, *value* and *coded_value* members. + Set the *key*, *value* and *coded_value* attributes. .. method:: Morsel.isReservedKey(K) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -391,8 +391,8 @@ :class:`RawIOBase` implementation, but wrap one, like :class:`BufferedWriter` and :class:`BufferedReader` do. - :class:`BufferedIOBase` provides or overrides these members in addition to - those from :class:`IOBase`: + :class:`BufferedIOBase` provides or overrides these methods and attribute in + addition to those from :class:`IOBase`: .. attribute:: raw diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst --- a/Doc/library/nntplib.rst +++ b/Doc/library/nntplib.rst @@ -394,7 +394,7 @@ Send an ``ARTICLE`` command, where *message_spec* has the same meaning as for :meth:`stat`. Return a tuple ``(response, info)`` where *info* - is a :class:`~collections.namedtuple` with three members *number*, + is a :class:`~collections.namedtuple` with three attributes *number*, *message_id* and *lines* (in that order). *number* is the article number in the group (or 0 if the information is not available), *message_id* the message id as a string, and *lines* a list of lines (without terminating diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1339,11 +1339,12 @@ .. note:: - The exact meaning and resolution of the :attr:`st_atime`, :attr:`st_mtime`, and - :attr:`st_ctime` members depends on the operating system and the file system. - For example, on Windows systems using the FAT or FAT32 file systems, - :attr:`st_mtime` has 2-second resolution, and :attr:`st_atime` has only 1-day - resolution. See your operating system documentation for details. + The exact meaning and resolution of the :attr:`st_atime`, + :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating + system and the file system. For example, on Windows systems using the FAT + or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and + :attr:`st_atime` has only 1-day resolution. See your operating system + documentation for details. For backward compatibility, the return value of :func:`~os.stat` is also accessible as a tuple of at least 10 integers giving the most important (and portable) diff --git a/Doc/library/pyclbr.rst b/Doc/library/pyclbr.rst --- a/Doc/library/pyclbr.rst +++ b/Doc/library/pyclbr.rst @@ -45,7 +45,7 @@ The :class:`Class` objects used as values in the dictionary returned by :func:`readmodule` and :func:`readmodule_ex` provide the following data -members: +attributes: .. attribute:: Class.module @@ -89,7 +89,7 @@ ---------------- The :class:`Function` objects used as values in the dictionary returned by -:func:`readmodule_ex` provide the following data members: +:func:`readmodule_ex` provide the following attributes: .. attribute:: Function.module diff --git a/Doc/library/reprlib.rst b/Doc/library/reprlib.rst --- a/Doc/library/reprlib.rst +++ b/Doc/library/reprlib.rst @@ -66,7 +66,7 @@ Repr Objects ------------ -:class:`Repr` instances provide several members which can be used to provide +:class:`Repr` instances provide several attributes which can be used to provide size limits for the representations of different object types, and methods which format specific object types. diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst --- a/Doc/library/shlex.rst +++ b/Doc/library/shlex.rst @@ -24,8 +24,8 @@ Split the string *s* using shell-like syntax. If *comments* is :const:`False` (the default), the parsing of comments in the given string will be disabled - (setting the :attr:`commenters` member of the :class:`shlex` instance to the - empty string). This function operates in POSIX mode by default, but uses + (setting the :attr:`commenters` attribute of the :class:`shlex` instance to + the empty string). This function operates in POSIX mode by default, but uses non-POSIX mode if the *posix* argument is false. .. note:: @@ -44,7 +44,7 @@ from. It must be a file-/stream-like object with :meth:`read` and :meth:`readline` methods, or a string. If no argument is given, input will be taken from ``sys.stdin``. The second optional argument is a filename - string, which sets the initial value of the :attr:`infile` member. If the + string, which sets the initial value of the :attr:`infile` attribute. If the *instream* argument is omitted or equal to ``sys.stdin``, this second argument defaults to "stdin". The *posix* argument defines the operational mode: when *posix* is not true (default), the :class:`shlex` instance will @@ -202,8 +202,8 @@ .. attribute:: shlex.source - This member is ``None`` by default. If you assign a string to it, that string - will be recognized as a lexical-level inclusion request similar to the + This attribute is ``None`` by default. If you assign a string to it, that + string will be recognized as a lexical-level inclusion request similar to the ``source`` keyword in various shells. That is, the immediately following token will opened as a filename and input taken from that stream until EOF, at which point the :meth:`close` method of that stream will be called and the input @@ -213,7 +213,7 @@ .. attribute:: shlex.debug - If this member is numeric and ``1`` or more, a :class:`shlex` instance will + If this attribute is numeric and ``1`` or more, a :class:`shlex` instance will print verbose progress output on its behavior. If you need to use this, you can read the module source code to learn the details. diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -81,7 +81,7 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass The mix-in class must come first, since it overrides a method defined in -:class:`UDPServer`. Setting the various member variables also changes the +:class:`UDPServer`. Setting the various attributes also change the behavior of the underlying server mechanism. To implement a service, you must derive a class from :class:`BaseRequestHandler` diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2567,7 +2567,7 @@ foo`` does not require a module object named *foo* to exist, rather it requires an (external) *definition* for a module named *foo* somewhere.) -A special member of every module is :attr:`__dict__`. This is the dictionary +A special attribute of every module is :attr:`__dict__`. This is the dictionary containing the module's symbol table. Modifying this dictionary will actually change the module's symbol table, but direct assignment to the :attr:`__dict__` attribute is not possible (you can write ``m.__dict__['a'] = 1``, which defines diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -497,38 +497,39 @@ .. attribute:: dwFlags - A bit field that determines whether certain :class:`STARTUPINFO` members - are used when the process creates a window. :: + A bit field that determines whether certain :class:`STARTUPINFO` + attributes are used when the process creates a window. :: si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW .. attribute:: hStdInput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard input handle for the process. If :data:`STARTF_USESTDHANDLES` - is not specified, the default for standard input is the keyboard buffer. + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard input handle for the process. If + :data:`STARTF_USESTDHANDLES` is not specified, the default for standard + input is the keyboard buffer. .. attribute:: hStdOutput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard output handle for the process. Otherwise, this member is - ignored and the default for standard output is the console window's + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard output handle for the process. Otherwise, this attribute + is ignored and the default for standard output is the console window's buffer. .. attribute:: hStdError - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard error handle for the process. Otherwise, this member is + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard error handle for the process. Otherwise, this attribute is ignored and the default for standard error is the console window's buffer. .. attribute:: wShowWindow - If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member + If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this attribute can be any of the values that can be specified in the ``nCmdShow`` parameter for the `ShowWindow `__ - function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is + function, except for ``SW_SHOWDEFAULT``. Otherwise, this attribute is ignored. :data:`SW_HIDE` is provided for this attribute. It is used when @@ -562,12 +563,12 @@ .. data:: STARTF_USESTDHANDLES Specifies that the :attr:`STARTUPINFO.hStdInput`, - :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members + :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` attributes contain additional information. .. data:: STARTF_USESHOWWINDOW - Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains + Specifies that the :attr:`STARTUPINFO.wShowWindow` attribute contains additional information. .. data:: CREATE_NEW_CONSOLE diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -60,7 +60,7 @@ This function operates exactly as :func:`TemporaryFile` does, except that the file is guaranteed to have a visible name in the file system (on Unix, the directory entry is not unlinked). That name can be retrieved - from the :attr:`name` member of the file object. Whether the name can be + from the :attr:`name` attribute of the file object. Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows NT or later). If *delete* is true (the default), the file is @@ -96,7 +96,7 @@ of the temporary directory object), the newly created temporary directory and all its contents are removed from the filesystem. - The directory name can be retrieved from the :attr:`name` member + The directory name can be retrieved from the :attr:`name` attribute of the returned object. The directory can be explicitly cleaned up by calling the 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 @@ -105,7 +105,7 @@ can be imported), :class:`HTTPSHandler` will also be added. A :class:`BaseHandler` subclass may also change its :attr:`handler_order` - member variable to modify its position in the handlers list. + attribute to modify its position in the handlers list. .. function:: pathname2url(path) @@ -536,7 +536,7 @@ Remove any parents. -The following members and methods should only be used by classes derived from +The following attribute and methods should only be used by classes derived from :class:`BaseHandler`. .. note:: diff --git a/Doc/library/xdrlib.rst b/Doc/library/xdrlib.rst --- a/Doc/library/xdrlib.rst +++ b/Doc/library/xdrlib.rst @@ -260,7 +260,7 @@ .. exception:: Error - The base exception class. :exc:`Error` has a single public data member + The base exception class. :exc:`Error` has a single public attribute :attr:`msg` containing the description of the error. diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -136,7 +136,7 @@ :class:`Fault` or :class:`ProtocolError` object indicating an error. Servers that support the XML introspection API support some common methods -grouped under the reserved :attr:`system` member: +grouped under the reserved :attr:`system` attribute: .. method:: ServerProxy.system.listMethods() @@ -310,7 +310,7 @@ ------------- A :class:`Fault` object encapsulates the content of an XML-RPC fault tag. Fault -objects have the following members: +objects have the following attributes: .. attribute:: Fault.faultCode @@ -359,7 +359,7 @@ A :class:`ProtocolError` object describes a protocol error in the underlying transport layer (such as a 404 'not found' error if the server named by the URI -does not exist). It has the following members: +does not exist). It has the following attributes: .. attribute:: ProtocolError.url diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1459,7 +1459,7 @@ On FreeBSD, the :func:`os.stat` function now returns times with nanosecond resolution, and the returned object now has :attr:`st_gen` and - :attr:`st_birthtime`. The :attr:`st_flags` member is also available, if the + :attr:`st_birthtime`. The :attr:`st_flags` attribute is also available, if the platform supports it. (Contributed by Antti Louko and Diego Petten?.) .. (Patch 1180695, 1212117) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 20:44:32 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 20:44:32 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_from_3=2E2_=2E_Replace_the_term_members_with_correct__?= =?utf8?q?and_appropriate?= Message-ID: http://hg.python.org/cpython/rev/283f20f1d31f changeset: 71209:283f20f1d31f parent: 71207:24297278c78d parent: 71208:d442c313536b user: Senthil Kumaran date: Mon Jul 04 11:31:53 2011 -0700 summary: Merge from 3.2 . Replace the term members with correct and appropriate terminology. Initial patch by Adam Woodbeck. files: Doc/library/cmd.rst | 2 +- Doc/library/curses.rst | 4 +- Doc/library/datetime.rst | 133 ++++++++++---------- Doc/library/decimal.rst | 2 +- Doc/library/doctest.rst | 19 +- Doc/library/gzip.rst | 2 +- Doc/library/html.entities.rst | 2 +- Doc/library/http.cookies.rst | 2 +- Doc/library/io.rst | 4 +- Doc/library/nntplib.rst | 2 +- Doc/library/os.rst | 11 +- Doc/library/pyclbr.rst | 4 +- Doc/library/reprlib.rst | 2 +- Doc/library/shlex.rst | 12 +- Doc/library/socketserver.rst | 2 +- Doc/library/stdtypes.rst | 2 +- Doc/library/subprocess.rst | 29 ++-- Doc/library/tempfile.rst | 4 +- Doc/library/urllib.request.rst | 4 +- Doc/library/xdrlib.rst | 2 +- Doc/library/xmlrpc.client.rst | 6 +- Doc/whatsnew/2.5.rst | 2 +- 22 files changed, 127 insertions(+), 125 deletions(-) diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst --- a/Doc/library/cmd.rst +++ b/Doc/library/cmd.rst @@ -50,7 +50,7 @@ the line as argument. The optional argument is a banner or intro string to be issued before the first - prompt (this overrides the :attr:`intro` class member). + prompt (this overrides the :attr:`intro` class attribute). If the :mod:`readline` module is loaded, input will automatically inherit :program:`bash`\ -like history-list editing (e.g. :kbd:`Control-P` scrolls back diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1639,7 +1639,7 @@ each keystroke entered with the keystroke as a parameter; command dispatch is done on the result. This method returns the window contents as a string; whether blanks in the window are included is affected by the - :attr:`stripspaces` member. + :attr:`stripspaces` attribute. .. method:: do_command(ch) @@ -1711,7 +1711,7 @@ .. attribute:: stripspaces - This data member is a flag which controls the interpretation of blanks in + This attribute is a flag which controls the interpretation of blanks in the window. When it is on, trailing blanks on each line are ignored; any cursor motion that would land the cursor on a trailing blank goes to the end of that line instead, and trailing blanks are stripped when the window diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -11,7 +11,7 @@ The :mod:`datetime` module supplies classes for manipulating dates and times in both simple and complex ways. While date and time arithmetic is supported, the -focus of the implementation is on efficient member extraction for output +focus of the implementation is on efficient attribute extraction for output formatting and manipulation. For related functionality, see also the :mod:`time` and :mod:`calendar` modules. @@ -25,7 +25,7 @@ work with, at the cost of ignoring some aspects of reality. For applications requiring more, :class:`datetime` and :class:`time` objects -have an optional time zone information member, :attr:`tzinfo`, that can contain +have an optional time zone information attribute, :attr:`tzinfo`, that can contain an instance of a subclass of the abstract :class:`tzinfo` class. These :class:`tzinfo` objects capture information about the offset from UTC time, the time zone name, and whether Daylight Saving Time is in effect. Note that only @@ -499,9 +499,9 @@ .. method:: date.replace(year, month, day) - Return a date with the same value, except for those members given new values by - whichever keyword arguments are specified. For example, if ``d == date(2002, - 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. + Return a date with the same value, except for those parameters given new + values by whichever keyword arguments are specified. For example, if ``d == + date(2002, 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. .. method:: date.timetuple() @@ -748,11 +748,11 @@ .. classmethod:: datetime.combine(date, time) - Return a new :class:`datetime` object whose date members are equal to the given - :class:`date` object's, and whose time and :attr:`tzinfo` members are equal to - the given :class:`time` object's. For any :class:`datetime` object *d*, ``d == - datetime.combine(d.date(), d.timetz())``. If date is a :class:`datetime` - object, its time and :attr:`tzinfo` members are ignored. + Return a new :class:`datetime` object whose date attributes are equal to the + given :class:`date` object's, and whose time and :attr:`tzinfo` attributes are + equal to the given :class:`time` object's. For any :class:`datetime` object + *d*, ``d == datetime.combine(d.date(), d.timetz())``. If date is a + :class:`datetime` object, its time and :attr:`tzinfo` attributes are ignored. .. classmethod:: datetime.strptime(date_string, format) @@ -846,43 +846,44 @@ (1) datetime2 is a duration of timedelta removed from datetime1, moving forward in time if ``timedelta.days`` > 0, or backward if ``timedelta.days`` < 0. The - result has the same :attr:`tzinfo` member as the input datetime, and datetime2 - - datetime1 == timedelta after. :exc:`OverflowError` is raised if datetime2.year - would be smaller than :const:`MINYEAR` or larger than :const:`MAXYEAR`. Note - that no time zone adjustments are done even if the input is an aware object. + result has the same :attr:`tzinfo` attribute as the input datetime, and + datetime2 - datetime1 == timedelta after. :exc:`OverflowError` is raised if + datetime2.year would be smaller than :const:`MINYEAR` or larger than + :const:`MAXYEAR`. Note that no time zone adjustments are done even if the + input is an aware object. (2) Computes the datetime2 such that datetime2 + timedelta == datetime1. As for - addition, the result has the same :attr:`tzinfo` member as the input datetime, - and no time zone adjustments are done even if the input is aware. This isn't - quite equivalent to datetime1 + (-timedelta), because -timedelta in isolation - can overflow in cases where datetime1 - timedelta does not. + addition, the result has the same :attr:`tzinfo` attribute as the input + datetime, and no time zone adjustments are done even if the input is aware. + This isn't quite equivalent to datetime1 + (-timedelta), because -timedelta + in isolation can overflow in cases where datetime1 - timedelta does not. (3) Subtraction of a :class:`datetime` from a :class:`datetime` is defined only if both operands are naive, or if both are aware. If one is aware and the other is naive, :exc:`TypeError` is raised. - If both are naive, or both are aware and have the same :attr:`tzinfo` member, - the :attr:`tzinfo` members are ignored, and the result is a :class:`timedelta` + If both are naive, or both are aware and have the same :attr:`tzinfo` attribute, + the :attr:`tzinfo` attributes are ignored, and the result is a :class:`timedelta` object *t* such that ``datetime2 + t == datetime1``. No time zone adjustments are done in this case. - If both are aware and have different :attr:`tzinfo` members, ``a-b`` acts as if - *a* and *b* were first converted to naive UTC datetimes first. The result is - ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - - b.utcoffset())`` except that the implementation never overflows. + If both are aware and have different :attr:`tzinfo` attributes, ``a-b`` acts + as if *a* and *b* were first converted to naive UTC datetimes first. The + result is ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) + - b.utcoffset())`` except that the implementation never overflows. (4) *datetime1* is considered less than *datetime2* when *datetime1* precedes *datetime2* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. - If both comparands are aware, and have the same :attr:`tzinfo` member, the - common :attr:`tzinfo` member is ignored and the base datetimes are compared. If - both comparands are aware and have different :attr:`tzinfo` members, the - comparands are first adjusted by subtracting their UTC offsets (obtained from - ``self.utcoffset()``). + If both comparands are aware, and have the same :attr:`tzinfo` attribute, the + common :attr:`tzinfo` attribute is ignored and the base datetimes are + compared. If both comparands are aware and have different :attr:`tzinfo` + attributes, the comparands are first adjusted by subtracting their UTC + offsets (obtained from ``self.utcoffset()``). .. note:: @@ -915,22 +916,22 @@ .. method:: datetime.timetz() Return :class:`time` object with same hour, minute, second, microsecond, and - tzinfo members. See also method :meth:`time`. + tzinfo attributes. See also method :meth:`time`. .. method:: datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]]) - Return a datetime with the same members, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive datetime from an aware datetime with no - conversion of date and time members. + Return a datetime with the same attributes, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive datetime from an aware + datetime with no conversion of date and time attributes. .. method:: datetime.astimezone(tz) - Return a :class:`datetime` object with new :attr:`tzinfo` member *tz*, adjusting - the date and time members so the result is the same UTC time as *self*, but in - *tz*'s local time. + Return a :class:`datetime` object with new :attr:`tzinfo` attribute *tz*, + adjusting the date and time attributes so the result is the same UTC time as + *self*, but in *tz*'s local time. *tz* must be an instance of a :class:`tzinfo` subclass, and its :meth:`utcoffset` and :meth:`dst` methods must not return ``None``. *self* must @@ -938,18 +939,18 @@ not return ``None``). If ``self.tzinfo`` is *tz*, ``self.astimezone(tz)`` is equal to *self*: no - adjustment of date or time members is performed. Else the result is local time - in time zone *tz*, representing the same UTC time as *self*: after ``astz = - dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have the same date - and time members as ``dt - dt.utcoffset()``. The discussion of class - :class:`tzinfo` explains the cases at Daylight Saving Time transition boundaries - where this cannot be achieved (an issue only if *tz* models both standard and - daylight time). + adjustment of date or time attributes is performed. Else the result is local + time in time zone *tz*, representing the same UTC time as *self*: after + ``astz = dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have + the same date and time attributes as ``dt - dt.utcoffset()``. The discussion + of class :class:`tzinfo` explains the cases at Daylight Saving Time transition + boundaries where this cannot be achieved (an issue only if *tz* models both + standard and daylight time). If you merely want to attach a time zone object *tz* to a datetime *dt* without - adjustment of date and time members, use ``dt.replace(tzinfo=tz)``. If you + adjustment of date and time attributes, use ``dt.replace(tzinfo=tz)``. If you merely want to remove the time zone object from an aware datetime *dt* without - conversion of date and time members, use ``dt.replace(tzinfo=None)``. + conversion of date and time attributes, use ``dt.replace(tzinfo=None)``. Note that the default :meth:`tzinfo.fromutc` method can be overridden in a :class:`tzinfo` subclass to affect the result returned by :meth:`astimezone`. @@ -1260,14 +1261,14 @@ * comparison of :class:`time` to :class:`time`, where *a* is considered less than *b* when *a* precedes *b* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. If both comparands are aware, and have - the same :attr:`tzinfo` member, the common :attr:`tzinfo` member is ignored and - the base times are compared. If both comparands are aware and have different - :attr:`tzinfo` members, the comparands are first adjusted by subtracting their - UTC offsets (obtained from ``self.utcoffset()``). In order to stop mixed-type - comparisons from falling back to the default comparison by object address, when - a :class:`time` object is compared to an object of a different type, - :exc:`TypeError` is raised unless the comparison is ``==`` or ``!=``. The - latter cases return :const:`False` or :const:`True`, respectively. + the same :attr:`tzinfo` attribute, the common :attr:`tzinfo` attribute is + ignored and the base times are compared. If both comparands are aware and + have different :attr:`tzinfo` attributes, the comparands are first adjusted by + subtracting their UTC offsets (obtained from ``self.utcoffset()``). In order + to stop mixed-type comparisons from falling back to the default comparison by + object address, when a :class:`time` object is compared to an object of a + different type, :exc:`TypeError` is raised unless the comparison is ``==`` or + ``!=``. The latter cases return :const:`False` or :const:`True`, respectively. * hash, use as dict key @@ -1282,10 +1283,10 @@ .. method:: time.replace([hour[, minute[, second[, microsecond[, tzinfo]]]]]) - Return a :class:`time` with the same value, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive :class:`time` from an aware :class:`time`, - without conversion of the time members. + Return a :class:`time` with the same value, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive :class:`time` from an + aware :class:`time`, without conversion of the time attributes. .. method:: time.isoformat() @@ -1370,7 +1371,7 @@ An instance of (a concrete subclass of) :class:`tzinfo` can be passed to the constructors for :class:`datetime` and :class:`time` objects. The latter objects -view their members as being in local time, and the :class:`tzinfo` object +view their attributes as being in local time, and the :class:`tzinfo` object supports methods revealing offset of local time from UTC, the name of the time zone, and DST offset, all relative to a date or time object passed to them. @@ -1415,9 +1416,9 @@ already been added to the UTC offset returned by :meth:`utcoffset`, so there's no need to consult :meth:`dst` unless you're interested in obtaining DST info separately. For example, :meth:`datetime.timetuple` calls its :attr:`tzinfo` - member's :meth:`dst` method to determine how the :attr:`tm_isdst` flag should be - set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for DST changes - when crossing time zones. + attribute's :meth:`dst` method to determine how the :attr:`tm_isdst` flag + should be set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for + DST changes when crossing time zones. An instance *tz* of a :class:`tzinfo` subclass that models both standard and daylight times must be consistent in this sense: @@ -1493,10 +1494,10 @@ .. method:: tzinfo.fromutc(dt) This is called from the default :class:`datetime.astimezone()` implementation. - When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time members - are to be viewed as expressing a UTC time. The purpose of :meth:`fromutc` is to - adjust the date and time members, returning an equivalent datetime in *self*'s - local time. + When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time + attributes are to be viewed as expressing a UTC time. The purpose of + :meth:`fromutc` is to adjust the date and time attributes, returning an + equivalent datetime in *self*'s local time. Most :class:`tzinfo` subclasses should be able to inherit the default :meth:`fromutc` implementation without problems. It's strong enough to handle diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -654,7 +654,7 @@ Normalize the number by stripping the rightmost trailing zeros and converting any result equal to :const:`Decimal('0')` to - :const:`Decimal('0e0')`. Used for producing canonical values for members + :const:`Decimal('0e0')`. Used for producing canonical values for attributes of an equivalence class. For example, ``Decimal('32.100')`` and ``Decimal('0.321000e+2')`` both normalize to the equivalent value ``Decimal('32.1')``. diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1127,11 +1127,10 @@ .. class:: DocTest(examples, globs, name, filename, lineno, docstring) A collection of doctest examples that should be run in a single namespace. The - constructor arguments are used to initialize the member variables of the same - names. + constructor arguments are used to initialize the attributes of the same names. - :class:`DocTest` defines the following member variables. They are initialized by + :class:`DocTest` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1184,11 +1183,11 @@ .. class:: Example(source, want, exc_msg=None, lineno=0, indent=0, options=None) A single interactive example, consisting of a Python statement and its expected - output. The constructor arguments are used to initialize the member variables - of the same names. + output. The constructor arguments are used to initialize the attributes of + the same names. - :class:`Example` defines the following member variables. They are initialized by + :class:`Example` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1675,9 +1674,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example's actual output did not match its expected output. The constructor arguments are - used to initialize the member variables of the same names. + used to initialize the attributes of the same names. -:exc:`DocTestFailure` defines the following member variables: +:exc:`DocTestFailure` defines the following attributes: .. attribute:: DocTestFailure.test @@ -1699,9 +1698,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example raised an unexpected exception. The constructor arguments are used - to initialize the member variables of the same names. + to initialize the attributes of the same names. -:exc:`UnexpectedException` defines the following member variables: +:exc:`UnexpectedException` defines the following attributes: .. attribute:: UnexpectedException.test diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -61,7 +61,7 @@ time is used. This module ignores the timestamp when decompressing; however, some programs, such as :program:`gunzip`\ , make use of it. The format of the timestamp is the same as that of the return value of - ``time.time()`` and of the ``st_mtime`` member of the object returned + ``time.time()`` and of the ``st_mtime`` attribute of the object returned by ``os.stat()``. Calling a :class:`GzipFile` object's :meth:`close` method does not close diff --git a/Doc/library/html.entities.rst b/Doc/library/html.entities.rst --- a/Doc/library/html.entities.rst +++ b/Doc/library/html.entities.rst @@ -11,7 +11,7 @@ This module defines three dictionaries, ``name2codepoint``, ``codepoint2name``, and ``entitydefs``. ``entitydefs`` is used to provide the :attr:`entitydefs` -member of the :class:`html.parser.HTMLParser` class. The definition provided +attribute of the :class:`html.parser.HTMLParser` class. The definition provided here contains all the entities defined by XHTML 1.0 that can be handled using simple textual substitution in the Latin-1 character set (ISO-8859-1). diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst --- a/Doc/library/http.cookies.rst +++ b/Doc/library/http.cookies.rst @@ -152,7 +152,7 @@ .. method:: Morsel.set(key, value, coded_value) - Set the *key*, *value* and *coded_value* members. + Set the *key*, *value* and *coded_value* attributes. .. method:: Morsel.isReservedKey(K) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -391,8 +391,8 @@ :class:`RawIOBase` implementation, but wrap one, like :class:`BufferedWriter` and :class:`BufferedReader` do. - :class:`BufferedIOBase` provides or overrides these members in addition to - those from :class:`IOBase`: + :class:`BufferedIOBase` provides or overrides these methods and attribute in + addition to those from :class:`IOBase`: .. attribute:: raw diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst --- a/Doc/library/nntplib.rst +++ b/Doc/library/nntplib.rst @@ -407,7 +407,7 @@ Send an ``ARTICLE`` command, where *message_spec* has the same meaning as for :meth:`stat`. Return a tuple ``(response, info)`` where *info* - is a :class:`~collections.namedtuple` with three members *number*, + is a :class:`~collections.namedtuple` with three attributes *number*, *message_id* and *lines* (in that order). *number* is the article number in the group (or 0 if the information is not available), *message_id* the message id as a string, and *lines* a list of lines (without terminating diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1826,11 +1826,12 @@ .. note:: - The exact meaning and resolution of the :attr:`st_atime`, :attr:`st_mtime`, and - :attr:`st_ctime` members depends on the operating system and the file system. - For example, on Windows systems using the FAT or FAT32 file systems, - :attr:`st_mtime` has 2-second resolution, and :attr:`st_atime` has only 1-day - resolution. See your operating system documentation for details. + The exact meaning and resolution of the :attr:`st_atime`, + :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating + system and the file system. For example, on Windows systems using the FAT + or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and + :attr:`st_atime` has only 1-day resolution. See your operating system + documentation for details. For backward compatibility, the return value of :func:`~os.stat` is also accessible as a tuple of at least 10 integers giving the most important (and portable) diff --git a/Doc/library/pyclbr.rst b/Doc/library/pyclbr.rst --- a/Doc/library/pyclbr.rst +++ b/Doc/library/pyclbr.rst @@ -45,7 +45,7 @@ The :class:`Class` objects used as values in the dictionary returned by :func:`readmodule` and :func:`readmodule_ex` provide the following data -members: +attributes: .. attribute:: Class.module @@ -89,7 +89,7 @@ ---------------- The :class:`Function` objects used as values in the dictionary returned by -:func:`readmodule_ex` provide the following data members: +:func:`readmodule_ex` provide the following attributes: .. attribute:: Function.module diff --git a/Doc/library/reprlib.rst b/Doc/library/reprlib.rst --- a/Doc/library/reprlib.rst +++ b/Doc/library/reprlib.rst @@ -66,7 +66,7 @@ Repr Objects ------------ -:class:`Repr` instances provide several members which can be used to provide +:class:`Repr` instances provide several attributes which can be used to provide size limits for the representations of different object types, and methods which format specific object types. diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst --- a/Doc/library/shlex.rst +++ b/Doc/library/shlex.rst @@ -24,8 +24,8 @@ Split the string *s* using shell-like syntax. If *comments* is :const:`False` (the default), the parsing of comments in the given string will be disabled - (setting the :attr:`commenters` member of the :class:`shlex` instance to the - empty string). This function operates in POSIX mode by default, but uses + (setting the :attr:`commenters` attribute of the :class:`shlex` instance to + the empty string). This function operates in POSIX mode by default, but uses non-POSIX mode if the *posix* argument is false. .. note:: @@ -44,7 +44,7 @@ from. It must be a file-/stream-like object with :meth:`read` and :meth:`readline` methods, or a string. If no argument is given, input will be taken from ``sys.stdin``. The second optional argument is a filename - string, which sets the initial value of the :attr:`infile` member. If the + string, which sets the initial value of the :attr:`infile` attribute. If the *instream* argument is omitted or equal to ``sys.stdin``, this second argument defaults to "stdin". The *posix* argument defines the operational mode: when *posix* is not true (default), the :class:`shlex` instance will @@ -202,8 +202,8 @@ .. attribute:: shlex.source - This member is ``None`` by default. If you assign a string to it, that string - will be recognized as a lexical-level inclusion request similar to the + This attribute is ``None`` by default. If you assign a string to it, that + string will be recognized as a lexical-level inclusion request similar to the ``source`` keyword in various shells. That is, the immediately following token will opened as a filename and input taken from that stream until EOF, at which point the :meth:`close` method of that stream will be called and the input @@ -213,7 +213,7 @@ .. attribute:: shlex.debug - If this member is numeric and ``1`` or more, a :class:`shlex` instance will + If this attribute is numeric and ``1`` or more, a :class:`shlex` instance will print verbose progress output on its behavior. If you need to use this, you can read the module source code to learn the details. diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -81,7 +81,7 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass The mix-in class must come first, since it overrides a method defined in -:class:`UDPServer`. Setting the various member variables also changes the +:class:`UDPServer`. Setting the various attributes also change the behavior of the underlying server mechanism. To implement a service, you must derive a class from :class:`BaseRequestHandler` diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2578,7 +2578,7 @@ foo`` does not require a module object named *foo* to exist, rather it requires an (external) *definition* for a module named *foo* somewhere.) -A special member of every module is :attr:`__dict__`. This is the dictionary +A special attribute of every module is :attr:`__dict__`. This is the dictionary containing the module's symbol table. Modifying this dictionary will actually change the module's symbol table, but direct assignment to the :attr:`__dict__` attribute is not possible (you can write ``m.__dict__['a'] = 1``, which defines diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -567,38 +567,39 @@ .. attribute:: dwFlags - A bit field that determines whether certain :class:`STARTUPINFO` members - are used when the process creates a window. :: + A bit field that determines whether certain :class:`STARTUPINFO` + attributes are used when the process creates a window. :: si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW .. attribute:: hStdInput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard input handle for the process. If :data:`STARTF_USESTDHANDLES` - is not specified, the default for standard input is the keyboard buffer. + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard input handle for the process. If + :data:`STARTF_USESTDHANDLES` is not specified, the default for standard + input is the keyboard buffer. .. attribute:: hStdOutput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard output handle for the process. Otherwise, this member is - ignored and the default for standard output is the console window's + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard output handle for the process. Otherwise, this attribute + is ignored and the default for standard output is the console window's buffer. .. attribute:: hStdError - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard error handle for the process. Otherwise, this member is + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard error handle for the process. Otherwise, this attribute is ignored and the default for standard error is the console window's buffer. .. attribute:: wShowWindow - If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member + If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this attribute can be any of the values that can be specified in the ``nCmdShow`` parameter for the `ShowWindow `__ - function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is + function, except for ``SW_SHOWDEFAULT``. Otherwise, this attribute is ignored. :data:`SW_HIDE` is provided for this attribute. It is used when @@ -632,12 +633,12 @@ .. data:: STARTF_USESTDHANDLES Specifies that the :attr:`STARTUPINFO.hStdInput`, - :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members + :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` attributes contain additional information. .. data:: STARTF_USESHOWWINDOW - Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains + Specifies that the :attr:`STARTUPINFO.wShowWindow` attribute contains additional information. .. data:: CREATE_NEW_CONSOLE diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -60,7 +60,7 @@ This function operates exactly as :func:`TemporaryFile` does, except that the file is guaranteed to have a visible name in the file system (on Unix, the directory entry is not unlinked). That name can be retrieved - from the :attr:`name` member of the file object. Whether the name can be + from the :attr:`name` attribute of the file object. Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows NT or later). If *delete* is true (the default), the file is @@ -96,7 +96,7 @@ of the temporary directory object), the newly created temporary directory and all its contents are removed from the filesystem. - The directory name can be retrieved from the :attr:`name` member + The directory name can be retrieved from the :attr:`name` attribute of the returned object. The directory can be explicitly cleaned up by calling the 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 @@ -105,7 +105,7 @@ can be imported), :class:`HTTPSHandler` will also be added. A :class:`BaseHandler` subclass may also change its :attr:`handler_order` - member variable to modify its position in the handlers list. + attribute to modify its position in the handlers list. .. function:: pathname2url(path) @@ -546,7 +546,7 @@ Remove any parents. -The following members and methods should only be used by classes derived from +The following attribute and methods should only be used by classes derived from :class:`BaseHandler`. .. note:: diff --git a/Doc/library/xdrlib.rst b/Doc/library/xdrlib.rst --- a/Doc/library/xdrlib.rst +++ b/Doc/library/xdrlib.rst @@ -260,7 +260,7 @@ .. exception:: Error - The base exception class. :exc:`Error` has a single public data member + The base exception class. :exc:`Error` has a single public attribute :attr:`msg` containing the description of the error. diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -136,7 +136,7 @@ :class:`Fault` or :class:`ProtocolError` object indicating an error. Servers that support the XML introspection API support some common methods -grouped under the reserved :attr:`system` member: +grouped under the reserved :attr:`system` attribute: .. method:: ServerProxy.system.listMethods() @@ -310,7 +310,7 @@ ------------- A :class:`Fault` object encapsulates the content of an XML-RPC fault tag. Fault -objects have the following members: +objects have the following attributes: .. attribute:: Fault.faultCode @@ -359,7 +359,7 @@ A :class:`ProtocolError` object describes a protocol error in the underlying transport layer (such as a 404 'not found' error if the server named by the URI -does not exist). It has the following members: +does not exist). It has the following attributes: .. attribute:: ProtocolError.url diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1459,7 +1459,7 @@ On FreeBSD, the :func:`os.stat` function now returns times with nanosecond resolution, and the returned object now has :attr:`st_gen` and - :attr:`st_birthtime`. The :attr:`st_flags` member is also available, if the + :attr:`st_birthtime`. The :attr:`st_flags` attribute is also available, if the platform supports it. (Contributed by Antti Louko and Diego Petten?.) .. (Patch 1180695, 1212117) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 20:44:33 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 20:44:33 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_whitespace_?= =?utf8?q?nit_in_datetime_and_os_rst_files=2E?= Message-ID: http://hg.python.org/cpython/rev/184192b3687c changeset: 71210:184192b3687c branch: 3.2 parent: 71208:d442c313536b user: Senthil Kumaran date: Mon Jul 04 11:43:51 2011 -0700 summary: Fix whitespace nit in datetime and os rst files. files: Doc/library/datetime.rst | 2 +- Doc/library/os.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1251,7 +1251,7 @@ subtracting their UTC offsets (obtained from ``self.utcoffset()``). In order to stop mixed-type comparisons from falling back to the default comparison by object address, when a :class:`time` object is compared to an object of a - different type, :exc:`TypeError` is raised unless the comparison is ``==`` or + different type, :exc:`TypeError` is raised unless the comparison is ``==`` or ``!=``. The latter cases return :const:`False` or :const:`True`, respectively. * hash, use as dict key diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1339,7 +1339,7 @@ .. note:: - The exact meaning and resolution of the :attr:`st_atime`, + The exact meaning and resolution of the :attr:`st_atime`, :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating system and the file system. For example, on Windows systems using the FAT or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 20:44:34 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 20:44:34 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_from_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/f9d30fac3da0 changeset: 71211:f9d30fac3da0 parent: 71209:283f20f1d31f parent: 71210:184192b3687c user: Senthil Kumaran date: Mon Jul 04 11:44:17 2011 -0700 summary: merge from 3.2 files: Doc/library/datetime.rst | 2 +- Doc/library/os.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1267,7 +1267,7 @@ subtracting their UTC offsets (obtained from ``self.utcoffset()``). In order to stop mixed-type comparisons from falling back to the default comparison by object address, when a :class:`time` object is compared to an object of a - different type, :exc:`TypeError` is raised unless the comparison is ``==`` or + different type, :exc:`TypeError` is raised unless the comparison is ``==`` or ``!=``. The latter cases return :const:`False` or :const:`True`, respectively. * hash, use as dict key diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1826,7 +1826,7 @@ .. note:: - The exact meaning and resolution of the :attr:`st_atime`, + The exact meaning and resolution of the :attr:`st_atime`, :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating system and the file system. For example, on Windows systems using the FAT or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 20:51:16 2011 From: python-checkins at python.org (local-hg) Date: Mon, 04 Jul 2011 20:51:16 +0200 Subject: [Python-checkins] =?utf8?q?cpython-gd_=283=2E2=29=3A_issue10403_-?= =?utf8?q?_Let=27s_not_use_members_anymore=2E_Use_=27attribute=27_where_it?= =?utf8?q?_denotes?= Message-ID: http://hg.python.org/cpython-gd/rev/d442c313536b changeset: 71208:d442c313536b branch: 3.2 parent: 71206:ab22ffd905b3 user: Senthil Kumaran date: Mon Jul 04 11:28:30 2011 -0700 files: Doc/library/cmd.rst Doc/library/curses.rst Doc/library/datetime.rst Doc/library/decimal.rst Doc/library/doctest.rst Doc/library/gzip.rst Doc/library/html.entities.rst Doc/library/http.cookies.rst Doc/library/io.rst Doc/library/nntplib.rst Doc/library/os.rst Doc/library/pyclbr.rst Doc/library/reprlib.rst Doc/library/shlex.rst Doc/library/socketserver.rst Doc/library/stdtypes.rst Doc/library/subprocess.rst Doc/library/tempfile.rst Doc/library/urllib.request.rst Doc/library/xdrlib.rst Doc/library/xmlrpc.client.rst Doc/whatsnew/2.5.rst description: issue10403 - Let's not use members anymore. Use 'attribute' where it denotes attribute and 'methods' where it denotes methods. Context should clarify usage. summary: issue10403 - Let's not use members anymore. Use 'attribute' where it denotes attribute and 'methods' where it denotes methods. Context should clarify usage. files: Doc/library/cmd.rst | 2 +- Doc/library/curses.rst | 4 +- Doc/library/datetime.rst | 133 ++++++++++---------- Doc/library/decimal.rst | 2 +- Doc/library/doctest.rst | 19 +- Doc/library/gzip.rst | 2 +- Doc/library/html.entities.rst | 2 +- Doc/library/http.cookies.rst | 2 +- Doc/library/io.rst | 4 +- Doc/library/nntplib.rst | 2 +- Doc/library/os.rst | 11 +- Doc/library/pyclbr.rst | 4 +- Doc/library/reprlib.rst | 2 +- Doc/library/shlex.rst | 12 +- Doc/library/socketserver.rst | 2 +- Doc/library/stdtypes.rst | 2 +- Doc/library/subprocess.rst | 29 ++-- Doc/library/tempfile.rst | 4 +- Doc/library/urllib.request.rst | 4 +- Doc/library/xdrlib.rst | 2 +- Doc/library/xmlrpc.client.rst | 6 +- Doc/whatsnew/2.5.rst | 2 +- 22 files changed, 127 insertions(+), 125 deletions(-) diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst --- a/Doc/library/cmd.rst +++ b/Doc/library/cmd.rst @@ -50,7 +50,7 @@ the line as argument. The optional argument is a banner or intro string to be issued before the first - prompt (this overrides the :attr:`intro` class member). + prompt (this overrides the :attr:`intro` class attribute). If the :mod:`readline` module is loaded, input will automatically inherit :program:`bash`\ -like history-list editing (e.g. :kbd:`Control-P` scrolls back diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1639,7 +1639,7 @@ each keystroke entered with the keystroke as a parameter; command dispatch is done on the result. This method returns the window contents as a string; whether blanks in the window are included is affected by the - :attr:`stripspaces` member. + :attr:`stripspaces` attribute. .. method:: do_command(ch) @@ -1711,7 +1711,7 @@ .. attribute:: stripspaces - This data member is a flag which controls the interpretation of blanks in + This attribute is a flag which controls the interpretation of blanks in the window. When it is on, trailing blanks on each line are ignored; any cursor motion that would land the cursor on a trailing blank goes to the end of that line instead, and trailing blanks are stripped when the window diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -11,7 +11,7 @@ The :mod:`datetime` module supplies classes for manipulating dates and times in both simple and complex ways. While date and time arithmetic is supported, the -focus of the implementation is on efficient member extraction for output +focus of the implementation is on efficient attribute extraction for output formatting and manipulation. For related functionality, see also the :mod:`time` and :mod:`calendar` modules. @@ -25,7 +25,7 @@ work with, at the cost of ignoring some aspects of reality. For applications requiring more, :class:`datetime` and :class:`time` objects -have an optional time zone information member, :attr:`tzinfo`, that can contain +have an optional time zone information attribute, :attr:`tzinfo`, that can contain an instance of a subclass of the abstract :class:`tzinfo` class. These :class:`tzinfo` objects capture information about the offset from UTC time, the time zone name, and whether Daylight Saving Time is in effect. Note that only @@ -499,9 +499,9 @@ .. method:: date.replace(year, month, day) - Return a date with the same value, except for those members given new values by - whichever keyword arguments are specified. For example, if ``d == date(2002, - 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. + Return a date with the same value, except for those parameters given new + values by whichever keyword arguments are specified. For example, if ``d == + date(2002, 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. .. method:: date.timetuple() @@ -732,11 +732,11 @@ .. classmethod:: datetime.combine(date, time) - Return a new :class:`datetime` object whose date members are equal to the given - :class:`date` object's, and whose time and :attr:`tzinfo` members are equal to - the given :class:`time` object's. For any :class:`datetime` object *d*, ``d == - datetime.combine(d.date(), d.timetz())``. If date is a :class:`datetime` - object, its time and :attr:`tzinfo` members are ignored. + Return a new :class:`datetime` object whose date attributes are equal to the + given :class:`date` object's, and whose time and :attr:`tzinfo` attributes are + equal to the given :class:`time` object's. For any :class:`datetime` object + *d*, ``d == datetime.combine(d.date(), d.timetz())``. If date is a + :class:`datetime` object, its time and :attr:`tzinfo` attributes are ignored. .. classmethod:: datetime.strptime(date_string, format) @@ -830,43 +830,44 @@ (1) datetime2 is a duration of timedelta removed from datetime1, moving forward in time if ``timedelta.days`` > 0, or backward if ``timedelta.days`` < 0. The - result has the same :attr:`tzinfo` member as the input datetime, and datetime2 - - datetime1 == timedelta after. :exc:`OverflowError` is raised if datetime2.year - would be smaller than :const:`MINYEAR` or larger than :const:`MAXYEAR`. Note - that no time zone adjustments are done even if the input is an aware object. + result has the same :attr:`tzinfo` attribute as the input datetime, and + datetime2 - datetime1 == timedelta after. :exc:`OverflowError` is raised if + datetime2.year would be smaller than :const:`MINYEAR` or larger than + :const:`MAXYEAR`. Note that no time zone adjustments are done even if the + input is an aware object. (2) Computes the datetime2 such that datetime2 + timedelta == datetime1. As for - addition, the result has the same :attr:`tzinfo` member as the input datetime, - and no time zone adjustments are done even if the input is aware. This isn't - quite equivalent to datetime1 + (-timedelta), because -timedelta in isolation - can overflow in cases where datetime1 - timedelta does not. + addition, the result has the same :attr:`tzinfo` attribute as the input + datetime, and no time zone adjustments are done even if the input is aware. + This isn't quite equivalent to datetime1 + (-timedelta), because -timedelta + in isolation can overflow in cases where datetime1 - timedelta does not. (3) Subtraction of a :class:`datetime` from a :class:`datetime` is defined only if both operands are naive, or if both are aware. If one is aware and the other is naive, :exc:`TypeError` is raised. - If both are naive, or both are aware and have the same :attr:`tzinfo` member, - the :attr:`tzinfo` members are ignored, and the result is a :class:`timedelta` + If both are naive, or both are aware and have the same :attr:`tzinfo` attribute, + the :attr:`tzinfo` attributes are ignored, and the result is a :class:`timedelta` object *t* such that ``datetime2 + t == datetime1``. No time zone adjustments are done in this case. - If both are aware and have different :attr:`tzinfo` members, ``a-b`` acts as if - *a* and *b* were first converted to naive UTC datetimes first. The result is - ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - - b.utcoffset())`` except that the implementation never overflows. + If both are aware and have different :attr:`tzinfo` attributes, ``a-b`` acts + as if *a* and *b* were first converted to naive UTC datetimes first. The + result is ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) + - b.utcoffset())`` except that the implementation never overflows. (4) *datetime1* is considered less than *datetime2* when *datetime1* precedes *datetime2* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. - If both comparands are aware, and have the same :attr:`tzinfo` member, the - common :attr:`tzinfo` member is ignored and the base datetimes are compared. If - both comparands are aware and have different :attr:`tzinfo` members, the - comparands are first adjusted by subtracting their UTC offsets (obtained from - ``self.utcoffset()``). + If both comparands are aware, and have the same :attr:`tzinfo` attribute, the + common :attr:`tzinfo` attribute is ignored and the base datetimes are + compared. If both comparands are aware and have different :attr:`tzinfo` + attributes, the comparands are first adjusted by subtracting their UTC + offsets (obtained from ``self.utcoffset()``). .. note:: @@ -899,22 +900,22 @@ .. method:: datetime.timetz() Return :class:`time` object with same hour, minute, second, microsecond, and - tzinfo members. See also method :meth:`time`. + tzinfo attributes. See also method :meth:`time`. .. method:: datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]]) - Return a datetime with the same members, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive datetime from an aware datetime with no - conversion of date and time members. + Return a datetime with the same attributes, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive datetime from an aware + datetime with no conversion of date and time attributes. .. method:: datetime.astimezone(tz) - Return a :class:`datetime` object with new :attr:`tzinfo` member *tz*, adjusting - the date and time members so the result is the same UTC time as *self*, but in - *tz*'s local time. + Return a :class:`datetime` object with new :attr:`tzinfo` attribute *tz*, + adjusting the date and time attributes so the result is the same UTC time as + *self*, but in *tz*'s local time. *tz* must be an instance of a :class:`tzinfo` subclass, and its :meth:`utcoffset` and :meth:`dst` methods must not return ``None``. *self* must @@ -922,18 +923,18 @@ not return ``None``). If ``self.tzinfo`` is *tz*, ``self.astimezone(tz)`` is equal to *self*: no - adjustment of date or time members is performed. Else the result is local time - in time zone *tz*, representing the same UTC time as *self*: after ``astz = - dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have the same date - and time members as ``dt - dt.utcoffset()``. The discussion of class - :class:`tzinfo` explains the cases at Daylight Saving Time transition boundaries - where this cannot be achieved (an issue only if *tz* models both standard and - daylight time). + adjustment of date or time attributes is performed. Else the result is local + time in time zone *tz*, representing the same UTC time as *self*: after + ``astz = dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have + the same date and time attributes as ``dt - dt.utcoffset()``. The discussion + of class :class:`tzinfo` explains the cases at Daylight Saving Time transition + boundaries where this cannot be achieved (an issue only if *tz* models both + standard and daylight time). If you merely want to attach a time zone object *tz* to a datetime *dt* without - adjustment of date and time members, use ``dt.replace(tzinfo=tz)``. If you + adjustment of date and time attributes, use ``dt.replace(tzinfo=tz)``. If you merely want to remove the time zone object from an aware datetime *dt* without - conversion of date and time members, use ``dt.replace(tzinfo=None)``. + conversion of date and time attributes, use ``dt.replace(tzinfo=None)``. Note that the default :meth:`tzinfo.fromutc` method can be overridden in a :class:`tzinfo` subclass to affect the result returned by :meth:`astimezone`. @@ -1244,14 +1245,14 @@ * comparison of :class:`time` to :class:`time`, where *a* is considered less than *b* when *a* precedes *b* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. If both comparands are aware, and have - the same :attr:`tzinfo` member, the common :attr:`tzinfo` member is ignored and - the base times are compared. If both comparands are aware and have different - :attr:`tzinfo` members, the comparands are first adjusted by subtracting their - UTC offsets (obtained from ``self.utcoffset()``). In order to stop mixed-type - comparisons from falling back to the default comparison by object address, when - a :class:`time` object is compared to an object of a different type, - :exc:`TypeError` is raised unless the comparison is ``==`` or ``!=``. The - latter cases return :const:`False` or :const:`True`, respectively. + the same :attr:`tzinfo` attribute, the common :attr:`tzinfo` attribute is + ignored and the base times are compared. If both comparands are aware and + have different :attr:`tzinfo` attributes, the comparands are first adjusted by + subtracting their UTC offsets (obtained from ``self.utcoffset()``). In order + to stop mixed-type comparisons from falling back to the default comparison by + object address, when a :class:`time` object is compared to an object of a + different type, :exc:`TypeError` is raised unless the comparison is ``==`` or + ``!=``. The latter cases return :const:`False` or :const:`True`, respectively. * hash, use as dict key @@ -1266,10 +1267,10 @@ .. method:: time.replace([hour[, minute[, second[, microsecond[, tzinfo]]]]]) - Return a :class:`time` with the same value, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive :class:`time` from an aware :class:`time`, - without conversion of the time members. + Return a :class:`time` with the same value, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive :class:`time` from an + aware :class:`time`, without conversion of the time attributes. .. method:: time.isoformat() @@ -1354,7 +1355,7 @@ An instance of (a concrete subclass of) :class:`tzinfo` can be passed to the constructors for :class:`datetime` and :class:`time` objects. The latter objects -view their members as being in local time, and the :class:`tzinfo` object +view their attributes as being in local time, and the :class:`tzinfo` object supports methods revealing offset of local time from UTC, the name of the time zone, and DST offset, all relative to a date or time object passed to them. @@ -1399,9 +1400,9 @@ already been added to the UTC offset returned by :meth:`utcoffset`, so there's no need to consult :meth:`dst` unless you're interested in obtaining DST info separately. For example, :meth:`datetime.timetuple` calls its :attr:`tzinfo` - member's :meth:`dst` method to determine how the :attr:`tm_isdst` flag should be - set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for DST changes - when crossing time zones. + attribute's :meth:`dst` method to determine how the :attr:`tm_isdst` flag + should be set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for + DST changes when crossing time zones. An instance *tz* of a :class:`tzinfo` subclass that models both standard and daylight times must be consistent in this sense: @@ -1477,10 +1478,10 @@ .. method:: tzinfo.fromutc(dt) This is called from the default :class:`datetime.astimezone()` implementation. - When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time members - are to be viewed as expressing a UTC time. The purpose of :meth:`fromutc` is to - adjust the date and time members, returning an equivalent datetime in *self*'s - local time. + When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time + attributes are to be viewed as expressing a UTC time. The purpose of + :meth:`fromutc` is to adjust the date and time attributes, returning an + equivalent datetime in *self*'s local time. Most :class:`tzinfo` subclasses should be able to inherit the default :meth:`fromutc` implementation without problems. It's strong enough to handle diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -654,7 +654,7 @@ Normalize the number by stripping the rightmost trailing zeros and converting any result equal to :const:`Decimal('0')` to - :const:`Decimal('0e0')`. Used for producing canonical values for members + :const:`Decimal('0e0')`. Used for producing canonical values for attributes of an equivalence class. For example, ``Decimal('32.100')`` and ``Decimal('0.321000e+2')`` both normalize to the equivalent value ``Decimal('32.1')``. diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1127,11 +1127,10 @@ .. class:: DocTest(examples, globs, name, filename, lineno, docstring) A collection of doctest examples that should be run in a single namespace. The - constructor arguments are used to initialize the member variables of the same - names. + constructor arguments are used to initialize the attributes of the same names. - :class:`DocTest` defines the following member variables. They are initialized by + :class:`DocTest` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1184,11 +1183,11 @@ .. class:: Example(source, want, exc_msg=None, lineno=0, indent=0, options=None) A single interactive example, consisting of a Python statement and its expected - output. The constructor arguments are used to initialize the member variables - of the same names. + output. The constructor arguments are used to initialize the attributes of + the same names. - :class:`Example` defines the following member variables. They are initialized by + :class:`Example` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1675,9 +1674,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example's actual output did not match its expected output. The constructor arguments are - used to initialize the member variables of the same names. + used to initialize the attributes of the same names. -:exc:`DocTestFailure` defines the following member variables: +:exc:`DocTestFailure` defines the following attributes: .. attribute:: DocTestFailure.test @@ -1699,9 +1698,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example raised an unexpected exception. The constructor arguments are used - to initialize the member variables of the same names. + to initialize the attributes of the same names. -:exc:`UnexpectedException` defines the following member variables: +:exc:`UnexpectedException` defines the following attributes: .. attribute:: UnexpectedException.test diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -61,7 +61,7 @@ time is used. This module ignores the timestamp when decompressing; however, some programs, such as :program:`gunzip`\ , make use of it. The format of the timestamp is the same as that of the return value of - ``time.time()`` and of the ``st_mtime`` member of the object returned + ``time.time()`` and of the ``st_mtime`` attribute of the object returned by ``os.stat()``. Calling a :class:`GzipFile` object's :meth:`close` method does not close diff --git a/Doc/library/html.entities.rst b/Doc/library/html.entities.rst --- a/Doc/library/html.entities.rst +++ b/Doc/library/html.entities.rst @@ -11,7 +11,7 @@ This module defines three dictionaries, ``name2codepoint``, ``codepoint2name``, and ``entitydefs``. ``entitydefs`` is used to provide the :attr:`entitydefs` -member of the :class:`html.parser.HTMLParser` class. The definition provided +attribute of the :class:`html.parser.HTMLParser` class. The definition provided here contains all the entities defined by XHTML 1.0 that can be handled using simple textual substitution in the Latin-1 character set (ISO-8859-1). diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst --- a/Doc/library/http.cookies.rst +++ b/Doc/library/http.cookies.rst @@ -152,7 +152,7 @@ .. method:: Morsel.set(key, value, coded_value) - Set the *key*, *value* and *coded_value* members. + Set the *key*, *value* and *coded_value* attributes. .. method:: Morsel.isReservedKey(K) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -391,8 +391,8 @@ :class:`RawIOBase` implementation, but wrap one, like :class:`BufferedWriter` and :class:`BufferedReader` do. - :class:`BufferedIOBase` provides or overrides these members in addition to - those from :class:`IOBase`: + :class:`BufferedIOBase` provides or overrides these methods and attribute in + addition to those from :class:`IOBase`: .. attribute:: raw diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst --- a/Doc/library/nntplib.rst +++ b/Doc/library/nntplib.rst @@ -394,7 +394,7 @@ Send an ``ARTICLE`` command, where *message_spec* has the same meaning as for :meth:`stat`. Return a tuple ``(response, info)`` where *info* - is a :class:`~collections.namedtuple` with three members *number*, + is a :class:`~collections.namedtuple` with three attributes *number*, *message_id* and *lines* (in that order). *number* is the article number in the group (or 0 if the information is not available), *message_id* the message id as a string, and *lines* a list of lines (without terminating diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1339,11 +1339,12 @@ .. note:: - The exact meaning and resolution of the :attr:`st_atime`, :attr:`st_mtime`, and - :attr:`st_ctime` members depends on the operating system and the file system. - For example, on Windows systems using the FAT or FAT32 file systems, - :attr:`st_mtime` has 2-second resolution, and :attr:`st_atime` has only 1-day - resolution. See your operating system documentation for details. + The exact meaning and resolution of the :attr:`st_atime`, + :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating + system and the file system. For example, on Windows systems using the FAT + or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and + :attr:`st_atime` has only 1-day resolution. See your operating system + documentation for details. For backward compatibility, the return value of :func:`~os.stat` is also accessible as a tuple of at least 10 integers giving the most important (and portable) diff --git a/Doc/library/pyclbr.rst b/Doc/library/pyclbr.rst --- a/Doc/library/pyclbr.rst +++ b/Doc/library/pyclbr.rst @@ -45,7 +45,7 @@ The :class:`Class` objects used as values in the dictionary returned by :func:`readmodule` and :func:`readmodule_ex` provide the following data -members: +attributes: .. attribute:: Class.module @@ -89,7 +89,7 @@ ---------------- The :class:`Function` objects used as values in the dictionary returned by -:func:`readmodule_ex` provide the following data members: +:func:`readmodule_ex` provide the following attributes: .. attribute:: Function.module diff --git a/Doc/library/reprlib.rst b/Doc/library/reprlib.rst --- a/Doc/library/reprlib.rst +++ b/Doc/library/reprlib.rst @@ -66,7 +66,7 @@ Repr Objects ------------ -:class:`Repr` instances provide several members which can be used to provide +:class:`Repr` instances provide several attributes which can be used to provide size limits for the representations of different object types, and methods which format specific object types. diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst --- a/Doc/library/shlex.rst +++ b/Doc/library/shlex.rst @@ -24,8 +24,8 @@ Split the string *s* using shell-like syntax. If *comments* is :const:`False` (the default), the parsing of comments in the given string will be disabled - (setting the :attr:`commenters` member of the :class:`shlex` instance to the - empty string). This function operates in POSIX mode by default, but uses + (setting the :attr:`commenters` attribute of the :class:`shlex` instance to + the empty string). This function operates in POSIX mode by default, but uses non-POSIX mode if the *posix* argument is false. .. note:: @@ -44,7 +44,7 @@ from. It must be a file-/stream-like object with :meth:`read` and :meth:`readline` methods, or a string. If no argument is given, input will be taken from ``sys.stdin``. The second optional argument is a filename - string, which sets the initial value of the :attr:`infile` member. If the + string, which sets the initial value of the :attr:`infile` attribute. If the *instream* argument is omitted or equal to ``sys.stdin``, this second argument defaults to "stdin". The *posix* argument defines the operational mode: when *posix* is not true (default), the :class:`shlex` instance will @@ -202,8 +202,8 @@ .. attribute:: shlex.source - This member is ``None`` by default. If you assign a string to it, that string - will be recognized as a lexical-level inclusion request similar to the + This attribute is ``None`` by default. If you assign a string to it, that + string will be recognized as a lexical-level inclusion request similar to the ``source`` keyword in various shells. That is, the immediately following token will opened as a filename and input taken from that stream until EOF, at which point the :meth:`close` method of that stream will be called and the input @@ -213,7 +213,7 @@ .. attribute:: shlex.debug - If this member is numeric and ``1`` or more, a :class:`shlex` instance will + If this attribute is numeric and ``1`` or more, a :class:`shlex` instance will print verbose progress output on its behavior. If you need to use this, you can read the module source code to learn the details. diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -81,7 +81,7 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass The mix-in class must come first, since it overrides a method defined in -:class:`UDPServer`. Setting the various member variables also changes the +:class:`UDPServer`. Setting the various attributes also change the behavior of the underlying server mechanism. To implement a service, you must derive a class from :class:`BaseRequestHandler` diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2567,7 +2567,7 @@ foo`` does not require a module object named *foo* to exist, rather it requires an (external) *definition* for a module named *foo* somewhere.) -A special member of every module is :attr:`__dict__`. This is the dictionary +A special attribute of every module is :attr:`__dict__`. This is the dictionary containing the module's symbol table. Modifying this dictionary will actually change the module's symbol table, but direct assignment to the :attr:`__dict__` attribute is not possible (you can write ``m.__dict__['a'] = 1``, which defines diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -497,38 +497,39 @@ .. attribute:: dwFlags - A bit field that determines whether certain :class:`STARTUPINFO` members - are used when the process creates a window. :: + A bit field that determines whether certain :class:`STARTUPINFO` + attributes are used when the process creates a window. :: si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW .. attribute:: hStdInput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard input handle for the process. If :data:`STARTF_USESTDHANDLES` - is not specified, the default for standard input is the keyboard buffer. + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard input handle for the process. If + :data:`STARTF_USESTDHANDLES` is not specified, the default for standard + input is the keyboard buffer. .. attribute:: hStdOutput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard output handle for the process. Otherwise, this member is - ignored and the default for standard output is the console window's + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard output handle for the process. Otherwise, this attribute + is ignored and the default for standard output is the console window's buffer. .. attribute:: hStdError - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard error handle for the process. Otherwise, this member is + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard error handle for the process. Otherwise, this attribute is ignored and the default for standard error is the console window's buffer. .. attribute:: wShowWindow - If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member + If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this attribute can be any of the values that can be specified in the ``nCmdShow`` parameter for the `ShowWindow `__ - function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is + function, except for ``SW_SHOWDEFAULT``. Otherwise, this attribute is ignored. :data:`SW_HIDE` is provided for this attribute. It is used when @@ -562,12 +563,12 @@ .. data:: STARTF_USESTDHANDLES Specifies that the :attr:`STARTUPINFO.hStdInput`, - :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members + :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` attributes contain additional information. .. data:: STARTF_USESHOWWINDOW - Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains + Specifies that the :attr:`STARTUPINFO.wShowWindow` attribute contains additional information. .. data:: CREATE_NEW_CONSOLE diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -60,7 +60,7 @@ This function operates exactly as :func:`TemporaryFile` does, except that the file is guaranteed to have a visible name in the file system (on Unix, the directory entry is not unlinked). That name can be retrieved - from the :attr:`name` member of the file object. Whether the name can be + from the :attr:`name` attribute of the file object. Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows NT or later). If *delete* is true (the default), the file is @@ -96,7 +96,7 @@ of the temporary directory object), the newly created temporary directory and all its contents are removed from the filesystem. - The directory name can be retrieved from the :attr:`name` member + The directory name can be retrieved from the :attr:`name` attribute of the returned object. The directory can be explicitly cleaned up by calling the 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 @@ -105,7 +105,7 @@ can be imported), :class:`HTTPSHandler` will also be added. A :class:`BaseHandler` subclass may also change its :attr:`handler_order` - member variable to modify its position in the handlers list. + attribute to modify its position in the handlers list. .. function:: pathname2url(path) @@ -536,7 +536,7 @@ Remove any parents. -The following members and methods should only be used by classes derived from +The following attribute and methods should only be used by classes derived from :class:`BaseHandler`. .. note:: diff --git a/Doc/library/xdrlib.rst b/Doc/library/xdrlib.rst --- a/Doc/library/xdrlib.rst +++ b/Doc/library/xdrlib.rst @@ -260,7 +260,7 @@ .. exception:: Error - The base exception class. :exc:`Error` has a single public data member + The base exception class. :exc:`Error` has a single public attribute :attr:`msg` containing the description of the error. diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -136,7 +136,7 @@ :class:`Fault` or :class:`ProtocolError` object indicating an error. Servers that support the XML introspection API support some common methods -grouped under the reserved :attr:`system` member: +grouped under the reserved :attr:`system` attribute: .. method:: ServerProxy.system.listMethods() @@ -310,7 +310,7 @@ ------------- A :class:`Fault` object encapsulates the content of an XML-RPC fault tag. Fault -objects have the following members: +objects have the following attributes: .. attribute:: Fault.faultCode @@ -359,7 +359,7 @@ A :class:`ProtocolError` object describes a protocol error in the underlying transport layer (such as a 404 'not found' error if the server named by the URI -does not exist). It has the following members: +does not exist). It has the following attributes: .. attribute:: ProtocolError.url diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1459,7 +1459,7 @@ On FreeBSD, the :func:`os.stat` function now returns times with nanosecond resolution, and the returned object now has :attr:`st_gen` and - :attr:`st_birthtime`. The :attr:`st_flags` member is also available, if the + :attr:`st_birthtime`. The :attr:`st_flags` attribute is also available, if the platform supports it. (Contributed by Antti Louko and Diego Petten?.) .. (Patch 1180695, 1212117) -- Repository URL: http://hg.python.org/cpython-gd From python-checkins at python.org Mon Jul 4 20:51:17 2011 From: python-checkins at python.org (local-hg) Date: Mon, 04 Jul 2011 20:51:17 +0200 Subject: [Python-checkins] =?utf8?q?cpython-gd_=28merge_3=2E2_-=3E_default?= =?utf8?q?=29=3A_Merge_from_3=2E2_=2E_Replace_the_term_members_with_correc?= =?utf8?q?t__and_appropriate?= Message-ID: http://hg.python.org/cpython-gd/rev/283f20f1d31f changeset: 71209:283f20f1d31f parent: 71207:24297278c78d parent: 71208:d442c313536b user: Senthil Kumaran date: Mon Jul 04 11:31:53 2011 -0700 files: Doc/library/cmd.rst Doc/library/datetime.rst Doc/library/gzip.rst Doc/library/io.rst Doc/library/nntplib.rst Doc/library/os.rst Doc/library/socketserver.rst Doc/library/stdtypes.rst Doc/library/subprocess.rst Doc/library/tempfile.rst Doc/library/urllib.request.rst description: Merge from 3.2 . Replace the term members with correct and appropriate terminology. Initial patch by Adam Woodbeck. summary: Merge from 3.2 . Replace the term members with correct and appropriate terminology. Initial patch by Adam Woodbeck. files: Doc/library/cmd.rst | 2 +- Doc/library/curses.rst | 4 +- Doc/library/datetime.rst | 133 ++++++++++---------- Doc/library/decimal.rst | 2 +- Doc/library/doctest.rst | 19 +- Doc/library/gzip.rst | 2 +- Doc/library/html.entities.rst | 2 +- Doc/library/http.cookies.rst | 2 +- Doc/library/io.rst | 4 +- Doc/library/nntplib.rst | 2 +- Doc/library/os.rst | 11 +- Doc/library/pyclbr.rst | 4 +- Doc/library/reprlib.rst | 2 +- Doc/library/shlex.rst | 12 +- Doc/library/socketserver.rst | 2 +- Doc/library/stdtypes.rst | 2 +- Doc/library/subprocess.rst | 29 ++-- Doc/library/tempfile.rst | 4 +- Doc/library/urllib.request.rst | 4 +- Doc/library/xdrlib.rst | 2 +- Doc/library/xmlrpc.client.rst | 6 +- Doc/whatsnew/2.5.rst | 2 +- 22 files changed, 127 insertions(+), 125 deletions(-) diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst --- a/Doc/library/cmd.rst +++ b/Doc/library/cmd.rst @@ -50,7 +50,7 @@ the line as argument. The optional argument is a banner or intro string to be issued before the first - prompt (this overrides the :attr:`intro` class member). + prompt (this overrides the :attr:`intro` class attribute). If the :mod:`readline` module is loaded, input will automatically inherit :program:`bash`\ -like history-list editing (e.g. :kbd:`Control-P` scrolls back diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1639,7 +1639,7 @@ each keystroke entered with the keystroke as a parameter; command dispatch is done on the result. This method returns the window contents as a string; whether blanks in the window are included is affected by the - :attr:`stripspaces` member. + :attr:`stripspaces` attribute. .. method:: do_command(ch) @@ -1711,7 +1711,7 @@ .. attribute:: stripspaces - This data member is a flag which controls the interpretation of blanks in + This attribute is a flag which controls the interpretation of blanks in the window. When it is on, trailing blanks on each line are ignored; any cursor motion that would land the cursor on a trailing blank goes to the end of that line instead, and trailing blanks are stripped when the window diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -11,7 +11,7 @@ The :mod:`datetime` module supplies classes for manipulating dates and times in both simple and complex ways. While date and time arithmetic is supported, the -focus of the implementation is on efficient member extraction for output +focus of the implementation is on efficient attribute extraction for output formatting and manipulation. For related functionality, see also the :mod:`time` and :mod:`calendar` modules. @@ -25,7 +25,7 @@ work with, at the cost of ignoring some aspects of reality. For applications requiring more, :class:`datetime` and :class:`time` objects -have an optional time zone information member, :attr:`tzinfo`, that can contain +have an optional time zone information attribute, :attr:`tzinfo`, that can contain an instance of a subclass of the abstract :class:`tzinfo` class. These :class:`tzinfo` objects capture information about the offset from UTC time, the time zone name, and whether Daylight Saving Time is in effect. Note that only @@ -499,9 +499,9 @@ .. method:: date.replace(year, month, day) - Return a date with the same value, except for those members given new values by - whichever keyword arguments are specified. For example, if ``d == date(2002, - 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. + Return a date with the same value, except for those parameters given new + values by whichever keyword arguments are specified. For example, if ``d == + date(2002, 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. .. method:: date.timetuple() @@ -748,11 +748,11 @@ .. classmethod:: datetime.combine(date, time) - Return a new :class:`datetime` object whose date members are equal to the given - :class:`date` object's, and whose time and :attr:`tzinfo` members are equal to - the given :class:`time` object's. For any :class:`datetime` object *d*, ``d == - datetime.combine(d.date(), d.timetz())``. If date is a :class:`datetime` - object, its time and :attr:`tzinfo` members are ignored. + Return a new :class:`datetime` object whose date attributes are equal to the + given :class:`date` object's, and whose time and :attr:`tzinfo` attributes are + equal to the given :class:`time` object's. For any :class:`datetime` object + *d*, ``d == datetime.combine(d.date(), d.timetz())``. If date is a + :class:`datetime` object, its time and :attr:`tzinfo` attributes are ignored. .. classmethod:: datetime.strptime(date_string, format) @@ -846,43 +846,44 @@ (1) datetime2 is a duration of timedelta removed from datetime1, moving forward in time if ``timedelta.days`` > 0, or backward if ``timedelta.days`` < 0. The - result has the same :attr:`tzinfo` member as the input datetime, and datetime2 - - datetime1 == timedelta after. :exc:`OverflowError` is raised if datetime2.year - would be smaller than :const:`MINYEAR` or larger than :const:`MAXYEAR`. Note - that no time zone adjustments are done even if the input is an aware object. + result has the same :attr:`tzinfo` attribute as the input datetime, and + datetime2 - datetime1 == timedelta after. :exc:`OverflowError` is raised if + datetime2.year would be smaller than :const:`MINYEAR` or larger than + :const:`MAXYEAR`. Note that no time zone adjustments are done even if the + input is an aware object. (2) Computes the datetime2 such that datetime2 + timedelta == datetime1. As for - addition, the result has the same :attr:`tzinfo` member as the input datetime, - and no time zone adjustments are done even if the input is aware. This isn't - quite equivalent to datetime1 + (-timedelta), because -timedelta in isolation - can overflow in cases where datetime1 - timedelta does not. + addition, the result has the same :attr:`tzinfo` attribute as the input + datetime, and no time zone adjustments are done even if the input is aware. + This isn't quite equivalent to datetime1 + (-timedelta), because -timedelta + in isolation can overflow in cases where datetime1 - timedelta does not. (3) Subtraction of a :class:`datetime` from a :class:`datetime` is defined only if both operands are naive, or if both are aware. If one is aware and the other is naive, :exc:`TypeError` is raised. - If both are naive, or both are aware and have the same :attr:`tzinfo` member, - the :attr:`tzinfo` members are ignored, and the result is a :class:`timedelta` + If both are naive, or both are aware and have the same :attr:`tzinfo` attribute, + the :attr:`tzinfo` attributes are ignored, and the result is a :class:`timedelta` object *t* such that ``datetime2 + t == datetime1``. No time zone adjustments are done in this case. - If both are aware and have different :attr:`tzinfo` members, ``a-b`` acts as if - *a* and *b* were first converted to naive UTC datetimes first. The result is - ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - - b.utcoffset())`` except that the implementation never overflows. + If both are aware and have different :attr:`tzinfo` attributes, ``a-b`` acts + as if *a* and *b* were first converted to naive UTC datetimes first. The + result is ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) + - b.utcoffset())`` except that the implementation never overflows. (4) *datetime1* is considered less than *datetime2* when *datetime1* precedes *datetime2* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. - If both comparands are aware, and have the same :attr:`tzinfo` member, the - common :attr:`tzinfo` member is ignored and the base datetimes are compared. If - both comparands are aware and have different :attr:`tzinfo` members, the - comparands are first adjusted by subtracting their UTC offsets (obtained from - ``self.utcoffset()``). + If both comparands are aware, and have the same :attr:`tzinfo` attribute, the + common :attr:`tzinfo` attribute is ignored and the base datetimes are + compared. If both comparands are aware and have different :attr:`tzinfo` + attributes, the comparands are first adjusted by subtracting their UTC + offsets (obtained from ``self.utcoffset()``). .. note:: @@ -915,22 +916,22 @@ .. method:: datetime.timetz() Return :class:`time` object with same hour, minute, second, microsecond, and - tzinfo members. See also method :meth:`time`. + tzinfo attributes. See also method :meth:`time`. .. method:: datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]]) - Return a datetime with the same members, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive datetime from an aware datetime with no - conversion of date and time members. + Return a datetime with the same attributes, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive datetime from an aware + datetime with no conversion of date and time attributes. .. method:: datetime.astimezone(tz) - Return a :class:`datetime` object with new :attr:`tzinfo` member *tz*, adjusting - the date and time members so the result is the same UTC time as *self*, but in - *tz*'s local time. + Return a :class:`datetime` object with new :attr:`tzinfo` attribute *tz*, + adjusting the date and time attributes so the result is the same UTC time as + *self*, but in *tz*'s local time. *tz* must be an instance of a :class:`tzinfo` subclass, and its :meth:`utcoffset` and :meth:`dst` methods must not return ``None``. *self* must @@ -938,18 +939,18 @@ not return ``None``). If ``self.tzinfo`` is *tz*, ``self.astimezone(tz)`` is equal to *self*: no - adjustment of date or time members is performed. Else the result is local time - in time zone *tz*, representing the same UTC time as *self*: after ``astz = - dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have the same date - and time members as ``dt - dt.utcoffset()``. The discussion of class - :class:`tzinfo` explains the cases at Daylight Saving Time transition boundaries - where this cannot be achieved (an issue only if *tz* models both standard and - daylight time). + adjustment of date or time attributes is performed. Else the result is local + time in time zone *tz*, representing the same UTC time as *self*: after + ``astz = dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have + the same date and time attributes as ``dt - dt.utcoffset()``. The discussion + of class :class:`tzinfo` explains the cases at Daylight Saving Time transition + boundaries where this cannot be achieved (an issue only if *tz* models both + standard and daylight time). If you merely want to attach a time zone object *tz* to a datetime *dt* without - adjustment of date and time members, use ``dt.replace(tzinfo=tz)``. If you + adjustment of date and time attributes, use ``dt.replace(tzinfo=tz)``. If you merely want to remove the time zone object from an aware datetime *dt* without - conversion of date and time members, use ``dt.replace(tzinfo=None)``. + conversion of date and time attributes, use ``dt.replace(tzinfo=None)``. Note that the default :meth:`tzinfo.fromutc` method can be overridden in a :class:`tzinfo` subclass to affect the result returned by :meth:`astimezone`. @@ -1260,14 +1261,14 @@ * comparison of :class:`time` to :class:`time`, where *a* is considered less than *b* when *a* precedes *b* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. If both comparands are aware, and have - the same :attr:`tzinfo` member, the common :attr:`tzinfo` member is ignored and - the base times are compared. If both comparands are aware and have different - :attr:`tzinfo` members, the comparands are first adjusted by subtracting their - UTC offsets (obtained from ``self.utcoffset()``). In order to stop mixed-type - comparisons from falling back to the default comparison by object address, when - a :class:`time` object is compared to an object of a different type, - :exc:`TypeError` is raised unless the comparison is ``==`` or ``!=``. The - latter cases return :const:`False` or :const:`True`, respectively. + the same :attr:`tzinfo` attribute, the common :attr:`tzinfo` attribute is + ignored and the base times are compared. If both comparands are aware and + have different :attr:`tzinfo` attributes, the comparands are first adjusted by + subtracting their UTC offsets (obtained from ``self.utcoffset()``). In order + to stop mixed-type comparisons from falling back to the default comparison by + object address, when a :class:`time` object is compared to an object of a + different type, :exc:`TypeError` is raised unless the comparison is ``==`` or + ``!=``. The latter cases return :const:`False` or :const:`True`, respectively. * hash, use as dict key @@ -1282,10 +1283,10 @@ .. method:: time.replace([hour[, minute[, second[, microsecond[, tzinfo]]]]]) - Return a :class:`time` with the same value, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive :class:`time` from an aware :class:`time`, - without conversion of the time members. + Return a :class:`time` with the same value, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive :class:`time` from an + aware :class:`time`, without conversion of the time attributes. .. method:: time.isoformat() @@ -1370,7 +1371,7 @@ An instance of (a concrete subclass of) :class:`tzinfo` can be passed to the constructors for :class:`datetime` and :class:`time` objects. The latter objects -view their members as being in local time, and the :class:`tzinfo` object +view their attributes as being in local time, and the :class:`tzinfo` object supports methods revealing offset of local time from UTC, the name of the time zone, and DST offset, all relative to a date or time object passed to them. @@ -1415,9 +1416,9 @@ already been added to the UTC offset returned by :meth:`utcoffset`, so there's no need to consult :meth:`dst` unless you're interested in obtaining DST info separately. For example, :meth:`datetime.timetuple` calls its :attr:`tzinfo` - member's :meth:`dst` method to determine how the :attr:`tm_isdst` flag should be - set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for DST changes - when crossing time zones. + attribute's :meth:`dst` method to determine how the :attr:`tm_isdst` flag + should be set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for + DST changes when crossing time zones. An instance *tz* of a :class:`tzinfo` subclass that models both standard and daylight times must be consistent in this sense: @@ -1493,10 +1494,10 @@ .. method:: tzinfo.fromutc(dt) This is called from the default :class:`datetime.astimezone()` implementation. - When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time members - are to be viewed as expressing a UTC time. The purpose of :meth:`fromutc` is to - adjust the date and time members, returning an equivalent datetime in *self*'s - local time. + When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time + attributes are to be viewed as expressing a UTC time. The purpose of + :meth:`fromutc` is to adjust the date and time attributes, returning an + equivalent datetime in *self*'s local time. Most :class:`tzinfo` subclasses should be able to inherit the default :meth:`fromutc` implementation without problems. It's strong enough to handle diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -654,7 +654,7 @@ Normalize the number by stripping the rightmost trailing zeros and converting any result equal to :const:`Decimal('0')` to - :const:`Decimal('0e0')`. Used for producing canonical values for members + :const:`Decimal('0e0')`. Used for producing canonical values for attributes of an equivalence class. For example, ``Decimal('32.100')`` and ``Decimal('0.321000e+2')`` both normalize to the equivalent value ``Decimal('32.1')``. diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1127,11 +1127,10 @@ .. class:: DocTest(examples, globs, name, filename, lineno, docstring) A collection of doctest examples that should be run in a single namespace. The - constructor arguments are used to initialize the member variables of the same - names. + constructor arguments are used to initialize the attributes of the same names. - :class:`DocTest` defines the following member variables. They are initialized by + :class:`DocTest` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1184,11 +1183,11 @@ .. class:: Example(source, want, exc_msg=None, lineno=0, indent=0, options=None) A single interactive example, consisting of a Python statement and its expected - output. The constructor arguments are used to initialize the member variables - of the same names. + output. The constructor arguments are used to initialize the attributes of + the same names. - :class:`Example` defines the following member variables. They are initialized by + :class:`Example` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1675,9 +1674,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example's actual output did not match its expected output. The constructor arguments are - used to initialize the member variables of the same names. + used to initialize the attributes of the same names. -:exc:`DocTestFailure` defines the following member variables: +:exc:`DocTestFailure` defines the following attributes: .. attribute:: DocTestFailure.test @@ -1699,9 +1698,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example raised an unexpected exception. The constructor arguments are used - to initialize the member variables of the same names. + to initialize the attributes of the same names. -:exc:`UnexpectedException` defines the following member variables: +:exc:`UnexpectedException` defines the following attributes: .. attribute:: UnexpectedException.test diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -61,7 +61,7 @@ time is used. This module ignores the timestamp when decompressing; however, some programs, such as :program:`gunzip`\ , make use of it. The format of the timestamp is the same as that of the return value of - ``time.time()`` and of the ``st_mtime`` member of the object returned + ``time.time()`` and of the ``st_mtime`` attribute of the object returned by ``os.stat()``. Calling a :class:`GzipFile` object's :meth:`close` method does not close diff --git a/Doc/library/html.entities.rst b/Doc/library/html.entities.rst --- a/Doc/library/html.entities.rst +++ b/Doc/library/html.entities.rst @@ -11,7 +11,7 @@ This module defines three dictionaries, ``name2codepoint``, ``codepoint2name``, and ``entitydefs``. ``entitydefs`` is used to provide the :attr:`entitydefs` -member of the :class:`html.parser.HTMLParser` class. The definition provided +attribute of the :class:`html.parser.HTMLParser` class. The definition provided here contains all the entities defined by XHTML 1.0 that can be handled using simple textual substitution in the Latin-1 character set (ISO-8859-1). diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst --- a/Doc/library/http.cookies.rst +++ b/Doc/library/http.cookies.rst @@ -152,7 +152,7 @@ .. method:: Morsel.set(key, value, coded_value) - Set the *key*, *value* and *coded_value* members. + Set the *key*, *value* and *coded_value* attributes. .. method:: Morsel.isReservedKey(K) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -391,8 +391,8 @@ :class:`RawIOBase` implementation, but wrap one, like :class:`BufferedWriter` and :class:`BufferedReader` do. - :class:`BufferedIOBase` provides or overrides these members in addition to - those from :class:`IOBase`: + :class:`BufferedIOBase` provides or overrides these methods and attribute in + addition to those from :class:`IOBase`: .. attribute:: raw diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst --- a/Doc/library/nntplib.rst +++ b/Doc/library/nntplib.rst @@ -407,7 +407,7 @@ Send an ``ARTICLE`` command, where *message_spec* has the same meaning as for :meth:`stat`. Return a tuple ``(response, info)`` where *info* - is a :class:`~collections.namedtuple` with three members *number*, + is a :class:`~collections.namedtuple` with three attributes *number*, *message_id* and *lines* (in that order). *number* is the article number in the group (or 0 if the information is not available), *message_id* the message id as a string, and *lines* a list of lines (without terminating diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1826,11 +1826,12 @@ .. note:: - The exact meaning and resolution of the :attr:`st_atime`, :attr:`st_mtime`, and - :attr:`st_ctime` members depends on the operating system and the file system. - For example, on Windows systems using the FAT or FAT32 file systems, - :attr:`st_mtime` has 2-second resolution, and :attr:`st_atime` has only 1-day - resolution. See your operating system documentation for details. + The exact meaning and resolution of the :attr:`st_atime`, + :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating + system and the file system. For example, on Windows systems using the FAT + or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and + :attr:`st_atime` has only 1-day resolution. See your operating system + documentation for details. For backward compatibility, the return value of :func:`~os.stat` is also accessible as a tuple of at least 10 integers giving the most important (and portable) diff --git a/Doc/library/pyclbr.rst b/Doc/library/pyclbr.rst --- a/Doc/library/pyclbr.rst +++ b/Doc/library/pyclbr.rst @@ -45,7 +45,7 @@ The :class:`Class` objects used as values in the dictionary returned by :func:`readmodule` and :func:`readmodule_ex` provide the following data -members: +attributes: .. attribute:: Class.module @@ -89,7 +89,7 @@ ---------------- The :class:`Function` objects used as values in the dictionary returned by -:func:`readmodule_ex` provide the following data members: +:func:`readmodule_ex` provide the following attributes: .. attribute:: Function.module diff --git a/Doc/library/reprlib.rst b/Doc/library/reprlib.rst --- a/Doc/library/reprlib.rst +++ b/Doc/library/reprlib.rst @@ -66,7 +66,7 @@ Repr Objects ------------ -:class:`Repr` instances provide several members which can be used to provide +:class:`Repr` instances provide several attributes which can be used to provide size limits for the representations of different object types, and methods which format specific object types. diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst --- a/Doc/library/shlex.rst +++ b/Doc/library/shlex.rst @@ -24,8 +24,8 @@ Split the string *s* using shell-like syntax. If *comments* is :const:`False` (the default), the parsing of comments in the given string will be disabled - (setting the :attr:`commenters` member of the :class:`shlex` instance to the - empty string). This function operates in POSIX mode by default, but uses + (setting the :attr:`commenters` attribute of the :class:`shlex` instance to + the empty string). This function operates in POSIX mode by default, but uses non-POSIX mode if the *posix* argument is false. .. note:: @@ -44,7 +44,7 @@ from. It must be a file-/stream-like object with :meth:`read` and :meth:`readline` methods, or a string. If no argument is given, input will be taken from ``sys.stdin``. The second optional argument is a filename - string, which sets the initial value of the :attr:`infile` member. If the + string, which sets the initial value of the :attr:`infile` attribute. If the *instream* argument is omitted or equal to ``sys.stdin``, this second argument defaults to "stdin". The *posix* argument defines the operational mode: when *posix* is not true (default), the :class:`shlex` instance will @@ -202,8 +202,8 @@ .. attribute:: shlex.source - This member is ``None`` by default. If you assign a string to it, that string - will be recognized as a lexical-level inclusion request similar to the + This attribute is ``None`` by default. If you assign a string to it, that + string will be recognized as a lexical-level inclusion request similar to the ``source`` keyword in various shells. That is, the immediately following token will opened as a filename and input taken from that stream until EOF, at which point the :meth:`close` method of that stream will be called and the input @@ -213,7 +213,7 @@ .. attribute:: shlex.debug - If this member is numeric and ``1`` or more, a :class:`shlex` instance will + If this attribute is numeric and ``1`` or more, a :class:`shlex` instance will print verbose progress output on its behavior. If you need to use this, you can read the module source code to learn the details. diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -81,7 +81,7 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass The mix-in class must come first, since it overrides a method defined in -:class:`UDPServer`. Setting the various member variables also changes the +:class:`UDPServer`. Setting the various attributes also change the behavior of the underlying server mechanism. To implement a service, you must derive a class from :class:`BaseRequestHandler` diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2578,7 +2578,7 @@ foo`` does not require a module object named *foo* to exist, rather it requires an (external) *definition* for a module named *foo* somewhere.) -A special member of every module is :attr:`__dict__`. This is the dictionary +A special attribute of every module is :attr:`__dict__`. This is the dictionary containing the module's symbol table. Modifying this dictionary will actually change the module's symbol table, but direct assignment to the :attr:`__dict__` attribute is not possible (you can write ``m.__dict__['a'] = 1``, which defines diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -567,38 +567,39 @@ .. attribute:: dwFlags - A bit field that determines whether certain :class:`STARTUPINFO` members - are used when the process creates a window. :: + A bit field that determines whether certain :class:`STARTUPINFO` + attributes are used when the process creates a window. :: si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW .. attribute:: hStdInput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard input handle for the process. If :data:`STARTF_USESTDHANDLES` - is not specified, the default for standard input is the keyboard buffer. + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard input handle for the process. If + :data:`STARTF_USESTDHANDLES` is not specified, the default for standard + input is the keyboard buffer. .. attribute:: hStdOutput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard output handle for the process. Otherwise, this member is - ignored and the default for standard output is the console window's + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard output handle for the process. Otherwise, this attribute + is ignored and the default for standard output is the console window's buffer. .. attribute:: hStdError - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard error handle for the process. Otherwise, this member is + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard error handle for the process. Otherwise, this attribute is ignored and the default for standard error is the console window's buffer. .. attribute:: wShowWindow - If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member + If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this attribute can be any of the values that can be specified in the ``nCmdShow`` parameter for the `ShowWindow `__ - function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is + function, except for ``SW_SHOWDEFAULT``. Otherwise, this attribute is ignored. :data:`SW_HIDE` is provided for this attribute. It is used when @@ -632,12 +633,12 @@ .. data:: STARTF_USESTDHANDLES Specifies that the :attr:`STARTUPINFO.hStdInput`, - :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members + :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` attributes contain additional information. .. data:: STARTF_USESHOWWINDOW - Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains + Specifies that the :attr:`STARTUPINFO.wShowWindow` attribute contains additional information. .. data:: CREATE_NEW_CONSOLE diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -60,7 +60,7 @@ This function operates exactly as :func:`TemporaryFile` does, except that the file is guaranteed to have a visible name in the file system (on Unix, the directory entry is not unlinked). That name can be retrieved - from the :attr:`name` member of the file object. Whether the name can be + from the :attr:`name` attribute of the file object. Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows NT or later). If *delete* is true (the default), the file is @@ -96,7 +96,7 @@ of the temporary directory object), the newly created temporary directory and all its contents are removed from the filesystem. - The directory name can be retrieved from the :attr:`name` member + The directory name can be retrieved from the :attr:`name` attribute of the returned object. The directory can be explicitly cleaned up by calling the 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 @@ -105,7 +105,7 @@ can be imported), :class:`HTTPSHandler` will also be added. A :class:`BaseHandler` subclass may also change its :attr:`handler_order` - member variable to modify its position in the handlers list. + attribute to modify its position in the handlers list. .. function:: pathname2url(path) @@ -546,7 +546,7 @@ Remove any parents. -The following members and methods should only be used by classes derived from +The following attribute and methods should only be used by classes derived from :class:`BaseHandler`. .. note:: diff --git a/Doc/library/xdrlib.rst b/Doc/library/xdrlib.rst --- a/Doc/library/xdrlib.rst +++ b/Doc/library/xdrlib.rst @@ -260,7 +260,7 @@ .. exception:: Error - The base exception class. :exc:`Error` has a single public data member + The base exception class. :exc:`Error` has a single public attribute :attr:`msg` containing the description of the error. diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -136,7 +136,7 @@ :class:`Fault` or :class:`ProtocolError` object indicating an error. Servers that support the XML introspection API support some common methods -grouped under the reserved :attr:`system` member: +grouped under the reserved :attr:`system` attribute: .. method:: ServerProxy.system.listMethods() @@ -310,7 +310,7 @@ ------------- A :class:`Fault` object encapsulates the content of an XML-RPC fault tag. Fault -objects have the following members: +objects have the following attributes: .. attribute:: Fault.faultCode @@ -359,7 +359,7 @@ A :class:`ProtocolError` object describes a protocol error in the underlying transport layer (such as a 404 'not found' error if the server named by the URI -does not exist). It has the following members: +does not exist). It has the following attributes: .. attribute:: ProtocolError.url diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1459,7 +1459,7 @@ On FreeBSD, the :func:`os.stat` function now returns times with nanosecond resolution, and the returned object now has :attr:`st_gen` and - :attr:`st_birthtime`. The :attr:`st_flags` member is also available, if the + :attr:`st_birthtime`. The :attr:`st_flags` attribute is also available, if the platform supports it. (Contributed by Antti Louko and Diego Petten?.) .. (Patch 1180695, 1212117) -- Repository URL: http://hg.python.org/cpython-gd From python-checkins at python.org Mon Jul 4 20:51:18 2011 From: python-checkins at python.org (local-hg) Date: Mon, 04 Jul 2011 20:51:18 +0200 Subject: [Python-checkins] =?utf8?q?cpython-gd_=283=2E2=29=3A_Fix_whitespa?= =?utf8?q?ce_nit_in_datetime_and_os_rst_files=2E?= Message-ID: http://hg.python.org/cpython-gd/rev/184192b3687c changeset: 71210:184192b3687c branch: 3.2 parent: 71208:d442c313536b user: Senthil Kumaran date: Mon Jul 04 11:43:51 2011 -0700 files: Doc/library/datetime.rst Doc/library/os.rst description: Fix whitespace nit in datetime and os rst files. summary: Fix whitespace nit in datetime and os rst files. files: Doc/library/datetime.rst | 2 +- Doc/library/os.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1251,7 +1251,7 @@ subtracting their UTC offsets (obtained from ``self.utcoffset()``). In order to stop mixed-type comparisons from falling back to the default comparison by object address, when a :class:`time` object is compared to an object of a - different type, :exc:`TypeError` is raised unless the comparison is ``==`` or + different type, :exc:`TypeError` is raised unless the comparison is ``==`` or ``!=``. The latter cases return :const:`False` or :const:`True`, respectively. * hash, use as dict key diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1339,7 +1339,7 @@ .. note:: - The exact meaning and resolution of the :attr:`st_atime`, + The exact meaning and resolution of the :attr:`st_atime`, :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating system and the file system. For example, on Windows systems using the FAT or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and -- Repository URL: http://hg.python.org/cpython-gd From python-checkins at python.org Mon Jul 4 20:51:18 2011 From: python-checkins at python.org (local-hg) Date: Mon, 04 Jul 2011 20:51:18 +0200 Subject: [Python-checkins] =?utf8?q?cpython-gd_=28merge_3=2E2_-=3E_default?= =?utf8?q?=29=3A_merge_from_3=2E2?= Message-ID: http://hg.python.org/cpython-gd/rev/f9d30fac3da0 changeset: 71211:f9d30fac3da0 parent: 71209:283f20f1d31f parent: 71210:184192b3687c user: Senthil Kumaran date: Mon Jul 04 11:44:17 2011 -0700 files: Doc/library/datetime.rst Doc/library/os.rst description: merge from 3.2 summary: merge from 3.2 files: Doc/library/datetime.rst | 2 +- Doc/library/os.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -1267,7 +1267,7 @@ subtracting their UTC offsets (obtained from ``self.utcoffset()``). In order to stop mixed-type comparisons from falling back to the default comparison by object address, when a :class:`time` object is compared to an object of a - different type, :exc:`TypeError` is raised unless the comparison is ``==`` or + different type, :exc:`TypeError` is raised unless the comparison is ``==`` or ``!=``. The latter cases return :const:`False` or :const:`True`, respectively. * hash, use as dict key diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1826,7 +1826,7 @@ .. note:: - The exact meaning and resolution of the :attr:`st_atime`, + The exact meaning and resolution of the :attr:`st_atime`, :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating system and the file system. For example, on Windows systems using the FAT or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and -- Repository URL: http://hg.python.org/cpython-gd From python-checkins at python.org Mon Jul 4 21:25:48 2011 From: python-checkins at python.org (local-hg) Date: Mon, 04 Jul 2011 21:25:48 +0200 Subject: [Python-checkins] =?utf8?q?hooks=3A_Save_stdout_before_calling_bu?= =?utf8?q?ildbot=27s_integrated_client_script?= Message-ID: http://hg.python.org/hooks/rev/fa3dd53cde8f changeset: 73:fa3dd53cde8f user: Antoine Pitrou date: Mon Jul 04 21:25:47 2011 +0200 summary: Save stdout before calling buildbot's integrated client script (attempting to fix a failure on push) files: hgbuildbot.py | 17 +++++++++++++---- 1 files changed, 13 insertions(+), 4 deletions(-) diff --git a/hgbuildbot.py b/hgbuildbot.py --- a/hgbuildbot.py +++ b/hgbuildbot.py @@ -20,6 +20,7 @@ import os import sys +from cStringIO import StringIO from mercurial.i18n import gettext as _ from mercurial.node import bin, hex, nullid @@ -110,8 +111,16 @@ 'files': files, 'branch': branch, }) - - for master in masters: - sendchanges(master, changes) - reactor.run() + old_stdout = sys.stdout + new_stdout = sys.stdout = StringIO() + try: + for master in masters: + sendchanges(master, changes) + reactor.run() + finally: + sys.stdout = old_stdout + new_stdout.seek(0) + for s in new_stdout: + ui.status(s) + -- Repository URL: http://hg.python.org/hooks From python-checkins at python.org Mon Jul 4 21:50:21 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 04 Jul 2011 21:50:21 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_closes_issu?= =?utf8?q?e10403_-_Let=27s_not_use_members_anymore=2E?= Message-ID: http://hg.python.org/cpython/rev/b8f5da066782 changeset: 71212:b8f5da066782 branch: 2.7 parent: 71188:a624b86264a4 user: Senthil Kumaran date: Mon Jul 04 12:50:02 2011 -0700 summary: Fix closes issue10403 - Let's not use members anymore. files: Doc/library/cmd.rst | 2 +- Doc/library/cookie.rst | 2 +- Doc/library/curses.rst | 4 +- Doc/library/datetime.rst | 133 +++++++++++----------- Doc/library/decimal.rst | 2 +- Doc/library/doctest.rst | 23 +-- Doc/library/gzip.rst | 2 +- Doc/library/htmllib.rst | 2 +- Doc/library/io.rst | 4 +- Doc/library/os.rst | 11 +- Doc/library/pyclbr.rst | 4 +- Doc/library/repr.rst | 2 +- Doc/library/shlex.rst | 12 +- Doc/library/socketserver.rst | 2 +- Doc/library/stdtypes.rst | 2 +- Doc/library/subprocess.rst | 29 ++-- Doc/library/tempfile.rst | 2 +- Doc/library/urllib2.rst | 4 +- Doc/library/xdrlib.rst | 2 +- Doc/library/xmlrpclib.rst | 6 +- Doc/whatsnew/2.5.rst | 2 +- 21 files changed, 127 insertions(+), 125 deletions(-) diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst --- a/Doc/library/cmd.rst +++ b/Doc/library/cmd.rst @@ -56,7 +56,7 @@ the line as argument. The optional argument is a banner or intro string to be issued before the first - prompt (this overrides the :attr:`intro` class member). + prompt (this overrides the :attr:`intro` class attribute). If the :mod:`readline` module is loaded, input will automatically inherit :program:`bash`\ -like history-list editing (e.g. :kbd:`Control-P` scrolls back diff --git a/Doc/library/cookie.rst b/Doc/library/cookie.rst --- a/Doc/library/cookie.rst +++ b/Doc/library/cookie.rst @@ -191,7 +191,7 @@ .. method:: Morsel.set(key, value, coded_value) - Set the *key*, *value* and *coded_value* members. + Set the *key*, *value* and *coded_value* attributes. .. method:: Morsel.isReservedKey(K) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1644,7 +1644,7 @@ each keystroke entered with the keystroke as a parameter; command dispatch is done on the result. This method returns the window contents as a string; whether blanks in the window are included is affected by the - :attr:`stripspaces` member. + :attr:`stripspaces` attribute. .. method:: do_command(ch) @@ -1716,7 +1716,7 @@ .. attribute:: stripspaces - This data member is a flag which controls the interpretation of blanks in + This attribute is a flag which controls the interpretation of blanks in the window. When it is on, trailing blanks on each line are ignored; any cursor motion that would land the cursor on a trailing blank goes to the end of that line instead, and trailing blanks are stripped when the window diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -13,7 +13,7 @@ The :mod:`datetime` module supplies classes for manipulating dates and times in both simple and complex ways. While date and time arithmetic is supported, the -focus of the implementation is on efficient member extraction for output +focus of the implementation is on efficient attribute extraction for output formatting and manipulation. For related functionality, see also the :mod:`time` and :mod:`calendar` modules. @@ -27,7 +27,7 @@ work with, at the cost of ignoring some aspects of reality. For applications requiring more, :class:`datetime` and :class:`time` objects -have an optional time zone information member, :attr:`tzinfo`, that can contain +have an optional time zone information attribute, :attr:`tzinfo`, that can contain an instance of a subclass of the abstract :class:`tzinfo` class. These :class:`tzinfo` objects capture information about the offset from UTC time, the time zone name, and whether Daylight Saving Time is in effect. Note that no @@ -463,9 +463,9 @@ .. method:: date.replace(year, month, day) - Return a date with the same value, except for those members given new values by - whichever keyword arguments are specified. For example, if ``d == date(2002, - 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. + Return a date with the same value, except for those parameters given new + values by whichever keyword arguments are specified. For example, if ``d == + date(2002, 12, 31)``, then ``d.replace(day=26) == date(2002, 12, 26)``. .. method:: date.timetuple() @@ -696,11 +696,11 @@ .. classmethod:: datetime.combine(date, time) - Return a new :class:`datetime` object whose date members are equal to the given - :class:`date` object's, and whose time and :attr:`tzinfo` members are equal to - the given :class:`time` object's. For any :class:`datetime` object *d*, ``d == - datetime.combine(d.date(), d.timetz())``. If date is a :class:`datetime` - object, its time and :attr:`tzinfo` members are ignored. + Return a new :class:`datetime` object whose date attributes are equal to the + given :class:`date` object's, and whose time and :attr:`tzinfo` attributes are + equal to the given :class:`time` object's. For any :class:`datetime` object + *d*, ``d == datetime.combine(d.date(), d.timetz())``. If date is a + :class:`datetime` object, its time and :attr:`tzinfo` attributes are ignored. .. classmethod:: datetime.strptime(date_string, format) @@ -795,43 +795,44 @@ (1) datetime2 is a duration of timedelta removed from datetime1, moving forward in time if ``timedelta.days`` > 0, or backward if ``timedelta.days`` < 0. The - result has the same :attr:`tzinfo` member as the input datetime, and datetime2 - - datetime1 == timedelta after. :exc:`OverflowError` is raised if datetime2.year - would be smaller than :const:`MINYEAR` or larger than :const:`MAXYEAR`. Note - that no time zone adjustments are done even if the input is an aware object. + result has the same :attr:`tzinfo` attribute as the input datetime, and + datetime2 - datetime1 == timedelta after. :exc:`OverflowError` is raised if + datetime2.year would be smaller than :const:`MINYEAR` or larger than + :const:`MAXYEAR`. Note that no time zone adjustments are done even if the + input is an aware object. (2) Computes the datetime2 such that datetime2 + timedelta == datetime1. As for - addition, the result has the same :attr:`tzinfo` member as the input datetime, - and no time zone adjustments are done even if the input is aware. This isn't - quite equivalent to datetime1 + (-timedelta), because -timedelta in isolation - can overflow in cases where datetime1 - timedelta does not. + addition, the result has the same :attr:`tzinfo` attribute as the input + datetime, and no time zone adjustments are done even if the input is aware. + This isn't quite equivalent to datetime1 + (-timedelta), because -timedelta + in isolation can overflow in cases where datetime1 - timedelta does not. (3) Subtraction of a :class:`datetime` from a :class:`datetime` is defined only if both operands are naive, or if both are aware. If one is aware and the other is naive, :exc:`TypeError` is raised. - If both are naive, or both are aware and have the same :attr:`tzinfo` member, - the :attr:`tzinfo` members are ignored, and the result is a :class:`timedelta` + If both are naive, or both are aware and have the same :attr:`tzinfo` attribute, + the :attr:`tzinfo` attributes are ignored, and the result is a :class:`timedelta` object *t* such that ``datetime2 + t == datetime1``. No time zone adjustments are done in this case. - If both are aware and have different :attr:`tzinfo` members, ``a-b`` acts as if - *a* and *b* were first converted to naive UTC datetimes first. The result is - ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - - b.utcoffset())`` except that the implementation never overflows. + If both are aware and have different :attr:`tzinfo` attributes, ``a-b`` acts + as if *a* and *b* were first converted to naive UTC datetimes first. The + result is ``(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) + - b.utcoffset())`` except that the implementation never overflows. (4) *datetime1* is considered less than *datetime2* when *datetime1* precedes *datetime2* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. - If both comparands are aware, and have the same :attr:`tzinfo` member, the - common :attr:`tzinfo` member is ignored and the base datetimes are compared. If - both comparands are aware and have different :attr:`tzinfo` members, the - comparands are first adjusted by subtracting their UTC offsets (obtained from - ``self.utcoffset()``). + If both comparands are aware, and have the same :attr:`tzinfo` attribute, the + common :attr:`tzinfo` attribute is ignored and the base datetimes are + compared. If both comparands are aware and have different :attr:`tzinfo` + attributes, the comparands are first adjusted by subtracting their UTC + offsets (obtained from ``self.utcoffset()``). .. note:: @@ -864,22 +865,22 @@ .. method:: datetime.timetz() Return :class:`time` object with same hour, minute, second, microsecond, and - tzinfo members. See also method :meth:`time`. + tzinfo attributes. See also method :meth:`time`. .. method:: datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]]) - Return a datetime with the same members, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive datetime from an aware datetime with no - conversion of date and time members. + Return a datetime with the same attributes, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive datetime from an aware + datetime with no conversion of date and time attributes. .. method:: datetime.astimezone(tz) - Return a :class:`datetime` object with new :attr:`tzinfo` member *tz*, adjusting - the date and time members so the result is the same UTC time as *self*, but in - *tz*'s local time. + Return a :class:`datetime` object with new :attr:`tzinfo` attribute *tz*, + adjusting the date and time attributes so the result is the same UTC time as + *self*, but in *tz*'s local time. *tz* must be an instance of a :class:`tzinfo` subclass, and its :meth:`utcoffset` and :meth:`dst` methods must not return ``None``. *self* must @@ -887,18 +888,18 @@ not return ``None``). If ``self.tzinfo`` is *tz*, ``self.astimezone(tz)`` is equal to *self*: no - adjustment of date or time members is performed. Else the result is local time - in time zone *tz*, representing the same UTC time as *self*: after ``astz = - dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have the same date - and time members as ``dt - dt.utcoffset()``. The discussion of class - :class:`tzinfo` explains the cases at Daylight Saving Time transition boundaries - where this cannot be achieved (an issue only if *tz* models both standard and - daylight time). + adjustment of date or time attributes is performed. Else the result is local + time in time zone *tz*, representing the same UTC time as *self*: after + ``astz = dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will usually have + the same date and time attributes as ``dt - dt.utcoffset()``. The discussion + of class :class:`tzinfo` explains the cases at Daylight Saving Time transition + boundaries where this cannot be achieved (an issue only if *tz* models both + standard and daylight time). If you merely want to attach a time zone object *tz* to a datetime *dt* without - adjustment of date and time members, use ``dt.replace(tzinfo=tz)``. If you + adjustment of date and time attributes, use ``dt.replace(tzinfo=tz)``. If you merely want to remove the time zone object from an aware datetime *dt* without - conversion of date and time members, use ``dt.replace(tzinfo=None)``. + conversion of date and time attributes, use ``dt.replace(tzinfo=None)``. Note that the default :meth:`tzinfo.fromutc` method can be overridden in a :class:`tzinfo` subclass to affect the result returned by :meth:`astimezone`. @@ -1209,14 +1210,14 @@ * comparison of :class:`time` to :class:`time`, where *a* is considered less than *b* when *a* precedes *b* in time. If one comparand is naive and the other is aware, :exc:`TypeError` is raised. If both comparands are aware, and have - the same :attr:`tzinfo` member, the common :attr:`tzinfo` member is ignored and - the base times are compared. If both comparands are aware and have different - :attr:`tzinfo` members, the comparands are first adjusted by subtracting their - UTC offsets (obtained from ``self.utcoffset()``). In order to stop mixed-type - comparisons from falling back to the default comparison by object address, when - a :class:`time` object is compared to an object of a different type, - :exc:`TypeError` is raised unless the comparison is ``==`` or ``!=``. The - latter cases return :const:`False` or :const:`True`, respectively. + the same :attr:`tzinfo` attribute, the common :attr:`tzinfo` attribute is + ignored and the base times are compared. If both comparands are aware and + have different :attr:`tzinfo` attributes, the comparands are first adjusted by + subtracting their UTC offsets (obtained from ``self.utcoffset()``). In order + to stop mixed-type comparisons from falling back to the default comparison by + object address, when a :class:`time` object is compared to an object of a + different type, :exc:`TypeError` is raised unless the comparison is ``==`` or + ``!=``. The latter cases return :const:`False` or :const:`True`, respectively. * hash, use as dict key @@ -1231,10 +1232,10 @@ .. method:: time.replace([hour[, minute[, second[, microsecond[, tzinfo]]]]]) - Return a :class:`time` with the same value, except for those members given new - values by whichever keyword arguments are specified. Note that ``tzinfo=None`` - can be specified to create a naive :class:`time` from an aware :class:`time`, - without conversion of the time members. + Return a :class:`time` with the same value, except for those attributes given + new values by whichever keyword arguments are specified. Note that + ``tzinfo=None`` can be specified to create a naive :class:`time` from an + aware :class:`time`, without conversion of the time attributes. .. method:: time.isoformat() @@ -1317,7 +1318,7 @@ An instance of (a concrete subclass of) :class:`tzinfo` can be passed to the constructors for :class:`datetime` and :class:`time` objects. The latter objects -view their members as being in local time, and the :class:`tzinfo` object +view their attributes as being in local time, and the :class:`tzinfo` object supports methods revealing offset of local time from UTC, the name of the time zone, and DST offset, all relative to a date or time object passed to them. @@ -1362,9 +1363,9 @@ already been added to the UTC offset returned by :meth:`utcoffset`, so there's no need to consult :meth:`dst` unless you're interested in obtaining DST info separately. For example, :meth:`datetime.timetuple` calls its :attr:`tzinfo` - member's :meth:`dst` method to determine how the :attr:`tm_isdst` flag should be - set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for DST changes - when crossing time zones. + attribute's :meth:`dst` method to determine how the :attr:`tm_isdst` flag + should be set, and :meth:`tzinfo.fromutc` calls :meth:`dst` to account for + DST changes when crossing time zones. An instance *tz* of a :class:`tzinfo` subclass that models both standard and daylight times must be consistent in this sense: @@ -1440,10 +1441,10 @@ .. method:: tzinfo.fromutc(self, dt) This is called from the default :class:`datetime.astimezone()` implementation. - When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time members - are to be viewed as expressing a UTC time. The purpose of :meth:`fromutc` is to - adjust the date and time members, returning an equivalent datetime in *self*'s - local time. + When called from that, ``dt.tzinfo`` is *self*, and *dt*'s date and time + attributes are to be viewed as expressing a UTC time. The purpose of + :meth:`fromutc` is to adjust the date and time attributes, returning an + equivalent datetime in *self*'s local time. Most :class:`tzinfo` subclasses should be able to inherit the default :meth:`fromutc` implementation without problems. It's strong enough to handle diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -742,7 +742,7 @@ Normalize the number by stripping the rightmost trailing zeros and converting any result equal to :const:`Decimal('0')` to - :const:`Decimal('0e0')`. Used for producing canonical values for members + :const:`Decimal('0e0')`. Used for producing canonical values for attributes of an equivalence class. For example, ``Decimal('32.100')`` and ``Decimal('0.321000e+2')`` both normalize to the equivalent value ``Decimal('32.1')``. diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1199,12 +1199,11 @@ .. class:: DocTest(examples, globs, name, filename, lineno, docstring) A collection of doctest examples that should be run in a single namespace. The - constructor arguments are used to initialize the member variables of the same - names. + constructor arguments are used to initialize the attributes of the same names. .. versionadded:: 2.4 - :class:`DocTest` defines the following member variables. They are initialized by + :class:`DocTest` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1257,12 +1256,12 @@ .. class:: Example(source, want[, exc_msg][, lineno][, indent][, options]) A single interactive example, consisting of a Python statement and its expected - output. The constructor arguments are used to initialize the member variables - of the same names. + output. The constructor arguments are used to initialize the attributes of the + same names. .. versionadded:: 2.4 - :class:`Example` defines the following member variables. They are initialized by + :class:`Example` defines the following attributes. They are initialized by the constructor, and should not be modified directly. @@ -1770,9 +1769,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example's actual output did not match its expected output. The constructor arguments are - used to initialize the member variables of the same names. - -:exc:`DocTestFailure` defines the following member variables: + used to initialize the attributes of the same names. + +:exc:`DocTestFailure` defines the following attributes: .. attribute:: DocTestFailure.test @@ -1794,9 +1793,9 @@ An exception raised by :class:`DocTestRunner` to signal that a doctest example raised an unexpected exception. The constructor arguments are used - to initialize the member variables of the same names. - -:exc:`UnexpectedException` defines the following member variables: + to initialize the attributes of the same names. + +:exc:`UnexpectedException` defines the following attributes: .. attribute:: UnexpectedException.test diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -58,7 +58,7 @@ time is used. This module ignores the timestamp when decompressing; however, some programs, such as :program:`gunzip`\ , make use of it. The format of the timestamp is the same as that of the return value of - ``time.time()`` and of the ``st_mtime`` member of the object returned + ``time.time()`` and of the ``st_mtime`` attribute of the object returned by ``os.stat()``. Calling a :class:`GzipFile` object's :meth:`close` method does not close diff --git a/Doc/library/htmllib.rst b/Doc/library/htmllib.rst --- a/Doc/library/htmllib.rst +++ b/Doc/library/htmllib.rst @@ -168,7 +168,7 @@ This module defines three dictionaries, ``name2codepoint``, ``codepoint2name``, and ``entitydefs``. ``entitydefs`` is used by the :mod:`htmllib` module to -provide the :attr:`entitydefs` member of the :class:`HTMLParser` class. The +provide the :attr:`entitydefs` attribute of the :class:`HTMLParser` class. The definition provided here contains all the entities defined by XHTML 1.0 that can be handled using simple textual substitution in the Latin-1 character set (ISO-8859-1). diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -407,8 +407,8 @@ :class:`RawIOBase` implementation, but wrap one, like :class:`BufferedWriter` and :class:`BufferedReader` do. - :class:`BufferedIOBase` provides or overrides these members in addition to - those from :class:`IOBase`: + :class:`BufferedIOBase` provides or overrides these methods and attribute in + addition to those from :class:`IOBase`: .. attribute:: raw diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1388,11 +1388,12 @@ .. note:: - The exact meaning and resolution of the :attr:`st_atime`, :attr:`st_mtime`, and - :attr:`st_ctime` members depends on the operating system and the file system. - For example, on Windows systems using the FAT or FAT32 file systems, - :attr:`st_mtime` has 2-second resolution, and :attr:`st_atime` has only 1-day - resolution. See your operating system documentation for details. + The exact meaning and resolution of the :attr:`st_atime`, + :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating + system and the file system. For example, on Windows systems using the FAT + or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and + :attr:`st_atime` has only 1-day resolution. See your operating system + documentation for details. For backward compatibility, the return value of :func:`~os.stat` is also accessible as a tuple of at least 10 integers giving the most important (and portable) diff --git a/Doc/library/pyclbr.rst b/Doc/library/pyclbr.rst --- a/Doc/library/pyclbr.rst +++ b/Doc/library/pyclbr.rst @@ -43,7 +43,7 @@ The :class:`Class` objects used as values in the dictionary returned by :func:`readmodule` and :func:`readmodule_ex` provide the following data -members: +attributes: .. attribute:: Class.module @@ -87,7 +87,7 @@ ---------------- The :class:`Function` objects used as values in the dictionary returned by -:func:`readmodule_ex` provide the following data members: +:func:`readmodule_ex` provide the following attributes: .. attribute:: Function.module diff --git a/Doc/library/repr.rst b/Doc/library/repr.rst --- a/Doc/library/repr.rst +++ b/Doc/library/repr.rst @@ -49,7 +49,7 @@ Repr Objects ------------ -:class:`Repr` instances provide several members which can be used to provide +:class:`Repr` instances provide several attributes which can be used to provide size limits for the representations of different object types, and methods which format specific object types. diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst --- a/Doc/library/shlex.rst +++ b/Doc/library/shlex.rst @@ -28,8 +28,8 @@ Split the string *s* using shell-like syntax. If *comments* is :const:`False` (the default), the parsing of comments in the given string will be disabled - (setting the :attr:`commenters` member of the :class:`shlex` instance to the - empty string). This function operates in POSIX mode by default, but uses + (setting the :attr:`commenters` attribute of the :class:`shlex` instance to + the empty string). This function operates in POSIX mode by default, but uses non-POSIX mode if the *posix* argument is false. .. versionadded:: 2.3 @@ -53,7 +53,7 @@ :meth:`readline` methods, or a string (strings are accepted since Python 2.3). If no argument is given, input will be taken from ``sys.stdin``. The second optional argument is a filename string, which sets the initial value of the - :attr:`infile` member. If the *instream* argument is omitted or equal to + :attr:`infile` attribute. If the *instream* argument is omitted or equal to ``sys.stdin``, this second argument defaults to "stdin". The *posix* argument was introduced in Python 2.3, and defines the operational mode. When *posix* is not true (default), the :class:`shlex` instance will operate in compatibility @@ -221,8 +221,8 @@ .. attribute:: shlex.source - This member is ``None`` by default. If you assign a string to it, that string - will be recognized as a lexical-level inclusion request similar to the + This attribute is ``None`` by default. If you assign a string to it, that + string will be recognized as a lexical-level inclusion request similar to the ``source`` keyword in various shells. That is, the immediately following token will opened as a filename and input taken from that stream until EOF, at which point the :meth:`close` method of that stream will be called and the input @@ -232,7 +232,7 @@ .. attribute:: shlex.debug - If this member is numeric and ``1`` or more, a :class:`shlex` instance will + If this attribute is numeric and ``1`` or more, a :class:`shlex` instance will print verbose progress output on its behavior. If you need to use this, you can read the module source code to learn the details. diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -85,7 +85,7 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass The mix-in class must come first, since it overrides a method defined in -:class:`UDPServer`. Setting the various member variables also changes the +:class:`UDPServer`. Setting the various attributes also change the behavior of the underlying server mechanism. To implement a service, you must derive a class from :class:`BaseRequestHandler` diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2787,7 +2787,7 @@ foo`` does not require a module object named *foo* to exist, rather it requires an (external) *definition* for a module named *foo* somewhere.) -A special member of every module is :attr:`__dict__`. This is the dictionary +A special attribute of every module is :attr:`__dict__`. This is the dictionary containing the module's symbol table. Modifying this dictionary will actually change the module's symbol table, but direct assignment to the :attr:`__dict__` attribute is not possible (you can write ``m.__dict__['a'] = 1``, which defines diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -428,38 +428,39 @@ .. attribute:: dwFlags - A bit field that determines whether certain :class:`STARTUPINFO` members - are used when the process creates a window. :: + A bit field that determines whether certain :class:`STARTUPINFO` + attributes are used when the process creates a window. :: si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW .. attribute:: hStdInput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard input handle for the process. If :data:`STARTF_USESTDHANDLES` - is not specified, the default for standard input is the keyboard buffer. + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard input handle for the process. If + :data:`STARTF_USESTDHANDLES` is not specified, the default for standard + input is the keyboard buffer. .. attribute:: hStdOutput - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard output handle for the process. Otherwise, this member is - ignored and the default for standard output is the console window's + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard output handle for the process. Otherwise, this attribute + is ignored and the default for standard output is the console window's buffer. .. attribute:: hStdError - If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this member is - the standard error handle for the process. Otherwise, this member is + If :attr:`dwFlags` specifies :data:`STARTF_USESTDHANDLES`, this attribute + is the standard error handle for the process. Otherwise, this attribute is ignored and the default for standard error is the console window's buffer. .. attribute:: wShowWindow - If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this member + If :attr:`dwFlags` specifies :data:`STARTF_USESHOWWINDOW`, this attribute can be any of the values that can be specified in the ``nCmdShow`` parameter for the `ShowWindow `__ - function, except for ``SW_SHOWDEFAULT``. Otherwise, this member is + function, except for ``SW_SHOWDEFAULT``. Otherwise, this attribute is ignored. :data:`SW_HIDE` is provided for this attribute. It is used when @@ -493,12 +494,12 @@ .. data:: STARTF_USESTDHANDLES Specifies that the :attr:`STARTUPINFO.hStdInput`, - :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` members + :attr:`STARTUPINFO.hStdOutput`, and :attr:`STARTUPINFO.hStdError` attributes contain additional information. .. data:: STARTF_USESHOWWINDOW - Specifies that the :attr:`STARTUPINFO.wShowWindow` member contains + Specifies that the :attr:`STARTUPINFO.wShowWindow` attribute contains additional information. .. data:: CREATE_NEW_CONSOLE diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -61,7 +61,7 @@ This function operates exactly as :func:`TemporaryFile` does, except that the file is guaranteed to have a visible name in the file system (on Unix, the directory entry is not unlinked). That name can be retrieved - from the :attr:`name` member of the file object. Whether the name can be + from the :attr:`name` attribute of the file object. Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows NT or later). If *delete* is true (the default), the file is diff --git a/Doc/library/urllib2.rst b/Doc/library/urllib2.rst --- a/Doc/library/urllib2.rst +++ b/Doc/library/urllib2.rst @@ -90,7 +90,7 @@ :class:`HTTPSHandler` will also be added. Beginning in Python 2.3, a :class:`BaseHandler` subclass may also change its - :attr:`handler_order` member variable to modify its position in the handlers + :attr:`handler_order` attribute to modify its position in the handlers list. The following exceptions are raised as appropriate: @@ -495,7 +495,7 @@ Remove any parents. -The following members and methods should only be used by classes derived from +The following attributes and methods should only be used by classes derived from :class:`BaseHandler`. .. note:: diff --git a/Doc/library/xdrlib.rst b/Doc/library/xdrlib.rst --- a/Doc/library/xdrlib.rst +++ b/Doc/library/xdrlib.rst @@ -257,7 +257,7 @@ .. exception:: Error - The base exception class. :exc:`Error` has a single public data member + The base exception class. :exc:`Error` has a single public attribute :attr:`msg` containing the description of the error. diff --git a/Doc/library/xmlrpclib.rst b/Doc/library/xmlrpclib.rst --- a/Doc/library/xmlrpclib.rst +++ b/Doc/library/xmlrpclib.rst @@ -148,7 +148,7 @@ :class:`Fault` or :class:`ProtocolError` object indicating an error. Servers that support the XML introspection API support some common methods -grouped under the reserved :attr:`system` member: +grouped under the reserved :attr:`system` attribute: .. method:: ServerProxy.system.listMethods() @@ -341,7 +341,7 @@ ------------- A :class:`Fault` object encapsulates the content of an XML-RPC fault tag. Fault -objects have the following members: +objects have the following attributes: .. attribute:: Fault.faultCode @@ -390,7 +390,7 @@ A :class:`ProtocolError` object describes a protocol error in the underlying transport layer (such as a 404 'not found' error if the server named by the URI -does not exist). It has the following members: +does not exist). It has the following attributes: .. attribute:: ProtocolError.url diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1459,7 +1459,7 @@ On FreeBSD, the :func:`os.stat` function now returns times with nanosecond resolution, and the returned object now has :attr:`st_gen` and - :attr:`st_birthtime`. The :attr:`st_flags` member is also available, if the + :attr:`st_birthtime`. The :attr:`st_flags` attribute is also available, if the platform supports it. (Contributed by Antti Louko and Diego Petten?.) .. (Patch 1180695, 1212117) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 4 22:55:47 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 04 Jul 2011 22:55:47 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312469=3A_partial_r?= =?utf8?q?evert_of_024827a9db64=2C_freebsd6_thread_initialization?= Message-ID: http://hg.python.org/cpython/rev/34061f0d35ba changeset: 71213:34061f0d35ba parent: 71211:f9d30fac3da0 user: Victor Stinner date: Mon Jul 04 22:53:49 2011 +0200 summary: Issue #12469: partial revert of 024827a9db64, freebsd6 thread initialization * Don't create a thread at startup anymore to initialize the pthread library: it changes the behaviour of many functions related to signal handling like sigwait() * Reenable test_sigtimedwait_poll() on FreeBSD 6 files: Lib/test/test_signal.py | 3 --- Python/thread_pthread.h | 5 +---- 2 files changed, 1 insertions(+), 7 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 @@ -670,9 +670,6 @@ @unittest.skipUnless(hasattr(signal, 'sigtimedwait'), 'need signal.sigtimedwait()') - # issue #12303: sigtimedwait() takes 30 seconds on FreeBSD 6 (kernel bug) - @unittest.skipIf(sys.platform =='freebsd6', - "sigtimedwait() with a null timeout doens't work on FreeBSD 6") def test_sigtimedwait_poll(self): # check that polling with sigtimedwait works self.wait_helper(signal.SIGALRM, ''' diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -144,10 +144,7 @@ * Initialization. */ -/* On FreeBSD6, pthread_kill() doesn't work on the main thread before - the creation of the first thread */ -#if defined(_HAVE_BSDI) \ - || (defined(__FreeBSD__) && __FreeBSD_version < 700000) +#if defined(_HAVE_BSDI) static void _noop(void) { -- Repository URL: http://hg.python.org/cpython From jimjjewett at gmail.com Tue Jul 5 00:27:33 2011 From: jimjjewett at gmail.com (Jim Jewett) Date: Mon, 4 Jul 2011 18:27:33 -0400 Subject: [Python-checkins] cpython: Remove mention of medical condition from the test suite. In-Reply-To: References: Message-ID: If you're going to get rid of the pun, you might as well change the whole sentence... On Sun, Jul 3, 2011 at 1:22 PM, georg.brandl wrote: > http://hg.python.org/cpython/rev/76452b892838 > changeset: ? 71146:76452b892838 > parent: ? ? ?71144:ce52310f61a0 > user: ? ? ? ?Georg Brandl > date: ? ? ? ?Sun Jul 03 19:22:42 2011 +0200 > summary: > ?Remove mention of medical condition from the test suite. > > files: > ?Lib/test/test_csv.py | ?8 ++++---- > ?1 files changed, 4 insertions(+), 4 deletions(-) > > > diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py > --- a/Lib/test/test_csv.py > +++ b/Lib/test/test_csv.py > @@ -459,20 +459,20 @@ > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'5', '6']]) > > ? ? def test_quoted_quote(self): > - ? ? ? ?self.readerAssertEqual('1,2,3,"""I see,"" said the blind man","as he picked up his hammer and saw"', > + ? ? ? ?self.readerAssertEqual('1,2,3,"""I see,"" said the happy man","as he picked up his hammer and saw"', > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[['1', '2', '3', > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? '"I see," said the blind man', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? '"I see," said the happy man', > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'as he picked up his hammer and saw']]) > > ? ? def test_quoted_nl(self): > ? ? ? ? input = '''\ > ?1,2,3,"""I see,"" > -said the blind man","as he picked up his > +said the happy man","as he picked up his > ?hammer and saw" > ?9,8,7,6''' > ? ? ? ? self.readerAssertEqual(input, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[['1', '2', '3', > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? '"I see,"\nsaid the blind man', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? '"I see,"\nsaid the happy man', > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'as he picked up his\nhammer and saw'], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ['9','8','7','6']]) > > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > > From python-checkins at python.org Tue Jul 5 01:15:35 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 01:15:35 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312469=3A_test=5Fsi?= =?utf8?q?gnal_checks_wakeup_signals_order=2C_except_on_freebsd6?= Message-ID: http://hg.python.org/cpython/rev/aad86a719fc6 changeset: 71214:aad86a719fc6 user: Victor Stinner date: Tue Jul 05 01:15:08 2011 +0200 summary: Issue #12469: test_signal checks wakeup signals order, except on freebsd6 On FreeBSD 6, when signals are unblocked, FreeBSD 6 delivers signals in the reverse order of their number. files: Lib/test/test_signal.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 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 @@ -240,10 +240,10 @@ def check_signum(signals): data = os.read(read, len(signals)+1) raised = struct.unpack('%uB' % len(data), data) - # We don't care of the signal delivery order (it's not portable or - # reliable) - raised = set(raised) - signals = set(signals) + if sys.platform == 'freebsd6': + # when signals are unblocked, FreeBSD 6 delivers signals in the + # reverse order of their number + signals = tuple(sorted(signals, reverse=False)) if raised != signals: raise Exception("%r != %r" % (raised, signals)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 01:34:35 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 01:34:35 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312469=3A_fix_signa?= =?utf8?q?l_order_check_of_test=5Fsignal?= Message-ID: http://hg.python.org/cpython/rev/f12b8548b4aa changeset: 71215:f12b8548b4aa user: Victor Stinner date: Tue Jul 05 01:32:06 2011 +0200 summary: Issue #12469: fix signal order check of test_signal When signals are unblocked, pending signal ared delivered in the reverse order of their number (also on Linux, not only on FreeBSD 6). Don't sort signals by their number if signals were not blocked (test_signum). files: Lib/test/test_signal.py | 11 ++++++----- 1 files changed, 6 insertions(+), 5 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 @@ -240,10 +240,6 @@ def check_signum(signals): data = os.read(read, len(signals)+1) raised = struct.unpack('%uB' % len(data), data) - if sys.platform == 'freebsd6': - # when signals are unblocked, FreeBSD 6 delivers signals in the - # reverse order of their number - signals = tuple(sorted(signals, reverse=False)) if raised != signals: raise Exception("%r != %r" % (raised, signals)) @@ -323,6 +319,11 @@ @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), 'need signal.pthread_sigmask()') def test_pending(self): + signals = (signal.SIGUSR1, signal.SIGUSR2) + # when signals are unblocked, pending signal ared delivered in the + # reverse order of their number + signals = tuple(sorted(signals, reverse=True)) + self.check_wakeup("""def test(): signum1 = signal.SIGUSR1 signum2 = signal.SIGUSR2 @@ -335,7 +336,7 @@ os.kill(os.getpid(), signum2) # Unblocking the 2 signals calls the C signal handler twice signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2)) - """, signal.SIGUSR1, signal.SIGUSR2) + """, *signals) @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 02:54:05 2011 From: python-checkins at python.org (ned.deily) Date: Tue, 05 Jul 2011 02:54:05 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDk2?= =?utf8?q?=3A__Install_test/capath_directory_to_prevent_test=5Fconnect=5Fc?= =?utf8?q?apath?= Message-ID: http://hg.python.org/cpython/rev/7731c900ddce changeset: 71216:7731c900ddce branch: 3.2 parent: 71210:184192b3687c user: Ned Deily date: Mon Jul 04 17:48:01 2011 -0700 summary: Issue #12496: Install test/capath directory to prevent test_connect_capath testcase failure in test_ssl. files: Makefile.pre.in | 1 + Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -910,6 +910,7 @@ XMLLIBSUBDIRS= xml xml/dom xml/etree xml/parsers xml/sax LIBSUBDIRS= tkinter tkinter/test tkinter/test/test_tkinter \ tkinter/test/test_ttk site-packages test \ + test/capath \ test/cjkencodings test/decimaltestdata test/xmltestdata test/subprocessdata \ test/tracedmodules test/encoded_modules \ concurrent concurrent/futures encodings \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,9 @@ Tests ----- +- Issue #12496: Install test/capath directory to prevent test_connect_capath + testcase failure in test_ssl. + - Issue #12469: Run "wakeup" signal tests in subprocess to run the test in a fresh process with only one thread and to not change signal handling of the parent process. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 02:54:06 2011 From: python-checkins at python.org (ned.deily) Date: Tue, 05 Jul 2011 02:54:06 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2312496=3A__Install_test/capath_directory_to_prevent_?= =?utf8?q?test=5Fconnect=5Fcapath?= Message-ID: http://hg.python.org/cpython/rev/880c3e764ead changeset: 71217:880c3e764ead parent: 71215:f12b8548b4aa parent: 71216:7731c900ddce user: Ned Deily date: Mon Jul 04 17:51:48 2011 -0700 summary: Issue #12496: Install test/capath directory to prevent test_connect_capath testcase failure in test_ssl. files: Makefile.pre.in | 1 + Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -912,6 +912,7 @@ XMLLIBSUBDIRS= xml xml/dom xml/etree xml/parsers xml/sax LIBSUBDIRS= tkinter tkinter/test tkinter/test/test_tkinter \ tkinter/test/test_ttk site-packages test \ + test/capath \ test/cjkencodings test/decimaltestdata test/xmltestdata \ test/subprocessdata \ test/tracedmodules test/encoded_modules \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -981,6 +981,9 @@ Tests ----- +- Issue #12496: Install test/capath directory to prevent test_connect_capath + testcase failure in test_ssl. + - Issue #12469: Run wakeup and pending signal tests in a subprocess to run the test in a fresh process with only one thread and to not change signal handling of the parent process. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 04:11:45 2011 From: python-checkins at python.org (ned.deily) Date: Tue, 05 Jul 2011 04:11:45 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDk3?= =?utf8?q?=3A_Install_test/data_to_prevent_failures_of_the_various_codecma?= =?utf8?q?ps?= Message-ID: http://hg.python.org/cpython/rev/95301c58c5d2 changeset: 71218:95301c58c5d2 branch: 3.2 parent: 71216:7731c900ddce user: Ned Deily date: Mon Jul 04 19:06:20 2011 -0700 summary: Issue #12497: Install test/data to prevent failures of the various codecmaps tests. files: Lib/test/data/README | 2 +- Makefile.pre.in | 2 +- Misc/NEWS | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/data/README b/Lib/test/data/README --- a/Lib/test/data/README +++ b/Lib/test/data/README @@ -1,2 +1,2 @@ This empty directory serves as destination for temporary files -created by some tests. +created by some tests, in particular, the test_codecmaps_* tests. diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -910,7 +910,7 @@ XMLLIBSUBDIRS= xml xml/dom xml/etree xml/parsers xml/sax LIBSUBDIRS= tkinter tkinter/test tkinter/test/test_tkinter \ tkinter/test/test_ttk site-packages test \ - test/capath \ + test/capath test/data \ test/cjkencodings test/decimaltestdata test/xmltestdata test/subprocessdata \ test/tracedmodules test/encoded_modules \ concurrent concurrent/futures encodings \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,7 +38,10 @@ Tests ----- -- Issue #12496: Install test/capath directory to prevent test_connect_capath +- Issue #12497: Install test/data to prevent failures of the various codecmaps + tests. + +- Issue #12496: Install test/capath directory to prevent test_connect_capath testcase failure in test_ssl. - Issue #12469: Run "wakeup" signal tests in subprocess to run the test in a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 04:11:46 2011 From: python-checkins at python.org (ned.deily) Date: Tue, 05 Jul 2011 04:11:46 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2312497=3A_Install_test/data_to_prevent_failures_of_t?= =?utf8?q?he_various_codecmaps?= Message-ID: http://hg.python.org/cpython/rev/842147eb1b26 changeset: 71219:842147eb1b26 parent: 71217:880c3e764ead parent: 71218:95301c58c5d2 user: Ned Deily date: Mon Jul 04 19:11:14 2011 -0700 summary: Issue #12497: Install test/data to prevent failures of the various codecmaps tests. files: Lib/test/data/README | 2 +- Makefile.pre.in | 2 +- Misc/NEWS | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/data/README b/Lib/test/data/README --- a/Lib/test/data/README +++ b/Lib/test/data/README @@ -1,2 +1,2 @@ This empty directory serves as destination for temporary files -created by some tests. +created by some tests, in particular, the test_codecmaps_* tests. diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -912,7 +912,7 @@ XMLLIBSUBDIRS= xml xml/dom xml/etree xml/parsers xml/sax LIBSUBDIRS= tkinter tkinter/test tkinter/test/test_tkinter \ tkinter/test/test_ttk site-packages test \ - test/capath \ + test/capath test/data \ test/cjkencodings test/decimaltestdata test/xmltestdata \ test/subprocessdata \ test/tracedmodules test/encoded_modules \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -981,7 +981,10 @@ Tests ----- -- Issue #12496: Install test/capath directory to prevent test_connect_capath +- Issue #12497: Install test/data to prevent failures of the various codecmaps + tests. + +- Issue #12496: Install test/capath directory to prevent test_connect_capath testcase failure in test_ssl. - Issue #12469: Run wakeup and pending signal tests in a subprocess to run the -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jul 5 05:10:19 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 05 Jul 2011 05:10:19 +0200 Subject: [Python-checkins] Daily reference leaks (880c3e764ead): sum=402 Message-ID: results for 880c3e764ead on branch "default" -------------------------------------------- test_concurrent_futures leaked [108, 0, 0] references, sum=108 test_packaging leaked [100, 100, 100] references, sum=300 test_warnings leaked [-2, -2, -2] references, sum=-6 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogGkT58w', '-x'] From python-checkins at python.org Tue Jul 5 05:23:50 2011 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 05 Jul 2011 05:23:50 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_start_out_this_?= =?utf8?q?branch_always_with_filename_NULL?= Message-ID: http://hg.python.org/cpython/rev/7eb85a23cf3d changeset: 71220:7eb85a23cf3d branch: 3.2 parent: 71218:95301c58c5d2 user: Benjamin Peterson date: Mon Jul 04 22:27:16 2011 -0500 summary: start out this branch always with filename NULL files: Python/_warnings.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -517,7 +517,7 @@ } else { const char *module_str = _PyUnicode_AsString(*module); - Py_XDECREF(*filename); + *filename = NULL; if (module_str == NULL) goto handle_error; if (strcmp(module_str, "__main__") == 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 05:23:51 2011 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 05 Jul 2011 05:23:51 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_start_out_this_?= =?utf8?q?branch_always_with_filename_NULL?= Message-ID: http://hg.python.org/cpython/rev/a8be035f299f changeset: 71221:a8be035f299f branch: 2.7 parent: 71212:b8f5da066782 user: Benjamin Peterson date: Mon Jul 04 22:27:16 2011 -0500 summary: start out this branch always with filename NULL files: Python/_warnings.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -514,7 +514,7 @@ } else { const char *module_str = PyString_AsString(*module); - Py_XDECREF(*filename); + *filename = NULL; if (module_str && strcmp(module_str, "__main__") == 0) { PyObject *argv = PySys_GetObject("argv"); if (argv != NULL && PyList_Size(argv) > 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 05:23:51 2011 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 05 Jul 2011 05:23:51 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/e38bb637328c changeset: 71222:e38bb637328c parent: 71219:842147eb1b26 parent: 71220:7eb85a23cf3d user: Benjamin Peterson date: Mon Jul 04 22:28:00 2011 -0500 summary: merge 3.2 files: Python/_warnings.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -517,7 +517,7 @@ } else { const char *module_str = _PyUnicode_AsString(*module); - Py_XDECREF(*filename); + *filename = NULL; if (module_str == NULL) goto handle_error; if (strcmp(module_str, "__main__") == 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 11:28:34 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 11:28:34 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzk2MTEs?= =?utf8?b?ICM5MDE1OiBGaWxlSU8ucmVhZCgpLCBGaWxlSU8ucmVhZGludG8oKSwgRmlsZUlP?= =?utf8?b?LndyaXRlKCkgYW5k?= Message-ID: http://hg.python.org/cpython/rev/6abbc5f68e20 changeset: 71223:6abbc5f68e20 branch: 2.7 parent: 71221:a8be035f299f user: Victor Stinner date: Tue Jul 05 11:28:19 2011 +0200 summary: Issue #9611, #9015: FileIO.read(), FileIO.readinto(), FileIO.write() and os.write() clamp the length to INT_MAX on Windows. files: Misc/NEWS | 3 +++ Modules/_io/fileio.c | 30 ++++++++++++++++++++++++++---- Modules/posixmodule.c | 13 ++++++++++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #9611, #9015: FileIO.read(), FileIO.readinto(), FileIO.write() and + os.write() clamp the length to INT_MAX on Windows. + - Issue #1195: my_fgets() now always clears errors before calling fgets(). Fix the following case: sys.stdin.read() stopped with CTRL+d (end of file), raw_input() interrupted by CTRL+c. diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -474,7 +474,7 @@ fileio_readinto(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n; + Py_ssize_t n, len; if (self->fd < 0) return err_closed(); @@ -485,9 +485,16 @@ return NULL; if (_PyVerify_fd(self->fd)) { + len = pbuf.len; Py_BEGIN_ALLOW_THREADS errno = 0; - n = read(self->fd, pbuf.buf, pbuf.len); +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (len > INT_MAX) + len = INT_MAX; + n = read(self->fd, pbuf.buf, (int)len); +#else + n = read(self->fd, pbuf.buf, len); +#endif Py_END_ALLOW_THREADS } else n = -1; @@ -620,6 +627,10 @@ return fileio_readall(self); } +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (size > INT_MAX) + size = INT_MAX; +#endif bytes = PyBytes_FromStringAndSize(NULL, size); if (bytes == NULL) return NULL; @@ -628,7 +639,11 @@ if (_PyVerify_fd(self->fd)) { Py_BEGIN_ALLOW_THREADS errno = 0; +#if defined(MS_WIN64) || defined(MS_WINDOWS) + n = read(self->fd, ptr, (int)size); +#else n = read(self->fd, ptr, size); +#endif Py_END_ALLOW_THREADS } else n = -1; @@ -655,7 +670,7 @@ fileio_write(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n; + Py_ssize_t n, len; if (self->fd < 0) return err_closed(); @@ -668,7 +683,14 @@ if (_PyVerify_fd(self->fd)) { Py_BEGIN_ALLOW_THREADS errno = 0; - n = write(self->fd, pbuf.buf, pbuf.len); + len = pbuf.len; +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (len > INT_MAX) + len = INT_MAX; + n = write(self->fd, pbuf.buf, (int)len); +#else + n = write(self->fd, pbuf.buf, len); +#endif Py_END_ALLOW_THREADS } else n = -1; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3903,7 +3903,7 @@ #endif gid_t grouplist[MAX_GROUPS]; - /* On MacOSX getgroups(2) can return more than MAX_GROUPS results + /* On MacOSX getgroups(2) can return more than MAX_GROUPS results * This is a helper variable to store the intermediate result when * that happens. * @@ -6648,7 +6648,7 @@ { Py_buffer pbuf; int fd; - Py_ssize_t size; + Py_ssize_t size, len; if (!PyArg_ParseTuple(args, "is*:write", &fd, &pbuf)) return NULL; @@ -6656,8 +6656,15 @@ PyBuffer_Release(&pbuf); return posix_error(); } + len = pbuf.len; Py_BEGIN_ALLOW_THREADS - size = write(fd, pbuf.buf, (size_t)pbuf.len); +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (len > INT_MAX) + len = INT_MAX; + size = write(fd, pbuf.buf, (int)len); +#else + size = write(fd, pbuf.buf, len); +#endif Py_END_ALLOW_THREADS PyBuffer_Release(&pbuf); if (size < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 11:38:42 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 11:38:42 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzk2MTEs?= =?utf8?q?_=239015=3A_FileIO=2Eread=28=29_clamps_the_length_to_INT=5FMAX_o?= =?utf8?q?n_Windows=2E?= Message-ID: http://hg.python.org/cpython/rev/7acdf9f5eb31 changeset: 71224:7acdf9f5eb31 branch: 3.2 parent: 71220:7eb85a23cf3d user: Victor Stinner date: Tue Jul 05 11:31:49 2011 +0200 summary: Issue #9611, #9015: FileIO.read() clamps the length to INT_MAX on Windows. files: Misc/NEWS | 4 +++- Modules/_io/fileio.c | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #9611, #9015: FileIO.read() clamps the length to INT_MAX on Windows. + - When a generator yields, do not retain the caller's exception state on the generator. @@ -908,7 +910,7 @@ (length bigger than 2^31-1 bytes). - Issue #9015, #9611: FileIO.readinto(), FileIO.write(), os.write() and - stdprinter.write() clamp the length to 2^31-1 on Windows. + stdprinter.write() clamp the length to INT_MAX on Windows. - Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() can now handle dates after 2038. diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -664,6 +664,10 @@ return fileio_readall(self); } +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (size > INT_MAX) + size = INT_MAX; +#endif bytes = PyBytes_FromStringAndSize(NULL, size); if (bytes == NULL) return NULL; @@ -672,7 +676,11 @@ if (_PyVerify_fd(self->fd)) { Py_BEGIN_ALLOW_THREADS errno = 0; +#if defined(MS_WIN64) || defined(MS_WINDOWS) + n = read(self->fd, ptr, (int)size); +#else n = read(self->fd, ptr, size); +#endif Py_END_ALLOW_THREADS } else n = -1; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 11:38:43 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 11:38:43 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiAobWVyZ2UgMy4yKSBJc3N1ZSAjOTYxMSwgIzkwMTU6IEZpbGVJTy5yZWFkKCkg?= =?utf8?q?clamps_the_length_to_INT=5FMAX_on?= Message-ID: http://hg.python.org/cpython/rev/e8646f120330 changeset: 71225:e8646f120330 parent: 71222:e38bb637328c parent: 71224:7acdf9f5eb31 user: Victor Stinner date: Tue Jul 05 11:34:18 2011 +0200 summary: (merge 3.2) Issue #9611, #9015: FileIO.read() clamps the length to INT_MAX on Windows. files: Misc/NEWS | 4 +++- Modules/_io/fileio.c | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #9611, #9015: FileIO.read() clamps the length to INT_MAX on Windows. + - Issue #9642: Uniformize the tests on the availability of the mbcs codec, add a new HAVE_MBCS define. @@ -1327,7 +1329,7 @@ (length bigger than 2^31-1 bytes). - Issue #9015, #9611: FileIO.readinto(), FileIO.write(), os.write() and - stdprinter.write() clamp the length to 2^31-1 on Windows. + stdprinter.write() clamp the length to INT_MAX on Windows. - Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() can now handle dates after 2038. diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -687,6 +687,10 @@ return fileio_readall(self); } +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (size > INT_MAX) + size = INT_MAX; +#endif bytes = PyBytes_FromStringAndSize(NULL, size); if (bytes == NULL) return NULL; @@ -695,7 +699,11 @@ if (_PyVerify_fd(self->fd)) { Py_BEGIN_ALLOW_THREADS errno = 0; +#if defined(MS_WIN64) || defined(MS_WINDOWS) + n = read(self->fd, ptr, (int)size); +#else n = read(self->fd, ptr, size); +#endif Py_END_ALLOW_THREADS } else n = -1; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 13:37:45 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 13:37:45 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogdGVzdF9hcnJheTog?= =?utf8?q?make_quiet_the_DeprecationWarning?= Message-ID: http://hg.python.org/cpython/rev/7bfedb159e82 changeset: 71226:7bfedb159e82 branch: 2.7 parent: 71223:6abbc5f68e20 user: Victor Stinner date: Tue Jul 05 13:14:17 2011 +0200 summary: test_array: make quiet the DeprecationWarning files: Lib/test/test_array.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -4,6 +4,7 @@ """ import unittest +import warnings from test import test_support from weakref import proxy import array, cStringIO @@ -783,7 +784,9 @@ def test_subclass_with_kwargs(self): # SF bug #1486663 -- this used to erroneously raise a TypeError - ArraySubclassWithKwargs('b', newarg=1) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", '', DeprecationWarning) + ArraySubclassWithKwargs('b', newarg=1) class StringTest(BaseTest): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 13:37:46 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 13:37:46 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogdGVzdF9pbzogbWFr?= =?utf8?q?e_quiet_the_DeprecationWarning=28=27classic_int_division=27=29?= Message-ID: http://hg.python.org/cpython/rev/9864e5d16407 changeset: 71227:9864e5d16407 branch: 2.7 user: Victor Stinner date: Tue Jul 05 13:29:26 2011 +0200 summary: test_io: make quiet the DeprecationWarning('classic int division') files: Lib/test/test_io.py | 2 +- 1 files changed, 1 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 @@ -2612,7 +2612,7 @@ def on_alarm(*args): # Will be called reentrantly from the same thread wio.write(data) - 1/0 + 1//0 signal.signal(signal.SIGALRM, on_alarm) r, w = os.pipe() wio = self.io.open(w, **fdopen_kwargs) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 14:08:17 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 14:08:17 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDkz?= =?utf8?q?=3A_subprocess=3A_communicate=28=29_handles_EINTR?= Message-ID: http://hg.python.org/cpython/rev/dcfacc2d93b4 changeset: 71228:dcfacc2d93b4 branch: 3.2 parent: 71224:7acdf9f5eb31 user: Victor Stinner date: Tue Jul 05 14:00:56 2011 +0200 summary: Issue #12493: subprocess: communicate() handles EINTR subprocess.Popen.communicate() now also handles EINTR errors if the process has only one pipe. files: Lib/subprocess.py | 6 +++--- Lib/test/test_subprocess.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -450,7 +450,7 @@ while True: try: return func(*args) - except OSError as e: + except (OSError, IOError) as e: if e.errno == errno.EINTR: continue raise @@ -804,10 +804,10 @@ raise self.stdin.close() elif self.stdout: - stdout = self.stdout.read() + stdout = _eintr_retry_call(self.stdout.read) self.stdout.close() elif self.stderr: - stderr = self.stderr.read() + stderr = _eintr_retry_call(self.stderr.read) self.stderr.close() self.wait() return (stdout, stderr) 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 @@ -675,6 +675,22 @@ time.sleep(2) p.communicate(b"x" * 2**20) + def test_communicate_eintr(self): + # Issue #12493: communicate() should handle EINTR + def handler(signum, frame): + pass + old_handler = signal.signal(signal.SIGALRM, handler) + self.addCleanup(signal.signal, signal.SIGALRM, old_handler) + + # the process is running for 2 seconds + args = [sys.executable, "-c", 'import time; time.sleep(2)'] + for stream in ('stdout', 'stderr'): + kw = {stream: subprocess.PIPE} + with subprocess.Popen(args, **kw) as process: + signal.alarm(1) + # communicate() will be interrupted by SIGALRM + process.communicate() + # context manager class _SuppressCoreFiles(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,9 @@ Library ------- +- Issue #12493: subprocess: Popen.communicate() now also handles EINTR errors + if the process has only one pipe. + - Issue #12467: warnings: fix a race condition if a warning is emitted at shutdown, if globals()['__file__'] is None. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 14:08:18 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 14:08:18 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28merge_3=2E2=29_Issue_=2312493=3A_subprocess=3A_communicat?= =?utf8?q?e=28=29_handles_EINTR?= Message-ID: http://hg.python.org/cpython/rev/42e23db3ddfc changeset: 71229:42e23db3ddfc parent: 71225:e8646f120330 parent: 71228:dcfacc2d93b4 user: Victor Stinner date: Tue Jul 05 14:04:39 2011 +0200 summary: (merge 3.2) Issue #12493: subprocess: communicate() handles EINTR subprocess.Popen.communicate() now also handles EINTR errors if the process has only one pipe. files: Lib/subprocess.py | 6 +++--- Lib/test/test_subprocess.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -446,7 +446,7 @@ while True: try: return func(*args) - except OSError as e: + except (OSError, IOError) as e: if e.errno == errno.EINTR: continue raise @@ -820,10 +820,10 @@ raise self.stdin.close() elif self.stdout: - stdout = self.stdout.read() + stdout = _eintr_retry_call(self.stdout.read) self.stdout.close() elif self.stderr: - stderr = self.stderr.read() + stderr = _eintr_retry_call(self.stderr.read) self.stderr.close() self.wait() else: 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 @@ -767,6 +767,22 @@ time.sleep(2) p.communicate(b"x" * 2**20) + def test_communicate_eintr(self): + # Issue #12493: communicate() should handle EINTR + def handler(signum, frame): + pass + old_handler = signal.signal(signal.SIGALRM, handler) + self.addCleanup(signal.signal, signal.SIGALRM, old_handler) + + # the process is running for 2 seconds + args = [sys.executable, "-c", 'import time; time.sleep(2)'] + for stream in ('stdout', 'stderr'): + kw = {stream: subprocess.PIPE} + with subprocess.Popen(args, **kw) as process: + signal.alarm(1) + # communicate() will be interrupted by SIGALRM + process.communicate() + # context manager class _SuppressCoreFiles(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -219,6 +219,9 @@ Library ------- +- Issue #12493: subprocess: Popen.communicate() now also handles EINTR errors + if the process has only one pipe. + - Issue #12467: warnings: fix a race condition if a warning is emitted at shutdown, if globals()['__file__'] is None. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 14:08:19 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 14:08:19 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyNDkz?= =?utf8?q?=3A_subprocess=3A_communicate=28=29_handles_EINTR?= Message-ID: http://hg.python.org/cpython/rev/6a28ccde2f1b changeset: 71230:6a28ccde2f1b branch: 2.7 parent: 71227:9864e5d16407 user: Victor Stinner date: Tue Jul 05 14:08:01 2011 +0200 summary: Issue #12493: subprocess: communicate() handles EINTR subprocess.Popen.communicate() now also handles EINTR errors if the process has only one pipe. files: Lib/subprocess.py | 6 +++--- Lib/test/test_subprocess.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -476,7 +476,7 @@ while True: try: return func(*args) - except OSError, e: + except (OSError, IOError) as e: if e.errno == errno.EINTR: continue raise @@ -743,10 +743,10 @@ raise self.stdin.close() elif self.stdout: - stdout = self.stdout.read() + stdout = _eintr_retry_call(self.stdout.read) self.stdout.close() elif self.stderr: - stderr = self.stderr.read() + stderr = _eintr_retry_call(self.stderr.read) self.stderr.close() self.wait() return (stdout, stderr) 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 @@ -664,6 +664,22 @@ except (ImportError, ValueError, resource.error): pass + def test_communicate_eintr(self): + # Issue #12493: communicate() should handle EINTR + def handler(signum, frame): + pass + old_handler = signal.signal(signal.SIGALRM, handler) + self.addCleanup(signal.signal, signal.SIGALRM, old_handler) + + # the process is running for 2 seconds + args = [sys.executable, "-c", 'import time; time.sleep(2)'] + for stream in ('stdout', 'stderr'): + kw = {stream: subprocess.PIPE} + with subprocess.Popen(args, **kw) as process: + signal.alarm(1) + # communicate() will be interrupted by SIGALRM + process.communicate() + @unittest.skipIf(mswindows, "POSIX specific tests") class POSIXProcessTestCase(BaseTestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,9 @@ Library ------- +- Issue #12493: subprocess: Popen.communicate() now also handles EINTR errors + if the process has only one pipe. + - Issue #12467: warnings: fix a race condition if a warning is emitted at shutdown, if globals()['__file__'] is None. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 14:31:55 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 14:31:55 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiAobWVyZ2UgMy4yKSBJc3N1ZSAjMTI0NTE6IHB5ZG9jOiBodG1sX2dldGZpbGUo?= =?utf8?q?=29_now_uses_tokenize=2Eopen=28=29_to?= Message-ID: http://hg.python.org/cpython/rev/2fbfb7ea362f changeset: 71232:2fbfb7ea362f parent: 71229:42e23db3ddfc parent: 71231:8b62f5d722f4 user: Victor Stinner date: Tue Jul 05 14:31:28 2011 +0200 summary: (merge 3.2) Issue #12451: pydoc: html_getfile() now uses tokenize.open() to support Python scripts using a encoding different than UTF-8 (read the coding cookie of the script). files: Lib/pydoc.py | 2 +- Misc/NEWS | 4 ++++ 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2311,7 +2311,7 @@ def html_getfile(path): """Get and display a source file listing safely.""" path = path.replace('%20', ' ') - with open(path, 'r') as fp: + with tokenize.open(path) as fp: lines = html.escape(fp.read()) body = '
%s
' % lines heading = html.heading( diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -219,6 +219,10 @@ Library ------- +- Issue #12451: pydoc: html_getfile() now uses tokenize.open() to support + Python scripts using a encoding different than UTF-8 (read the coding cookie + of the script). + - Issue #12493: subprocess: Popen.communicate() now also handles EINTR errors if the process has only one pipe. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 14:31:55 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 14:31:55 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDUx?= =?utf8?q?=3A_pydoc=3A_html=5Fgetfile=28=29_now_uses_tokenize=2Eopen=28=29?= =?utf8?q?_to_support_Python?= Message-ID: http://hg.python.org/cpython/rev/8b62f5d722f4 changeset: 71231:8b62f5d722f4 branch: 3.2 parent: 71228:dcfacc2d93b4 user: Victor Stinner date: Tue Jul 05 14:30:41 2011 +0200 summary: Issue #12451: pydoc: html_getfile() now uses tokenize.open() to support Python scripts using a encoding different than UTF-8 (read the coding cookie of the script). files: Lib/pydoc.py | 2 +- Misc/NEWS | 4 ++++ 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2580,7 +2580,7 @@ def html_getfile(path): """Get and display a source file listing safely.""" path = path.replace('%20', ' ') - with open(path, 'r') as fp: + with tokenize.open(path) as fp: lines = html.escape(fp.read()) body = '
%s
' % lines heading = html.heading( diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,10 @@ - Issue #12467: warnings: fix a race condition if a warning is emitted at shutdown, if globals()['__file__'] is None. +- Issue #12451: pydoc: html_getfile() now uses tokenize.open() to support + Python scripts using a encoding different than UTF-8 (read the coding cookie + of the script). + - Issue #12451: pydoc: importfile() now opens the Python script in binary mode, instead of text mode using the locale encoding, to avoid encoding issues. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 14:51:04 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 14:51:04 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDkz?= =?utf8?q?=3A_skip_test=5Fcommunicate=5Feintr=28=29_if_signal=2ESIGALRM_is?= =?utf8?q?_missing?= Message-ID: http://hg.python.org/cpython/rev/807921ba241d changeset: 71233:807921ba241d branch: 3.2 parent: 71231:8b62f5d722f4 user: Victor Stinner date: Tue Jul 05 14:49:46 2011 +0200 summary: Issue #12493: skip test_communicate_eintr() if signal.SIGALRM is missing files: Lib/test/test_subprocess.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) 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 @@ -675,6 +675,8 @@ time.sleep(2) p.communicate(b"x" * 2**20) + @unittest.skipUnless(hasattr(signal, 'SIGALRM'), + "Requires signal.SIGALRM") def test_communicate_eintr(self): # Issue #12493: communicate() should handle EINTR def handler(signum, frame): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 14:51:05 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 14:51:05 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=28merge_3=2E2=29_Issue_=2312493=3A_skip_test=5Fcommunicate?= =?utf8?q?=5Feintr=28=29_if_signal=2ESIGALRM_is?= Message-ID: http://hg.python.org/cpython/rev/4928cf093a11 changeset: 71234:4928cf093a11 parent: 71232:2fbfb7ea362f parent: 71233:807921ba241d user: Victor Stinner date: Tue Jul 05 14:50:08 2011 +0200 summary: (merge 3.2) Issue #12493: skip test_communicate_eintr() if signal.SIGALRM is missing files: Lib/test/test_subprocess.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) 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 @@ -767,6 +767,8 @@ time.sleep(2) p.communicate(b"x" * 2**20) + @unittest.skipUnless(hasattr(signal, 'SIGALRM'), + "Requires signal.SIGALRM") def test_communicate_eintr(self): # Issue #12493: communicate() should handle EINTR def handler(signum, frame): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 5 14:51:05 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 14:51:05 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyNDkz?= =?utf8?q?=3A_skip_test=5Fcommunicate=5Feintr=28=29_if_signal=2ESIGALRM_is?= =?utf8?q?_missing?= Message-ID: http://hg.python.org/cpython/rev/8a4c9c154b5d changeset: 71235:8a4c9c154b5d branch: 2.7 parent: 71230:6a28ccde2f1b user: Victor Stinner date: Tue Jul 05 14:50:35 2011 +0200 summary: Issue #12493: skip test_communicate_eintr() if signal.SIGALRM is missing files: Lib/test/test_subprocess.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) 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 @@ -664,6 +664,8 @@ except (ImportError, ValueError, resource.error): pass + @unittest.skipUnless(hasattr(signal, 'SIGALRM'), + "Requires signal.SIGALRM") def test_communicate_eintr(self): # Issue #12493: communicate() should handle EINTR def handler(signum, frame): -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Tue Jul 5 15:57:24 2011 From: ncoghlan at gmail.com (Nick Coghlan) Date: Tue, 5 Jul 2011 23:57:24 +1000 Subject: [Python-checkins] [Python-Dev] cpython: Remove mention of medical condition from the test suite. In-Reply-To: <87fwmldyyz.fsf@uwakimon.sk.tsukuba.ac.jp> References: <87fwmldyyz.fsf@uwakimon.sk.tsukuba.ac.jp> Message-ID: On Tue, Jul 5, 2011 at 4:27 PM, Stephen J. Turnbull wrote: > That points to why such changes are justified despite an author's > right to have her mode of expression respected -- the Python project > aims at professionalism, and offensive language detracts from it. Given that the contents of many test strings are quite arbitrary, I personally consider a bit of inoffensive humour or cultural references to be a fine thing to include rather than yet another instance of "foobar" (which itself has humorous *and* offensive origins). Heck, stripping just the Monty Python quotes from the test suite would probably take a while :) Avoiding offensive text has nothing to do with a desire to appear "professional" (at least for me) - it's about demonstrating common courtesy to the potentially wide variety of people that will read the Python source code in the future. (In the specific case, I thought quoting the venerable pun was fine, but I also don't have any real problem with modifying it) Cheers, Nick. P.S. 'twas a sad day when copyright concerns cost us the old test audio file :( -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From python-checkins at python.org Tue Jul 5 22:00:33 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 05 Jul 2011 22:00:33 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312459=3A_time=2Esl?= =?utf8?q?eep=28=29_now_raises_a_ValueError_if_the_sleep_length_is?= Message-ID: http://hg.python.org/cpython/rev/0e5485634817 changeset: 71236:0e5485634817 parent: 71234:4928cf093a11 user: Victor Stinner date: Tue Jul 05 22:00:25 2011 +0200 summary: Issue #12459: time.sleep() now raises a ValueError if the sleep length is negative, instead of an infinite sleep on Windows or raising an IOError on Linux for example, to have the same behaviour on all platforms. files: Lib/test/test_time.py | 2 ++ Misc/NEWS | 4 ++++ Modules/timemodule.c | 5 +++++ 3 files changed, 11 insertions(+), 0 deletions(-) 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 @@ -27,6 +27,8 @@ int(self.t)) def test_sleep(self): + self.assertRaises(ValueError, time.sleep, -2) + self.assertRaises(ValueError, time.sleep, -1) time.sleep(1.2) def test_strftime(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -219,6 +219,10 @@ Library ------- +- Issue #12459: time.sleep() now raises a ValueError if the sleep length is + negative, instead of an infinite sleep on Windows or raising an IOError on + Linux for example, to have the same behaviour on all platforms. + - Issue #12451: pydoc: html_getfile() now uses tokenize.open() to support Python scripts using a encoding different than UTF-8 (read the coding cookie of the script). diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -141,6 +141,11 @@ double secs; if (!PyArg_ParseTuple(args, "d:sleep", &secs)) return NULL; + if (secs < 0) { + PyErr_SetString(PyExc_ValueError, + "sleep length must be non-negative"); + return NULL; + } if (floatsleep(secs) != 0) return NULL; Py_INCREF(Py_None); -- Repository URL: http://hg.python.org/cpython From eric at trueblade.com Tue Jul 5 13:59:10 2011 From: eric at trueblade.com (Eric Smith) Date: Tue, 05 Jul 2011 07:59:10 -0400 Subject: [Python-checkins] cpython: Issue #12452: Plist and Dict are now deprecated In-Reply-To: References: Message-ID: <4E12FC8E.2070609@trueblade.com> On 7/4/2011 8:28 AM, victor.stinner wrote: > http://hg.python.org/cpython/rev/4f14050a963f > changeset: 71194:4f14050a963f > user: Victor Stinner > date: Mon Jul 04 14:28:45 2011 +0200 > summary: > Issue #12452: Plist and Dict are now deprecated > > Replace PendingDeprecationWarning warnings by DeprecationWarning. Shouldn't this be in MISC/News, be accompanied by documentation changes, and have tests? From g.brandl at gmx.net Tue Jul 5 22:17:10 2011 From: g.brandl at gmx.net (Georg Brandl) Date: Tue, 05 Jul 2011 22:17:10 +0200 Subject: [Python-checkins] [Python-Dev] cpython: Remove mention of medical condition from the test suite. In-Reply-To: References: <87fwmldyyz.fsf@uwakimon.sk.tsukuba.ac.jp> Message-ID: Am 05.07.2011 15:57, schrieb Nick Coghlan: > On Tue, Jul 5, 2011 at 4:27 PM, Stephen J. Turnbull wrote: >> That points to why such changes are justified despite an author's >> right to have her mode of expression respected -- the Python project >> aims at professionalism, and offensive language detracts from it. > > Given that the contents of many test strings are quite arbitrary, I > personally consider a bit of inoffensive humour or cultural references > to be a fine thing to include rather than yet another instance of > "foobar" (which itself has humorous *and* offensive origins). Heck, > stripping just the Monty Python quotes from the test suite would > probably take a while :) Well, the diversity list discussed this specific problem, and it was stated that even double-use of such terms documented in dictionaries is offensive to some. For this test string, a) I'm not a native speaker and therefore don't know of any special treatment this pun deserves and b) the content is really quite arbitrary, meaning that the test works just as well with this content. Georg From python-checkins at python.org Tue Jul 5 23:16:52 2011 From: python-checkins at python.org (ned.deily) Date: Tue, 05 Jul 2011 23:16:52 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzg3MTY6?= =?utf8?q?_Add_temporary_code_for_2=2E7_to_help_diagnose_buildbot_failure?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/18ce15f841cf changeset: 71237:18ce15f841cf branch: 2.7 parent: 71235:8a4c9c154b5d user: Ned Deily date: Tue Jul 05 14:16:03 2011 -0700 summary: Issue #8716: Add temporary code for 2.7 to help diagnose buildbot failure. files: Lib/lib-tk/test/runtktests.py | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/Lib/lib-tk/test/runtktests.py b/Lib/lib-tk/test/runtktests.py --- a/Lib/lib-tk/test/runtktests.py +++ b/Lib/lib-tk/test/runtktests.py @@ -25,6 +25,20 @@ return if sys.platform == 'darwin': + + # ** temporary test code for issue8716 ** + try: + import MacOS + wma = MacOS.WMAvailable() + print >> test.test_support.get_original_stdout(), \ + '\tcheck_tk_availability -- WMAvailable returned %r' % wma + except ImportError: + print >> test.test_support.get_original_stdout(), \ + '\tcheck_tk_availability -- could not import MacOS' + if not wma: + raise unittest.SkipTest("Window manager is not available") + # ** end of temporary test code for issue8716 ** + # The Aqua Tk implementations on OS X can abort the process if # being called in an environment where a window server connection # cannot be made, for instance when invoked by a buildbot or ssh -- Repository URL: http://hg.python.org/cpython From guido at python.org Wed Jul 6 00:50:09 2011 From: guido at python.org (Guido van Rossum) Date: Tue, 5 Jul 2011 15:50:09 -0700 Subject: [Python-checkins] cpython: Remove mention of medical condition from the test suite. In-Reply-To: References: Message-ID: It's not a bug and shouldn't be "fixed". We leave lots of minor infractions in the code because the code churn of fixing them all would be too distracting. On Jul 3, 2011 10:22 AM, "georg.brandl" wrote: > http://hg.python.org/cpython/rev/76452b892838 > changeset: 71146:76452b892838 > parent: 71144:ce52310f61a0 > user: Georg Brandl > date: Sun Jul 03 19:22:42 2011 +0200 > summary: > Remove mention of medical condition from the test suite. > > files: > Lib/test/test_csv.py | 8 ++++---- > 1 files changed, 4 insertions(+), 4 deletions(-) > > > diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py > --- a/Lib/test/test_csv.py > +++ b/Lib/test/test_csv.py > @@ -459,20 +459,20 @@ > '5', '6']]) > > def test_quoted_quote(self): > - self.readerAssertEqual('1,2,3,"""I see,"" said the blind man","as he picked up his hammer and saw"', > + self.readerAssertEqual('1,2,3,"""I see,"" said the happy man","as he picked up his hammer and saw"', > [['1', '2', '3', > - '"I see," said the blind man', > + '"I see," said the happy man', > 'as he picked up his hammer and saw']]) > > def test_quoted_nl(self): > input = '''\ > 1,2,3,"""I see,"" > -said the blind man","as he picked up his > +said the happy man","as he picked up his > hammer and saw" > 9,8,7,6''' > self.readerAssertEqual(input, > [['1', '2', '3', > - '"I see,"\nsaid the blind man', > + '"I see,"\nsaid the happy man', > 'as he picked up his\nhammer and saw'], > ['9','8','7','6']]) > > > -- > Repository URL: http://hg.python.org/cpython -------------- next part -------------- An HTML attachment was scrubbed... URL: From python-checkins at python.org Wed Jul 6 02:16:53 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 06 Jul 2011 02:16:53 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_=2311512=2E_Add_an_init?= =?utf8?q?ial_test_suite_for_the_cgitb=2C_providing_75=25_coverage=2E?= Message-ID: http://hg.python.org/cpython/rev/7e0102ec95d4 changeset: 71238:7e0102ec95d4 parent: 71236:0e5485634817 user: Brian Curtin date: Tue Jul 05 19:14:16 2011 -0500 summary: Fix #11512. Add an initial test suite for the cgitb, providing 75% coverage. Patch by Robbie Clemons (robquad), produced at the PyCon 2011 sprints. files: Lib/test/test_cgitb.py | 55 ++++++++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 2 + 3 files changed, 58 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_cgitb.py b/Lib/test/test_cgitb.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_cgitb.py @@ -0,0 +1,55 @@ +from test.support import run_unittest +import unittest +import sys +import subprocess +import cgitb + +class TestCgitb(unittest.TestCase): + + def test_fonts(self): + text = "Hello Robbie!" + self.assertEqual(cgitb.small(text), "{}".format(text)) + self.assertEqual(cgitb.strong(text), "{}".format(text)) + self.assertEqual(cgitb.grey(text), + '{}'.format(text)) + + def test_blanks(self): + self.assertEqual(cgitb.small(""), "") + self.assertEqual(cgitb.strong(""), "") + self.assertEqual(cgitb.grey(""), "") + + def test_html(self): + try: + raise ValueError("Hello World") + except ValueError as err: + # If the html was templated we could do a bit more here. + # At least check that we get details on what we just raised. + html = cgitb.html(sys.exc_info()) + self.assertIn("ValueError", html) + self.assertIn(str(err), html) + + def test_text(self): + try: + raise ValueError("Hello World") + except ValueError as err: + text = cgitb.text(sys.exc_info()) + self.assertIn("ValueError", text) + self.assertIn("Hello World", text) + + def test_hook(self): + proc = subprocess.Popen([sys.executable, '-c', + ('import cgitb;' + 'cgitb.enable();' + 'raise ValueError("Hello World")')], + stdout=subprocess.PIPE) + out = proc.stdout.read().decode(sys.getfilesystemencoding()) + self.addCleanup(proc.stdout.close) + self.assertIn("ValueError", out) + self.assertIn("Hello World", out) + + +def test_main(): + run_unittest(TestCgitb) + +if __name__ == "__main__": + test_main() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -175,6 +175,7 @@ Mike Clarkson Andrew Clegg Brad Clements +Robbie Clemons Steve Clift Nick Coghlan Josh Cogliati diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -994,6 +994,8 @@ Tests ----- +- Issue #11512: Add a test suite for the cgitb module. Patch by Robbie Clemons. + - Issue #12497: Install test/data to prevent failures of the various codecmaps tests. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 6 02:16:53 2011 From: python-checkins at python.org (brian.curtin) Date: Wed, 06 Jul 2011 02:16:53 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Normalize_whitespace_for_?= =?utf8?q?=2311512_fix=2E?= Message-ID: http://hg.python.org/cpython/rev/f362f0053eab changeset: 71239:f362f0053eab user: Brian Curtin date: Tue Jul 05 19:16:37 2011 -0500 summary: Normalize whitespace for #11512 fix. files: Lib/test/test_cgitb.py | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_cgitb.py b/Lib/test/test_cgitb.py --- a/Lib/test/test_cgitb.py +++ b/Lib/test/test_cgitb.py @@ -5,19 +5,19 @@ import cgitb class TestCgitb(unittest.TestCase): - + def test_fonts(self): text = "Hello Robbie!" self.assertEqual(cgitb.small(text), "{}".format(text)) self.assertEqual(cgitb.strong(text), "{}".format(text)) self.assertEqual(cgitb.grey(text), '{}'.format(text)) - + def test_blanks(self): self.assertEqual(cgitb.small(""), "") self.assertEqual(cgitb.strong(""), "") self.assertEqual(cgitb.grey(""), "") - + def test_html(self): try: raise ValueError("Hello World") @@ -35,11 +35,11 @@ text = cgitb.text(sys.exc_info()) self.assertIn("ValueError", text) self.assertIn("Hello World", text) - + def test_hook(self): proc = subprocess.Popen([sys.executable, '-c', - ('import cgitb;' - 'cgitb.enable();' + ('import cgitb;' + 'cgitb.enable();' 'raise ValueError("Hello World")')], stdout=subprocess.PIPE) out = proc.stdout.read().decode(sys.getfilesystemencoding()) @@ -50,6 +50,6 @@ def test_main(): run_unittest(TestCgitb) - + if __name__ == "__main__": test_main() -- Repository URL: http://hg.python.org/cpython From guido at python.org Wed Jul 6 02:35:44 2011 From: guido at python.org (Guido van Rossum) Date: Tue, 5 Jul 2011 17:35:44 -0700 Subject: [Python-checkins] cpython: Remove mention of medical condition from the test suite. In-Reply-To: References: Message-ID: To clarify, now that I have access to an actual keyboard instead of just a cellphone: I think it should be rolled back, since the proper process for controversial changes was not followed. Our process (part of our culture, if you will) for anything controversial is to discuss the change first, then, if deemed necessary, fix the code. And from the size of this thread it clearly is controversial. Georg, can you please revert this change? Note that another part of our process/culture is that we try not to engage in battling commits, i.e. generally we don't unilaterally roll back a change just to make the point that it is incorrect; we ask the original committer to roll it back. As to the controversy itself, if you want to make blind people fell more at home in the Python community surely there are more useful things to do than to remove puns involving blindness; e.g. improve accessibility of python.org or some part of it. Or maybe find some blind programmers and ask them what would help them. --Guido On Tue, Jul 5, 2011 at 3:50 PM, Guido van Rossum wrote: > It's not a bug and shouldn't be "fixed". We leave lots of minor infractions > in the code because the code churn of fixing them all would be too > distracting. > > On Jul 3, 2011 10:22 AM, "georg.brandl" wrote: >> http://hg.python.org/cpython/rev/76452b892838 >> changeset: 71146:76452b892838 >> parent: 71144:ce52310f61a0 >> user: Georg Brandl >> date: Sun Jul 03 19:22:42 2011 +0200 >> summary: >> Remove mention of medical condition from the test suite. >> >> files: >> Lib/test/test_csv.py | 8 ++++---- >> 1 files changed, 4 insertions(+), 4 deletions(-) >> >> >> diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py >> --- a/Lib/test/test_csv.py >> +++ b/Lib/test/test_csv.py >> @@ -459,20 +459,20 @@ >> '5', '6']]) >> >> def test_quoted_quote(self): >> - self.readerAssertEqual('1,2,3,"""I see,"" said the blind man","as he >> picked up his hammer and saw"', >> + self.readerAssertEqual('1,2,3,"""I see,"" said the happy man","as he >> picked up his hammer and saw"', >> [['1', '2', '3', >> - '"I see," said the blind man', >> + '"I see," said the happy man', >> 'as he picked up his hammer and saw']]) >> >> def test_quoted_nl(self): >> input = '''\ >> 1,2,3,"""I see,"" >> -said the blind man","as he picked up his >> +said the happy man","as he picked up his >> hammer and saw" >> 9,8,7,6''' >> self.readerAssertEqual(input, >> [['1', '2', '3', >> - '"I see,"\nsaid the blind man', >> + '"I see,"\nsaid the happy man', >> 'as he picked up his\nhammer and saw'], >> ['9','8','7','6']]) >> >> >> -- >> Repository URL: http://hg.python.org/cpython > -- --Guido van Rossum (python.org/~guido) From python-checkins at python.org Wed Jul 6 04:12:07 2011 From: python-checkins at python.org (ned.deily) Date: Wed, 06 Jul 2011 04:12:07 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzg3MTY6?= =?utf8?q?_Back_out_temporary_changeset_18ce15f841cf?= Message-ID: http://hg.python.org/cpython/rev/b5accd8adc3e changeset: 71240:b5accd8adc3e branch: 2.7 parent: 71237:18ce15f841cf user: Ned Deily date: Tue Jul 05 15:09:32 2011 -0700 summary: Issue #8716: Back out temporary changeset 18ce15f841cf files: Lib/lib-tk/test/runtktests.py | 14 -------------- 1 files changed, 0 insertions(+), 14 deletions(-) diff --git a/Lib/lib-tk/test/runtktests.py b/Lib/lib-tk/test/runtktests.py --- a/Lib/lib-tk/test/runtktests.py +++ b/Lib/lib-tk/test/runtktests.py @@ -25,20 +25,6 @@ return if sys.platform == 'darwin': - - # ** temporary test code for issue8716 ** - try: - import MacOS - wma = MacOS.WMAvailable() - print >> test.test_support.get_original_stdout(), \ - '\tcheck_tk_availability -- WMAvailable returned %r' % wma - except ImportError: - print >> test.test_support.get_original_stdout(), \ - '\tcheck_tk_availability -- could not import MacOS' - if not wma: - raise unittest.SkipTest("Window manager is not available") - # ** end of temporary test code for issue8716 ** - # The Aqua Tk implementations on OS X can abort the process if # being called in an environment where a window server connection # cannot be made, for instance when invoked by a buildbot or ssh -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 6 04:12:11 2011 From: python-checkins at python.org (ned.deily) Date: Wed, 06 Jul 2011 04:12:11 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzg3MTY6?= =?utf8?q?_Instead_of_relying_on_Aqua_Tk_exceptions_to_detect_lack_of?= Message-ID: http://hg.python.org/cpython/rev/b5ac5e25d506 changeset: 71241:b5ac5e25d506 branch: 2.7 user: Ned Deily date: Tue Jul 05 19:08:38 2011 -0700 summary: Issue #8716: Instead of relying on Aqua Tk exceptions to detect lack of OS X window manager connection in tk tests, use OS X Application Services API calls instead. files: Lib/lib-tk/test/runtktests.py | 60 +++++++++++++--------- 1 files changed, 35 insertions(+), 25 deletions(-) diff --git a/Lib/lib-tk/test/runtktests.py b/Lib/lib-tk/test/runtktests.py --- a/Lib/lib-tk/test/runtktests.py +++ b/Lib/lib-tk/test/runtktests.py @@ -10,41 +10,51 @@ import sys import unittest import importlib -import subprocess import test.test_support this_dir_path = os.path.abspath(os.path.dirname(__file__)) -_tk_available = None +_tk_unavailable = None def check_tk_availability(): """Check that Tk is installed and available.""" - global _tk_available + global _tk_unavailable - if _tk_available is not None: - return + if _tk_unavailable is None: + _tk_unavailable = False + if sys.platform == 'darwin': + # The Aqua Tk implementations on OS X can abort the process if + # being called in an environment where a window server connection + # cannot be made, for instance when invoked by a buildbot or ssh + # process not running under the same user id as the current console + # user. To avoid that, raise an exception if the window manager + # connection is not available. + from ctypes import cdll, c_int, pointer, Structure + from ctypes.util import find_library - if sys.platform == 'darwin': - # The Aqua Tk implementations on OS X can abort the process if - # being called in an environment where a window server connection - # cannot be made, for instance when invoked by a buildbot or ssh - # process not running under the same user id as the current console - # user. Instead, try to initialize Tk under a subprocess. - p = subprocess.Popen( - [sys.executable, '-c', 'import Tkinter; Tkinter.Button()'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stderr = test.test_support.strip_python_stderr(p.communicate()[1]) - if stderr or p.returncode: - raise unittest.SkipTest("tk cannot be initialized: %s" % stderr) - else: - import Tkinter - try: - Tkinter.Button() - except Tkinter.TclError as msg: - # assuming tk is not available - raise unittest.SkipTest("tk not available: %s" % msg) + app_services = cdll.LoadLibrary(find_library("ApplicationServices")) - _tk_available = True + if app_services.CGMainDisplayID() == 0: + _tk_unavailable = "cannot run without OS X window manager" + else: + class ProcessSerialNumber(Structure): + _fields_ = [("highLongOfPSN", c_int), + ("lowLongOfPSN", c_int)] + psn = ProcessSerialNumber() + psn_p = pointer(psn) + if ( (app_services.GetCurrentProcess(psn_p) < 0) or + (app_services.SetFrontProcess(psn_p) < 0) ): + _tk_unavailable = "cannot run without OS X gui process" + else: # not OS X + import Tkinter + try: + Tkinter.Button() + except Tkinter.TclError as msg: + # assuming tk is not available + _tk_unavailable = "tk not available: %s" % msg + + if _tk_unavailable: + raise unittest.SkipTest(_tk_unavailable) return def is_package(path): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 6 04:12:12 2011 From: python-checkins at python.org (ned.deily) Date: Wed, 06 Jul 2011 04:12:12 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzg3MTY6?= =?utf8?q?_Instead_of_relying_on_Aqua_Tk_exceptions_to_detect_lack_of?= Message-ID: http://hg.python.org/cpython/rev/b58b0c5c7e96 changeset: 71242:b58b0c5c7e96 branch: 3.2 parent: 71233:807921ba241d user: Ned Deily date: Tue Jul 05 19:09:37 2011 -0700 summary: Issue #8716: Instead of relying on Aqua Tk exceptions to detect lack of OS X window manager connection in tk tests, use OS X Application Services API calls instead. files: Lib/tkinter/test/support.py | 60 ++++++++++++++---------- 1 files changed, 35 insertions(+), 25 deletions(-) diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -1,38 +1,48 @@ -import subprocess import sys -from test import support import tkinter import unittest -_tk_available = None +_tk_unavailable = None def check_tk_availability(): """Check that Tk is installed and available.""" - global _tk_available + global _tk_unavailable - if _tk_available is not None: - return + if _tk_unavailable is None: + _tk_unavailable = False + if sys.platform == 'darwin': + # The Aqua Tk implementations on OS X can abort the process if + # being called in an environment where a window server connection + # cannot be made, for instance when invoked by a buildbot or ssh + # process not running under the same user id as the current console + # user. To avoid that, raise an exception if the window manager + # connection is not available. + from ctypes import cdll, c_int, pointer, Structure + from ctypes.util import find_library - if sys.platform == 'darwin': - # The Aqua Tk implementations on OS X can abort the process if - # being called in an environment where a window server connection - # cannot be made, for instance when invoked by a buildbot or ssh - # process not running under the same user id as the current console - # user. Instead, try to initialize Tk under a subprocess. - p = subprocess.Popen( - [sys.executable, '-c', 'import tkinter; tkinter.Button()'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stderr = support.strip_python_stderr(p.communicate()[1]) - if stderr or p.returncode: - raise unittest.SkipTest("tk cannot be initialized: %s" % stderr) - else: - try: - tkinter.Button() - except tkinter.TclError as msg: - # assuming tk is not available - raise unittest.SkipTest("tk not available: %s" % msg) + app_services = cdll.LoadLibrary(find_library("ApplicationServices")) - _tk_available = True + if app_services.CGMainDisplayID() == 0: + _tk_unavailable = "cannot run without OS X window manager" + else: + class ProcessSerialNumber(Structure): + _fields_ = [("highLongOfPSN", c_int), + ("lowLongOfPSN", c_int)] + psn = ProcessSerialNumber() + psn_p = pointer(psn) + if ( (app_services.GetCurrentProcess(psn_p) < 0) or + (app_services.SetFrontProcess(psn_p) < 0) ): + _tk_unavailable = "cannot run without OS X gui process" + else: # not OS X + import tkinter + try: + tkinter.Button() + except tkinter.TclError as msg: + # assuming tk is not available + _tk_unavailable = "tk not available: %s" % msg + + if _tk_unavailable: + raise unittest.SkipTest(_tk_unavailable) return def get_tk_root(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 6 04:12:15 2011 From: python-checkins at python.org (ned.deily) Date: Wed, 06 Jul 2011 04:12:15 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=238716=3A_Instead_of_relying_on_Aqua_Tk_exceptions_to?= =?utf8?q?_detect_lack_of?= Message-ID: http://hg.python.org/cpython/rev/2f7e353f9e83 changeset: 71243:2f7e353f9e83 parent: 71239:f362f0053eab parent: 71242:b58b0c5c7e96 user: Ned Deily date: Tue Jul 05 19:11:15 2011 -0700 summary: Issue #8716: Instead of relying on Aqua Tk exceptions to detect lack of OS X window manager connection in tk tests, use OS X Application Services API calls instead. files: Lib/tkinter/test/support.py | 60 ++++++++++++++---------- 1 files changed, 35 insertions(+), 25 deletions(-) diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -1,38 +1,48 @@ -import subprocess import sys -from test import support import tkinter import unittest -_tk_available = None +_tk_unavailable = None def check_tk_availability(): """Check that Tk is installed and available.""" - global _tk_available + global _tk_unavailable - if _tk_available is not None: - return + if _tk_unavailable is None: + _tk_unavailable = False + if sys.platform == 'darwin': + # The Aqua Tk implementations on OS X can abort the process if + # being called in an environment where a window server connection + # cannot be made, for instance when invoked by a buildbot or ssh + # process not running under the same user id as the current console + # user. To avoid that, raise an exception if the window manager + # connection is not available. + from ctypes import cdll, c_int, pointer, Structure + from ctypes.util import find_library - if sys.platform == 'darwin': - # The Aqua Tk implementations on OS X can abort the process if - # being called in an environment where a window server connection - # cannot be made, for instance when invoked by a buildbot or ssh - # process not running under the same user id as the current console - # user. Instead, try to initialize Tk under a subprocess. - p = subprocess.Popen( - [sys.executable, '-c', 'import tkinter; tkinter.Button()'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stderr = support.strip_python_stderr(p.communicate()[1]) - if stderr or p.returncode: - raise unittest.SkipTest("tk cannot be initialized: %s" % stderr) - else: - try: - tkinter.Button() - except tkinter.TclError as msg: - # assuming tk is not available - raise unittest.SkipTest("tk not available: %s" % msg) + app_services = cdll.LoadLibrary(find_library("ApplicationServices")) - _tk_available = True + if app_services.CGMainDisplayID() == 0: + _tk_unavailable = "cannot run without OS X window manager" + else: + class ProcessSerialNumber(Structure): + _fields_ = [("highLongOfPSN", c_int), + ("lowLongOfPSN", c_int)] + psn = ProcessSerialNumber() + psn_p = pointer(psn) + if ( (app_services.GetCurrentProcess(psn_p) < 0) or + (app_services.SetFrontProcess(psn_p) < 0) ): + _tk_unavailable = "cannot run without OS X gui process" + else: # not OS X + import tkinter + try: + tkinter.Button() + except tkinter.TclError as msg: + # assuming tk is not available + _tk_unavailable = "tk not available: %s" % msg + + if _tk_unavailable: + raise unittest.SkipTest(_tk_unavailable) return def get_tk_root(): -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Jul 6 05:08:56 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 06 Jul 2011 05:08:56 +0200 Subject: [Python-checkins] Daily reference leaks (f362f0053eab): sum=-77 Message-ID: results for f362f0053eab on branch "default" -------------------------------------------- test_concurrent_futures leaked [54, 0, -108] references, sum=-54 test_packaging leaked [100, 100, 100] references, sum=300 test_pydoc leaked [0, 0, -323] references, sum=-323 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogSK9znv', '-x'] From python-checkins at python.org Wed Jul 6 07:31:12 2011 From: python-checkins at python.org (georg.brandl) Date: Wed, 06 Jul 2011 07:31:12 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Revert_76452b892838_as_per?= Message-ID: http://hg.python.org/cpython/rev/71a1f53c8203 changeset: 71244:71a1f53c8203 user: Georg Brandl date: Wed Jul 06 07:31:38 2011 +0200 summary: Revert 76452b892838 as per http://mail.python.org/pipermail/python-dev/2011-July/112243.html. files: Lib/test/test_csv.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -459,20 +459,20 @@ '5', '6']]) def test_quoted_quote(self): - self.readerAssertEqual('1,2,3,"""I see,"" said the happy man","as he picked up his hammer and saw"', + self.readerAssertEqual('1,2,3,"""I see,"" said the blind man","as he picked up his hammer and saw"', [['1', '2', '3', - '"I see," said the happy man', + '"I see," said the blind man', 'as he picked up his hammer and saw']]) def test_quoted_nl(self): input = '''\ 1,2,3,"""I see,"" -said the happy man","as he picked up his +said the blind man","as he picked up his hammer and saw" 9,8,7,6''' self.readerAssertEqual(input, [['1', '2', '3', - '"I see,"\nsaid the happy man', + '"I see,"\nsaid the blind man', 'as he picked up his\nhammer and saw'], ['9','8','7','6']]) -- Repository URL: http://hg.python.org/cpython From g.brandl at gmx.net Wed Jul 6 07:35:15 2011 From: g.brandl at gmx.net (Georg Brandl) Date: Wed, 06 Jul 2011 07:35:15 +0200 Subject: [Python-checkins] cpython: Remove mention of medical condition from the test suite. In-Reply-To: References: Message-ID: Am 06.07.2011 02:35, schrieb Guido van Rossum: > To clarify, now that I have access to an actual keyboard instead of > just a cellphone: I think it should be rolled back, since the proper > process for controversial changes was not followed. Our process (part > of our culture, if you will) for anything controversial is to discuss > the change first, then, if deemed necessary, fix the code. And from > the size of this thread it clearly is controversial. Georg, can you > please revert this change? Sure; done. > Note that another part of our process/culture is that we try not to > engage in battling commits, i.e. generally we don't unilaterally roll > back a change just to make the point that it is incorrect; we ask the > original committer to roll it back. > > As to the controversy itself, if you want to make blind people fell > more at home in the Python community surely there are more useful > things to do than to remove puns involving blindness; e.g. improve > accessibility of python.org or some part of it. Or maybe find some > blind programmers and ask them what would help them. Well, it was stated that even non-joking use of such words can offend (the example given was "your argument is blind to (these facts)"). I consider use in jokes to be more serious, since it's careless use. Sorry if I overreacted here. Georg From ncoghlan at gmail.com Wed Jul 6 08:49:32 2011 From: ncoghlan at gmail.com (Nick Coghlan) Date: Wed, 6 Jul 2011 16:49:32 +1000 Subject: [Python-checkins] [Python-Dev] cpython: Remove mention of medical condition from the test suite. In-Reply-To: References: <87fwmldyyz.fsf@uwakimon.sk.tsukuba.ac.jp> Message-ID: On Wed, Jul 6, 2011 at 6:17 AM, Georg Brandl wrote: > For this test string, a) I'm not a native speaker and therefore don't know of > any special treatment this pun deserves It's not an especially *good* joke, just a very old one that plays on double meanings of both "see" (as in sight and understanding) and "saw" (as in sight and a tool). Still, I'd put it in the same category as the Monty Python quotes we have scattered around the test suite - if people came across them and didn't realise they were quotes they might be puzzled, but attempting to retain that Pythonesque sense of humour is itself part of what makes the Python community what it is. Cheers, Nick. -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From solipsis at pitrou.net Thu Jul 7 05:09:11 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 07 Jul 2011 05:09:11 +0200 Subject: [Python-checkins] Daily reference leaks (71a1f53c8203): sum=300 Message-ID: results for 71a1f53c8203 on branch "default" -------------------------------------------- test_concurrent_futures leaked [639, 0, -639] references, sum=0 test_packaging leaked [100, 100, 100] references, sum=300 test_pydoc leaked [-323, 323, 0] references, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog0fk6PV', '-x'] From python-checkins at python.org Thu Jul 7 13:59:39 2011 From: python-checkins at python.org (vinay.sajip) Date: Thu, 07 Jul 2011 13:59:39 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Closes_=2312391=3A_temporar?= =?utf8?q?y_files_are_now_cleaned_up=2E?= Message-ID: http://hg.python.org/cpython/rev/a4405b799e1b changeset: 71245:a4405b799e1b user: Vinay Sajip date: Thu Jul 07 12:59:31 2011 +0100 summary: Closes #12391: temporary files are now cleaned up. files: Lib/packaging/install.py | 12 +++++------- 1 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Lib/packaging/install.py b/Lib/packaging/install.py --- a/Lib/packaging/install.py +++ b/Lib/packaging/install.py @@ -42,10 +42,7 @@ :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: filename = os.path.split(old)[-1] @@ -126,8 +123,11 @@ elif _is_archive_file(path): logger.info('Installing from archive: %s', path) _unpacked_dir = tempfile.mkdtemp() - shutil.unpack_archive(path, _unpacked_dir) - return _run_install_from_archive(_unpacked_dir) + try: + shutil.unpack_archive(path, _unpacked_dir) + return _run_install_from_archive(_unpacked_dir) + finally: + shutil.rmtree(_unpacked_dir) else: logger.warning('No projects to install.') return False @@ -179,8 +179,6 @@ :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: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 7 14:08:54 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 07 Jul 2011 14:08:54 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_Add_PEP_400=3A_Deprecate_codec?= =?utf8?q?s=2EStreamReader_and_codecs=2EStreamWriter?= Message-ID: http://hg.python.org/peps/rev/49565ae9b261 changeset: 3894:49565ae9b261 user: Victor Stinner date: Thu Jul 07 14:08:47 2011 +0200 summary: Add PEP 400: Deprecate codecs.StreamReader and codecs.StreamWriter files: pep-0400.txt | 323 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 323 insertions(+), 0 deletions(-) diff --git a/pep-0400.txt b/pep-0400.txt new file mode 100644 --- /dev/null +++ b/pep-0400.txt @@ -0,0 +1,323 @@ +PEP: 400 +Title: Deprecate codecs.StreamReader and codecs.StreamWriter +Version: $Revision$ +Last-Modified: $Date$ +Author: Victor Stinner +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 28-May-2011 +Python-Version: 3.3 + + +Abstract +======== + +io.TextIOWrapper and codecs.StreamReaderWriter offer the same API +[#f1]_. TextIOWrapper has more features and is faster than +StreamReaderWriter. Duplicate code means that bugs should be fixed +twice and that we may have subtle differences between the two +implementations. + +The codecs modules was introduced in Python 2.0, see the PEP 100. The +io module was introduced in Python 2.6 and 3.0 (see the PEP 3116), and +reimplemented in C in Python 2.7 and 3.1. + + +Motivation +========== + +When the Python I/O model was updated for 3.0, the concept of a +"stream-with-known-encoding" was introduced in the form of +io.TextIOWrapper. As this class is critical to the performance of +text-based I/O in Python 3, this module has an optimised C version +which is used by CPython by default. Many corner cases in handling +buffering, stateful codecs and universal newlines have been dealt with +since the release of Python 3.0. + +This new interface overlaps heavily with the legacy +codecs.StreamReader, codecs.StreamWriter and codecs.StreamReaderWriter +interfaces that were part of the original codec interface design in +PEP 100. These interfaces are organised around the principle of an +encoding with an associated stream (i.e. the reverse of arrangement in +the io module), so the original PEP 100 design required that codec +writers provide appropriate StreamReader and StreamWriter +implementations in addition to the core codec encode() and decode() +methods. This places a heavy burden on codec authors providing these +specialised implementations to correctly handle many of the corner +cases that have now been dealt with by io.TextIOWrapper. While deeper +integration between the codec and the stream allows for additional +optimisations in theory, these optimisations have in practice either +not been carried out and else the associated code duplication means +that the corner cases that have been fixed in io.TextIOWrapper are +still not handled correctly in the various StreamReader and +StreamWriter implementations. + +Accordingly, this PEP proposes that: + +* codecs.open() be updated to delegate to the builtin open() in Python + 3.3; +* the legacy codecs.Stream* interfaces, including the streamreader and + streamwriter attributes of codecs.CodecInfo be deprecated in Python + 3.3 and removed in Python 3.4. + + +Rationale +========= + +StreamReader and StreamWriter issues +'''''''''''''''''''''''''''''''''''' + + * StreamReader is unable to translate newlines. + * StreamReaderWriter handles reads using StreamReader and writes + using StreamWriter. These two classes may be inconsistent. To stay + consistent, flush() must be called after each write which slows + down interlaced read-write. + * StreamWriter doesn't support "line buffering" (flush if the input + text contains a newline). + * StreamReader classes of the CJK encodings (e.g. GB18030) don't + support universal newlines, only UNIX newlines ('\\n'). + * StreamReader and StreamWriter are stateful codecs but don't expose + functions to control their state (getstate() or setstate()). Each + codec has to implement corner cases, see "Issue with stateful + codecs". + * StreamReader and StreamWriter are very similar to IncrementalReader + and IncrementalEncoder, some code is duplicated for stateful codecs + (e.g. UTF-16). + * Each codec has to reimplement its own StreamReader and StreamWriter + class, even if it's trivial (just call the encoder/decoder). + * codecs.open(filename, "r") creates a io.TextIOWrapper object. + * No codec implements an optimized method in StreamReader or + StreamWriter based on the specificities of the codec. + +Other issues in the bug tracker: + + * `Issue #5445 `_ (2009-03-08): + codecs.StreamWriter.writelines problem when passed generator + * `Issue #7262: `_ (2009-11-04): + codecs.open() + eol (windows) + * `Issue #8260 `_ (2010-03-29): + When I use codecs.open(...) and f.readline() follow up by f.read() + return bad result + * `Issue #8630 `_ (2010-05-05): + Keepends param in codec readline(s) + * `Issue #10344 `_ (2010-11-06): + codecs.readline doesn't care buffering + * `Issue #11461 `_ (2011-03-10): + Reading UTF-16 with codecs.readline() breaks on surrogate pairs + * `Issue #12446 `_ (2011-06-30): + StreamReader Readlines behavior odd + * `Issue #12508 `_ (2011-07-06): + Codecs Anomaly + * `Issue #12512 `_ (2011-07-07): + codecs: StreamWriter issues with stateful codecs after a seek or + with append mode + +TextIOWrapper features +'''''''''''''''''''''' + + * TextIOWrapper supports any kind of newline, including translating + newlines (to UNIX newlines), to read and write. + * TextIOWrapper reuses incremental encoders and decoders (no + duplication of code). + * The io module (TextIOWrapper) is faster than the codecs module + (StreamReader). It is implemented in C, whereas codecs is + implemented in Python. + * TextIOWrapper has a readahead algorithm which speeds up small + reads: read character by character or line by line (io is 10x + through 25x faster than codecs on these operations). + * TextIOWrapper has a write buffer. + * TextIOWrapper.tell() is optimized. + * TextIOWrapper supports random access (read+write) using a single + class which permit to optimize interlaced read-write (but no such + optimization is implemented). + +TextIOWrapper issues +'''''''''''''''''''' + + * `Issue #12213 `_ (2011-05-30): + BufferedRandom, BufferedRWPair: issues with interlaced read-write + * `Issue #12215 `_ (2011-05-30): + TextIOWrapper: issues with interlaced read-write + +Possible improvements of StreamReader and StreamWriter +'''''''''''''''''''''''''''''''''''''''''''''''''''''' + +It would be possible to add functions to StreamReader and StreamWriter +to give access to the state of codec. And so it would be possible fix +issues with stateful codecs in a base class instead of having to fix +them is each stateful StreamReader and StreamWriter classes. + +It would be possible to change StreamReader and StreamWriter to make +them use IncrementalDecoder and IncrementalEncoder. + +A codec can implement variants which are optimized for the specific +encoding or intercept certain stream methods to add functionality or +improve the encoding/decoding performance. TextIOWrapper cannot +implement such optimization, but TextIOWrapper uses incremental +encoders and decoders and uses read and write buffers, so the overhead +of incomplete inputs is low or nul. + +A lot more could be done for other variable length encoding codecs, +e.g. UTF-8, since these often have problems near the end of a read due +to missing bytes. The UTF-32-BE/LE codecs could simply multiply the +character position by 4 to get the byte position. + + +Usage of StreamReader and StreamWriter +'''''''''''''''''''''''''''''''''''''' + +These classes are rarely used directly, but indirectly using +codecs.open(). They are not used in Python 3 standard library (except +in the codecs module). + +Some projects implement their own codec with StreamReader and +StreamWriter, but don't use these classes. + + +Backwards Compatibility +======================= + +Keep the public API, codecs.open +'''''''''''''''''''''''''''''''' + +codecs.open() can be replaced by the builtin open() function. open() +has a similar API but has also more options. + +codecs.open() was the only way to open a text file in Unicode mode +until Python 2.6. Many Python 2 programs uses this function. Removing +codecs.open() implies more work to port programs from Python 2 to +Python 3, especially projets using the same code base for the two +Python versions (without using 2to3 program). + +codecs.open() is kept for backward compatibility with Python 2. + + +Deprecate StreamReader and StreamWriter +''''''''''''''''''''''''''''''''''''''' + +Instanciate StreamReader or StreamWriter must raise a +DeprecationWarning in Python 3.3. Implement a subclass don't raise a +DeprecationWarning. + +codecs.open() will be changed to reuse the builtin open() function +(TextIOWrapper). + +EncodedFile(), StreamRandom, StreamReader, StreamReaderWriter and +StreamWriter will be removed in Python 3.4. + + +Issue with stateful codecs +========================== + +It is difficult to use correctly a stateful codec with a stream. Some +cases are supported by the codecs module, while io has no more known +bug related to stateful codecs. The main difference between the codecs +and the io module is that bugs have to be fixed in StreamReader and/or +StreamWriter classes of each codec for the codecs module, whereas bugs +can be fixed only once in io.TextIOWrapper. Here are some examples of +issues with stateful codecs. + +Stateful codecs +''''''''''''''' + +Python supports the following stateful codecs: + + * cp932 + * cp949 + * cp950 + * euc_jis_2004 + * euc_jisx2003 + * euc_jp + * euc_kr + * gb18030 + * gbk + * hz + * iso2022_jp + * iso2022_jp_1 + * iso2022_jp_2 + * iso2022_jp_2004 + * iso2022_jp_3 + * iso2022_jp_ext + * iso2022_kr + * shift_jis + * shift_jis_2004 + * shift_jisx0213 + * utf_8_sig + * utf_16 + * utf_32 + +Read and seek(0) +'''''''''''''''' + +:: + + with open(filename, 'w', encoding='utf-16') as f: + f.write('abc') + f.write('def') + f.seek(0) + assert f.read() == 'abcdef' + f.seek(0) + assert f.read() == 'abcdef' + +The io and codecs modules support this usecase correctly. + +seek(n) +''''''' + +:: + + with open(filename, 'w', encoding='utf-16') as f: + f.write('abc') + pos = f.tell() + with open(filename, 'w', encoding='utf-16') as f: + f.seek(pos) + f.write('def') + f.seek(0) + f.write('###') + with open(filename, 'r', encoding='utf-16') as f: + assert f.read() == '###def' + +The io module supports this usecase, whereas codecs fails because it +writes a new BOM on the second write (issue #12512). + +Append mode +''''''''''' + +:: + + with open(filename, 'w', encoding='utf-16') as f: + f.write('abc') + with open(filename, 'a', encoding='utf-16') as f: + f.write('def') + with open(filename, 'r', encoding='utf-16') as f: + assert f.read() == 'abcdef' + +The io module supports this usecase, whereas codecs fails because it +writes a new BOM on the second write (issue #12512). + + +Links +===== + + * `PEP 100: Python Unicode Integration + `_ + * `PEP 3116 `_ + * `Issue #8796: Deprecate codecs.open() + `_ + * `[python-dev] Deprecate codecs.open() and StreamWriter/StreamReader + `_ + + +Copyright +========= + +This document has been placed in the public domain. + + +Footnotes +========= + +.. [#f1] StreamReaderWriter has two more attributes than + TextIOWrapper, reader and writer. + -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jul 7 14:40:52 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 07 Jul 2011 14:40:52 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_400=3A_typo?= Message-ID: http://hg.python.org/peps/rev/bd79ad755ca2 changeset: 3895:bd79ad755ca2 user: Victor Stinner date: Thu Jul 07 14:40:48 2011 +0200 summary: PEP 400: typo files: pep-0400.txt | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pep-0400.txt b/pep-0400.txt --- a/pep-0400.txt +++ b/pep-0400.txt @@ -19,7 +19,7 @@ twice and that we may have subtle differences between the two implementations. -The codecs modules was introduced in Python 2.0, see the PEP 100. The +The codecs module was introduced in Python 2.0, see the PEP 100. The io module was introduced in Python 2.6 and 3.0 (see the PEP 3116), and reimplemented in C in Python 2.7 and 3.1. @@ -143,10 +143,10 @@ Possible improvements of StreamReader and StreamWriter '''''''''''''''''''''''''''''''''''''''''''''''''''''' -It would be possible to add functions to StreamReader and StreamWriter -to give access to the state of codec. And so it would be possible fix -issues with stateful codecs in a base class instead of having to fix -them is each stateful StreamReader and StreamWriter classes. +By adding codec state read/write functions to the StreamReader and +StreamWriter classes, it will become possible to fix issues with +stateful codecs in a base class instead of in each stateful +StreamReader and StreamWriter classes. It would be possible to change StreamReader and StreamWriter to make them use IncrementalDecoder and IncrementalEncoder. @@ -196,9 +196,9 @@ Deprecate StreamReader and StreamWriter ''''''''''''''''''''''''''''''''''''''' -Instanciate StreamReader or StreamWriter must raise a -DeprecationWarning in Python 3.3. Implement a subclass don't raise a -DeprecationWarning. +Instanciating StreamReader or StreamWriter must raise a +DeprecationWarning in Python 3.3. Implementing a subclass doesn't +raise a DeprecationWarning. codecs.open() will be changed to reuse the builtin open() function (TextIOWrapper). -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jul 7 15:15:20 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 07 Jul 2011 15:15:20 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_400=3A_update_interlaced_r?= =?utf8?q?ead-write_issues?= Message-ID: http://hg.python.org/peps/rev/472453d5bbb3 changeset: 3896:472453d5bbb3 user: Victor Stinner date: Thu Jul 07 15:15:17 2011 +0200 summary: PEP 400: update interlaced read-write issues Note: Issue #12213 doesn't concern TextIOWrapper, it concerns Buffered* classes which are also used by the codecs module. files: pep-0400.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0400.txt b/pep-0400.txt --- a/pep-0400.txt +++ b/pep-0400.txt @@ -112,6 +112,8 @@ * `Issue #12512 `_ (2011-07-07): codecs: StreamWriter issues with stateful codecs after a seek or with append mode + * `Issue #12513 `_ (2011-07-07): + codec.StreamReaderWriter: issues with interlaced read-write TextIOWrapper features '''''''''''''''''''''' @@ -135,8 +137,6 @@ TextIOWrapper issues '''''''''''''''''''' - * `Issue #12213 `_ (2011-05-30): - BufferedRandom, BufferedRWPair: issues with interlaced read-write * `Issue #12215 `_ (2011-05-30): TextIOWrapper: issues with interlaced read-write -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Jul 8 01:10:39 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Jul 2011 01:10:39 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=239566=3A_cast_unsig?= =?utf8?q?ned_int_to_Py=5Fssize=5Ft_in_md5_and_sha1_modules?= Message-ID: http://hg.python.org/cpython/rev/43fd627cc060 changeset: 71246:43fd627cc060 user: Victor Stinner date: Fri Jul 08 01:10:28 2011 +0200 summary: Issue #9566: cast unsigned int to Py_ssize_t in md5 and sha1 modules Fix a compiler warning on Windows 64 bits. files: Modules/md5module.c | 2 +- Modules/sha1module.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/md5module.c b/Modules/md5module.c --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -243,7 +243,7 @@ in += MD5_BLOCKSIZE; inlen -= MD5_BLOCKSIZE; } else { - n = MIN(inlen, (MD5_BLOCKSIZE - md5->curlen)); + n = MIN(inlen, (Py_ssize_t)(MD5_BLOCKSIZE - md5->curlen)); memcpy(md5->buf + md5->curlen, in, (size_t)n); md5->curlen += n; in += n; diff --git a/Modules/sha1module.c b/Modules/sha1module.c --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -218,7 +218,7 @@ in += SHA1_BLOCKSIZE; inlen -= SHA1_BLOCKSIZE; } else { - n = MIN(inlen, (SHA1_BLOCKSIZE - sha1->curlen)); + n = MIN(inlen, (Py_ssize_t)(SHA1_BLOCKSIZE - sha1->curlen)); memcpy(sha1->buf + sha1->curlen, in, (size_t)n); sha1->curlen += n; in += n; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 01:45:23 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Jul 2011 01:45:23 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312016=3A_Multibyte?= =?utf8?q?_CJK_decoders_now_resynchronize_faster?= Message-ID: http://hg.python.org/cpython/rev/16cbd84de848 changeset: 71247:16cbd84de848 user: Victor Stinner date: Fri Jul 08 01:45:13 2011 +0200 summary: Issue #12016: Multibyte CJK decoders now resynchronize faster They only ignore the first byte of an invalid byte sequence. For example, b'\xff\n'.decode('gb2312', 'replace') gives '\ufffd\n' instead of '\ufffd'. files: Doc/whatsnew/3.3.rst | 23 ++++ Lib/test/test_codecencodings_cn.py | 21 ++- Lib/test/test_codecencodings_hk.py | 4 +- Lib/test/test_codecencodings_jp.py | 96 +++++++++++------ Lib/test/test_codecencodings_kr.py | 25 ++- Lib/test/test_codecencodings_tw.py | 4 +- Lib/test/test_codecmaps_tw.py | 3 + Misc/NEWS | 4 + Modules/cjkcodecs/_codecs_cn.c | 14 +- Modules/cjkcodecs/_codecs_hk.c | 2 +- Modules/cjkcodecs/_codecs_jp.c | 34 +++--- Modules/cjkcodecs/_codecs_kr.c | 18 +- Modules/cjkcodecs/_codecs_tw.c | 4 +- 13 files changed, 159 insertions(+), 93 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 @@ -68,6 +68,29 @@ * Stub +codecs +------ + +Multibyte CJK decoders now resynchronize faster. They only ignore the first +byte of an invalid byte sequence. For example, b'\xff\n'.decode('gb2312', +'replace') gives '?\n' instead of '?'. + +(http://bugs.python.org/issue12016) + +Don't reset incremental encoders of CJK codecs at each call to their encode() +method anymore. For example: :: + + $ ./python -q + >>> import codecs + >>> encoder = codecs.getincrementalencoder('hz')('strict') + >>> b''.join(encoder.encode(x) for x in '\u52ff\u65bd\u65bc\u4eba\u3002 Bye.') + b'~{NpJ)l6HK!#~} Bye.' + +This example gives b'~{Np~}~{J)~}~{l6~}~{HK~}~{!#~} Bye.' with older Python +versions. + +(http://bugs.python.org/issue12100) + faulthandler ------------ diff --git a/Lib/test/test_codecencodings_cn.py b/Lib/test/test_codecencodings_cn.py --- a/Lib/test/test_codecencodings_cn.py +++ b/Lib/test/test_codecencodings_cn.py @@ -15,8 +15,8 @@ # invalid bytes (b"abc\x81\x81\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x81\x81\xc1\xc4", "replace", "abc\ufffd\u804a"), - (b"abc\x81\x81\xc1\xc4\xc8", "replace", "abc\ufffd\u804a\ufffd"), + (b"abc\x81\x81\xc1\xc4", "replace", "abc\ufffd\ufffd\u804a"), + (b"abc\x81\x81\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u804a\ufffd"), (b"abc\x81\x81\xc1\xc4", "ignore", "abc\u804a"), (b"\xc1\x64", "strict", None), ) @@ -28,8 +28,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u804a"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u804a\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u804a"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u804a\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u804a"), (b"\x83\x34\x83\x31", "strict", None), ("\u30fb", "strict", None), @@ -42,11 +42,14 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u804a"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u804a\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u804a"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u804a\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u804a"), - (b"abc\x84\x39\x84\x39\xc1\xc4", "replace", "abc\ufffd\u804a"), + (b"abc\x84\x39\x84\x39\xc1\xc4", "replace", "abc\ufffd9\ufffd9\u804a"), ("\u30fb", "strict", b"\x819\xa79"), + (b"abc\x84\x32\x80\x80def", "replace", 'abc\ufffd2\ufffd\ufffddef'), + (b"abc\x81\x30\x81\x30def", "strict", 'abc\x80def'), + (b"abc\x86\x30\x81\x30def", "replace", 'abc\ufffd0\ufffd0def'), ) has_iso10646 = True @@ -74,9 +77,11 @@ '\u5df1\u6240\u4e0d\u6b32\uff0c\u52ff\u65bd\u65bc\u4eba\u3002' 'Bye.\n'), # invalid bytes - (b'ab~cd', 'replace', 'ab\uFFFDd'), + (b'ab~cd', 'replace', 'ab\uFFFDcd'), (b'ab\xffcd', 'replace', 'ab\uFFFDcd'), (b'ab~{\x81\x81\x41\x44~}cd', 'replace', 'ab\uFFFD\uFFFD\u804Acd'), + (b'ab~{\x41\x44~}cd', 'replace', 'ab\u804Acd'), + (b"ab~{\x79\x79\x41\x44~}cd", "replace", "ab\ufffd\ufffd\u804acd"), ) def test_main(): diff --git a/Lib/test/test_codecencodings_hk.py b/Lib/test/test_codecencodings_hk.py --- a/Lib/test/test_codecencodings_hk.py +++ b/Lib/test/test_codecencodings_hk.py @@ -15,8 +15,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u8b10"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u8b10\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u8b10"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u8b10\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u8b10"), ) diff --git a/Lib/test/test_codecencodings_jp.py b/Lib/test/test_codecencodings_jp.py --- a/Lib/test/test_codecencodings_jp.py +++ b/Lib/test/test_codecencodings_jp.py @@ -15,50 +15,57 @@ # invalid bytes (b"abc\x81\x00\x81\x00\x82\x84", "strict", None), (b"abc\xf8", "strict", None), - (b"abc\x81\x00\x82\x84", "replace", "abc\ufffd\uff44"), - (b"abc\x81\x00\x82\x84\x88", "replace", "abc\ufffd\uff44\ufffd"), - (b"abc\x81\x00\x82\x84", "ignore", "abc\uff44"), + (b"abc\x81\x00\x82\x84", "replace", "abc\ufffd\x00\uff44"), + (b"abc\x81\x00\x82\x84\x88", "replace", "abc\ufffd\x00\uff44\ufffd"), + (b"abc\x81\x00\x82\x84", "ignore", "abc\x00\uff44"), + (b"ab\xEBxy", "replace", "ab\uFFFDxy"), + (b"ab\xF0\x39xy", "replace", "ab\uFFFD9xy"), + (b"ab\xEA\xF0xy", "replace", 'ab\ufffd\ue038y'), # sjis vs cp932 (b"\\\x7e", "replace", "\\\x7e"), (b"\x81\x5f\x81\x61\x81\x7c", "replace", "\uff3c\u2225\uff0d"), ) +euc_commontests = ( + # invalid bytes + (b"abc\x80\x80\xc1\xc4", "strict", None), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u7956"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u7956\ufffd"), + (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u7956"), + (b"abc\xc8", "strict", None), + (b"abc\x8f\x83\x83", "replace", "abc\ufffd\ufffd\ufffd"), + (b"\x82\xFCxy", "replace", "\ufffd\ufffdxy"), + (b"\xc1\x64", "strict", None), + (b"\xa1\xc0", "strict", "\uff3c"), + (b"\xa1\xc0\\", "strict", "\uff3c\\"), + (b"\x8eXY", "replace", "\ufffdXY"), +) + +class Test_EUC_JIS_2004(test_multibytecodec_support.TestBase, + unittest.TestCase): + encoding = 'euc_jis_2004' + tstring = test_multibytecodec_support.load_teststring('euc_jisx0213') + codectests = euc_commontests + xmlcharnametest = ( + "\xab\u211c\xbb = \u2329\u1234\u232a", + b"\xa9\xa8ℜ\xa9\xb2 = ⟨ሴ⟩" + ) + class Test_EUC_JISX0213(test_multibytecodec_support.TestBase, unittest.TestCase): encoding = 'euc_jisx0213' tstring = test_multibytecodec_support.load_teststring('euc_jisx0213') - codectests = ( - # invalid bytes - (b"abc\x80\x80\xc1\xc4", "strict", None), - (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u7956"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u7956\ufffd"), - (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u7956"), - (b"abc\x8f\x83\x83", "replace", "abc\ufffd"), - (b"\xc1\x64", "strict", None), - (b"\xa1\xc0", "strict", "\uff3c"), - ) + codectests = euc_commontests xmlcharnametest = ( "\xab\u211c\xbb = \u2329\u1234\u232a", b"\xa9\xa8ℜ\xa9\xb2 = ⟨ሴ⟩" ) -eucjp_commontests = ( - (b"abc\x80\x80\xc1\xc4", "strict", None), - (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u7956"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u7956\ufffd"), - (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u7956"), - (b"abc\x8f\x83\x83", "replace", "abc\ufffd"), - (b"\xc1\x64", "strict", None), -) - class Test_EUC_JP_COMPAT(test_multibytecodec_support.TestBase, unittest.TestCase): encoding = 'euc_jp' tstring = test_multibytecodec_support.load_teststring('euc_jp') - codectests = eucjp_commontests + ( - (b"\xa1\xc0\\", "strict", "\uff3c\\"), + codectests = euc_commontests + ( ("\xa5", "strict", b"\x5c"), ("\u203e", "strict", b"\x7e"), ) @@ -66,8 +73,6 @@ shiftjis_commonenctests = ( (b"abc\x80\x80\x82\x84", "strict", None), (b"abc\xf8", "strict", None), - (b"abc\x80\x80\x82\x84", "replace", "abc\ufffd\uff44"), - (b"abc\x80\x80\x82\x84\x88", "replace", "abc\ufffd\uff44\ufffd"), (b"abc\x80\x80\x82\x84def", "ignore", "abc\uff44def"), ) @@ -75,20 +80,41 @@ encoding = 'shift_jis' tstring = test_multibytecodec_support.load_teststring('shift_jis') codectests = shiftjis_commonenctests + ( + (b"abc\x80\x80\x82\x84", "replace", "abc\ufffd\ufffd\uff44"), + (b"abc\x80\x80\x82\x84\x88", "replace", "abc\ufffd\ufffd\uff44\ufffd"), + (b"\\\x7e", "strict", "\\\x7e"), (b"\x81\x5f\x81\x61\x81\x7c", "strict", "\uff3c\u2016\u2212"), + (b"abc\x81\x39", "replace", "abc\ufffd9"), + (b"abc\xEA\xFC", "replace", "abc\ufffd\ufffd"), + (b"abc\xFF\x58", "replace", "abc\ufffdX"), + ) + +class Test_SJIS_2004(test_multibytecodec_support.TestBase, unittest.TestCase): + encoding = 'shift_jis_2004' + tstring = test_multibytecodec_support.load_teststring('shift_jis') + codectests = shiftjis_commonenctests + ( + (b"\\\x7e", "strict", "\xa5\u203e"), + (b"\x81\x5f\x81\x61\x81\x7c", "strict", "\\\u2016\u2212"), + (b"abc\xEA\xFC", "strict", "abc\u64bf"), + (b"\x81\x39xy", "replace", "\ufffd9xy"), + (b"\xFF\x58xy", "replace", "\ufffdXxy"), + (b"\x80\x80\x82\x84xy", "replace", "\ufffd\ufffd\uff44xy"), + (b"\x80\x80\x82\x84\x88xy", "replace", "\ufffd\ufffd\uff44\u5864y"), + (b"\xFC\xFBxy", "replace", '\ufffd\u95b4y'), + ) + xmlcharnametest = ( + "\xab\u211c\xbb = \u2329\u1234\u232a", + b"\x85Gℜ\x85Q = ⟨ሴ⟩" ) class Test_SJISX0213(test_multibytecodec_support.TestBase, unittest.TestCase): encoding = 'shift_jisx0213' tstring = test_multibytecodec_support.load_teststring('shift_jisx0213') - codectests = ( - # invalid bytes - (b"abc\x80\x80\x82\x84", "strict", None), - (b"abc\xf8", "strict", None), - (b"abc\x80\x80\x82\x84", "replace", "abc\ufffd\uff44"), - (b"abc\x80\x80\x82\x84\x88", "replace", "abc\ufffd\uff44\ufffd"), - (b"abc\x80\x80\x82\x84def", "ignore", "abc\uff44def"), + codectests = shiftjis_commonenctests + ( + (b"abc\x80\x80\x82\x84", "replace", "abc\ufffd\ufffd\uff44"), + (b"abc\x80\x80\x82\x84\x88", "replace", "abc\ufffd\ufffd\uff44\ufffd"), + # sjis vs cp932 (b"\\\x7e", "replace", "\xa5\u203e"), (b"\x81\x5f\x81\x61\x81\x7c", "replace", "\x5c\u2016\u2212"), diff --git a/Lib/test/test_codecencodings_kr.py b/Lib/test/test_codecencodings_kr.py --- a/Lib/test/test_codecencodings_kr.py +++ b/Lib/test/test_codecencodings_kr.py @@ -15,8 +15,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\uc894"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\uc894\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\uc894"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\uc894\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\uc894"), ) @@ -27,8 +27,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\uc894"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\uc894\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", 'abc\ufffd\ufffd\uc894'), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\uc894\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\uc894"), # composed make-up sequence errors @@ -40,13 +40,14 @@ (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4", "strict", None), (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xd4", "strict", "\uc4d4"), (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xd4x", "strict", "\uc4d4x"), - (b"a\xa4\xd4\xa4\xb6\xa4", "replace", "a\ufffd"), + (b"a\xa4\xd4\xa4\xb6\xa4", "replace", 'a\ufffd'), (b"\xa4\xd4\xa3\xb6\xa4\xd0\xa4\xd4", "strict", None), (b"\xa4\xd4\xa4\xb6\xa3\xd0\xa4\xd4", "strict", None), (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa3\xd4", "strict", None), - (b"\xa4\xd4\xa4\xff\xa4\xd0\xa4\xd4", "replace", "\ufffd"), - (b"\xa4\xd4\xa4\xb6\xa4\xff\xa4\xd4", "replace", "\ufffd"), - (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xff", "replace", "\ufffd"), + (b"\xa4\xd4\xa4\xff\xa4\xd0\xa4\xd4", "replace", '\ufffd\u6e21\ufffd\u3160\ufffd'), + (b"\xa4\xd4\xa4\xb6\xa4\xff\xa4\xd4", "replace", '\ufffd\u6e21\ub544\ufffd\ufffd'), + (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xff", "replace", '\ufffd\u6e21\ub544\u572d\ufffd'), + (b"\xa4\xd4\xff\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xd4", "replace", '\ufffd\ufffd\ufffd\uc4d4'), (b"\xc1\xc4", "strict", "\uc894"), ) @@ -57,9 +58,13 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ucd27"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ucd27\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\ucd27"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\ucd27\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\ucd27"), + (b"\xD8abc", "replace", "\uFFFDabc"), + (b"\xD8\xFFabc", "replace", "\uFFFD\uFFFDabc"), + (b"\x84bxy", "replace", "\uFFFDbxy"), + (b"\x8CBxy", "replace", "\uFFFDBxy"), ) def test_main(): diff --git a/Lib/test/test_codecencodings_tw.py b/Lib/test/test_codecencodings_tw.py --- a/Lib/test/test_codecencodings_tw.py +++ b/Lib/test/test_codecencodings_tw.py @@ -15,8 +15,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u8b10"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u8b10\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u8b10"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u8b10\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u8b10"), ) diff --git a/Lib/test/test_codecmaps_tw.py b/Lib/test/test_codecmaps_tw.py --- a/Lib/test/test_codecmaps_tw.py +++ b/Lib/test/test_codecmaps_tw.py @@ -23,6 +23,9 @@ (b'\xa2\xcc', '\u5341'), (b'\xa2\xce', '\u5345'), ] + codectests = ( + (b"\xFFxy", "replace", "\ufffdxy"), + ) def test_main(): support.run_unittest(__name__) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -219,6 +219,10 @@ Library ------- +- Issue #12016: Multibyte CJK decoders now resynchronize faster. They only + ignore the first byte of an invalid byte sequence. For example, + b'\xff\n'.decode('gb2312', 'replace') gives '\ufffd\n' instead of '\ufffd'. + - Issue #12459: time.sleep() now raises a ValueError if the sleep length is negative, instead of an infinite sleep on Windows or raising an IOError on Linux for example, to have the same behaviour on all platforms. diff --git a/Modules/cjkcodecs/_codecs_cn.c b/Modules/cjkcodecs/_codecs_cn.c --- a/Modules/cjkcodecs/_codecs_cn.c +++ b/Modules/cjkcodecs/_codecs_cn.c @@ -85,7 +85,7 @@ TRYMAP_DEC(gb2312, **outbuf, c ^ 0x80, IN2 ^ 0x80) { NEXT(2, 1) } - else return 2; + else return 1; } return 0; @@ -141,7 +141,7 @@ REQUIRE_INBUF(2) GBK_DECODE(c, IN2, **outbuf) - else return 2; + else return 1; NEXT(2, 1) } @@ -267,7 +267,7 @@ c3 = IN3; c4 = IN4; if (c < 0x81 || c3 < 0x81 || c4 < 0x30 || c4 > 0x39) - return 4; + return 1; c -= 0x81; c2 -= 0x30; c3 -= 0x81; c4 -= 0x30; @@ -292,12 +292,12 @@ continue; } } - return 4; + return 1; } GBK_DECODE(c, c2, **outbuf) else TRYMAP_DEC(gb18030ext, **outbuf, c, c2); - else return 2; + else return 1; NEXT(2, 1) } @@ -400,7 +400,7 @@ else if (c2 == '\n') ; /* line-continuation */ else - return 2; + return 1; NEXT(2, 0); continue; } @@ -419,7 +419,7 @@ NEXT(2, 1) } else - return 2; + return 1; } } diff --git a/Modules/cjkcodecs/_codecs_hk.c b/Modules/cjkcodecs/_codecs_hk.c --- a/Modules/cjkcodecs/_codecs_hk.c +++ b/Modules/cjkcodecs/_codecs_hk.c @@ -161,7 +161,7 @@ case 0x8864: WRITE2(0x00ca, 0x030c); break; case 0x88a3: WRITE2(0x00ea, 0x0304); break; case 0x88a5: WRITE2(0x00ea, 0x030c); break; - default: return 2; + default: return 1; } NEXT(2, 2) /* all decoded codepoints are pairs, above. */ diff --git a/Modules/cjkcodecs/_codecs_jp.c b/Modules/cjkcodecs/_codecs_jp.c --- a/Modules/cjkcodecs/_codecs_jp.c +++ b/Modules/cjkcodecs/_codecs_jp.c @@ -112,7 +112,7 @@ TRYMAP_DEC(cp932ext, **outbuf, c, c2); else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)){ if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) - return 2; + return 1; c = (c < 0xe0 ? c - 0x81 : c - 0xc1); c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); @@ -120,7 +120,7 @@ c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21; TRYMAP_DEC(jisx0208, **outbuf, c, c2); - else return 2; + else return 1; } else if (c >= 0xf0 && c <= 0xf9) { if ((c2 >= 0x40 && c2 <= 0x7e) || @@ -128,10 +128,10 @@ OUT1(0xe000 + 188 * (c - 0xf0) + (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41)) else - return 2; + return 1; } else - return 2; + return 1; NEXT(2, 1) } @@ -256,7 +256,7 @@ NEXT(2, 1) } else - return 2; + return 1; } else if (c == 0x8f) { unsigned char c2, c3; @@ -274,7 +274,7 @@ continue; } else TRYMAP_DEC(jisx0212, **outbuf, c2, c3) ; - else return 3; + else return 1; NEXT(3, 1) } else { @@ -300,7 +300,7 @@ NEXT(2, 2) continue; } - else return 2; + else return 1; NEXT(2, 1) } } @@ -388,7 +388,7 @@ NEXT(2, 1) } else - return 2; + return 1; } else if (c == 0x8f) { unsigned char c2, c3; @@ -401,7 +401,7 @@ NEXT(3, 1) } else - return 3; + return 1; } else { unsigned char c2; @@ -417,7 +417,7 @@ #endif TRYMAP_DEC(jisx0208, **outbuf, c ^ 0x80, c2 ^ 0x80) ; - else return 2; + else return 1; NEXT(2, 1) } } @@ -502,7 +502,7 @@ REQUIRE_INBUF(2) c2 = IN2; if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) - return 2; + return 1; c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1); c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); @@ -522,10 +522,10 @@ continue; } else - return 2; + return 1; } else - return 2; + return 1; NEXT(1, 1) /* JIS X 0201 */ } @@ -645,7 +645,7 @@ REQUIRE_INBUF(2) c2 = IN2; if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) - return 2; + return 1; c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1); c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); @@ -671,7 +671,7 @@ NEXT_OUT(2) } else - return 2; + return 1; NEXT_IN(2) } else { /* Plane 2 */ @@ -689,13 +689,13 @@ continue; } else - return 2; + return 1; NEXT(2, 1) } continue; } else - return 2; + return 1; NEXT(1, 1) /* JIS X 0201 */ } diff --git a/Modules/cjkcodecs/_codecs_kr.c b/Modules/cjkcodecs/_codecs_kr.c --- a/Modules/cjkcodecs/_codecs_kr.c +++ b/Modules/cjkcodecs/_codecs_kr.c @@ -123,7 +123,7 @@ if ((*inbuf)[2] != EUCKR_JAMO_FIRSTBYTE || (*inbuf)[4] != EUCKR_JAMO_FIRSTBYTE || (*inbuf)[6] != EUCKR_JAMO_FIRSTBYTE) - return 8; + return 1; c = (*inbuf)[3]; if (0xa1 <= c && c <= 0xbe) @@ -143,7 +143,7 @@ jong = NONE; if (cho == NONE || jung == NONE || jong == NONE) - return 8; + return 1; OUT1(0xac00 + cho*588 + jung*28 + jong); NEXT(8, 1) @@ -152,7 +152,7 @@ NEXT(2, 1) } else - return 2; + return 1; } return 0; @@ -208,7 +208,7 @@ REQUIRE_INBUF(2) TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80); else TRYMAP_DEC(cp949ext, **outbuf, c, IN2); - else return 2; + else return 1; NEXT(2, 1) } @@ -375,7 +375,7 @@ i_jong = johabidx_jongseong[c_jong]; if (i_cho == NONE || i_jung == NONE || i_jong == NONE) - return 2; + return 1; /* we don't use U+1100 hangul jamo yet. */ if (i_cho == FILL) { @@ -391,7 +391,7 @@ OUT1(0x3100 | johabjamo_jungseong[c_jung]) else - return 2; + return 1; } } else { if (i_jung == FILL) { @@ -399,7 +399,7 @@ OUT1(0x3100 | johabjamo_choseong[c_cho]) else - return 2; + return 1; } else OUT1(0xac00 + @@ -414,7 +414,7 @@ c2 < 0x31 || (c2 >= 0x80 && c2 < 0x91) || (c2 & 0x7f) == 0x7f || (c == 0xda && (c2 >= 0xa1 && c2 <= 0xd3))) - return 2; + return 1; else { unsigned char t1, t2; @@ -425,7 +425,7 @@ t2 = (t2 < 0x5e ? t2 : t2 - 0x5e) + 0x21; TRYMAP_DEC(ksx1001, **outbuf, t1, t2); - else return 2; + else return 1; NEXT(2, 1) } } diff --git a/Modules/cjkcodecs/_codecs_tw.c b/Modules/cjkcodecs/_codecs_tw.c --- a/Modules/cjkcodecs/_codecs_tw.c +++ b/Modules/cjkcodecs/_codecs_tw.c @@ -55,7 +55,7 @@ TRYMAP_DEC(big5, **outbuf, c, IN2) { NEXT(2, 1) } - else return 2; + else return 1; } return 0; @@ -109,7 +109,7 @@ TRYMAP_DEC(cp950ext, **outbuf, c, IN2); else TRYMAP_DEC(big5, **outbuf, c, IN2); - else return 2; + else return 1; NEXT(2, 1) } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 02:08:03 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Jul 2011 02:08:03 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogQ2xvc2UgIzEyNTAx?= =?utf8?q?=3A_Adjust_callable=28=29_warning=3A_callable=28=29_is_only_not_?= =?utf8?q?supported_in?= Message-ID: http://hg.python.org/cpython/rev/1f814faaf54d changeset: 71248:1f814faaf54d branch: 2.7 parent: 71241:b5ac5e25d506 user: Victor Stinner date: Fri Jul 08 02:07:45 2011 +0200 summary: Close #12501: Adjust callable() warning: callable() is only not supported in Python 3.1. callable() is again supported in Python 3.2. files: Lib/test/test_builtin.py | 1 + Misc/NEWS | 3 +++ Python/bltinmodule.c | 2 +- 3 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1683,6 +1683,7 @@ def _run_unittest(*args): with check_py3k_warnings( + (".+ not supported in 3.1", DeprecationWarning), (".+ not supported in 3.x", DeprecationWarning), (".+ is renamed to imp.reload", DeprecationWarning), ("classic int division", DeprecationWarning)): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #12501: Adjust callable() warning: callable() is only not supported in + Python 3.1. callable() is again supported in Python 3.2. + - Issue #9611, #9015: FileIO.read(), FileIO.readinto(), FileIO.write() and os.write() clamp the length to INT_MAX on Windows. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -224,7 +224,7 @@ static PyObject * builtin_callable(PyObject *self, PyObject *v) { - if (PyErr_WarnPy3k("callable() not supported in 3.x; " + if (PyErr_WarnPy3k("callable() not supported in 3.1; " "use isinstance(x, collections.Callable)", 1) < 0) return NULL; return PyBool_FromLong((long)PyCallable_Check(v)); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 02:27:17 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Jul 2011 02:27:17 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyNDIz?= =?utf8?q?=3A_Fix_os=2Eabort=28=29_documentation?= Message-ID: http://hg.python.org/cpython/rev/1ac21a715c5d changeset: 71249:1ac21a715c5d branch: 2.7 user: Victor Stinner date: Fri Jul 08 02:14:55 2011 +0200 summary: Issue #12423: Fix os.abort() documentation The Python signal handler for SIGABRT is not called on os.abort() (only if the signal is raised manually or sent by another process). Patch by Kamil Kisiel. files: Doc/ACKS.txt | 3 ++- Doc/library/os.rst | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -103,6 +103,7 @@ * Robert Kern * Jim Kerr * Jan Kim + * Kamil Kisiel * Greg Kochanski * Guido Kollerie * Peter A. Koren @@ -139,7 +140,7 @@ * Ross Moore * Sjoerd Mullender * Dale Nagata - * Michal Nowikowski + * Michal Nowikowski * Ng Pheng Siong * Koray Oner * Tomas Oppelstrup diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1666,8 +1666,9 @@ Generate a :const:`SIGABRT` signal to the current process. On Unix, the default behavior is to produce a core dump; on Windows, the process immediately returns - an exit code of ``3``. Be aware that programs which use :func:`signal.signal` - to register a handler for :const:`SIGABRT` will behave differently. + an exit code of ``3``. Be aware that calling this function will not call the + Python signal handler registered for :const:`SIGABRT` with + :func:`signal.signal`. Availability: Unix, Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 02:27:18 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Jul 2011 02:27:18 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDIz?= =?utf8?q?=3A_Fix_os=2Eabort=28=29_documentation?= Message-ID: http://hg.python.org/cpython/rev/4e83d8f6d496 changeset: 71250:4e83d8f6d496 branch: 3.2 parent: 71242:b58b0c5c7e96 user: Victor Stinner date: Fri Jul 08 02:26:39 2011 +0200 summary: Issue #12423: Fix os.abort() documentation The Python signal handler for SIGABRT is not called on os.abort() (only if the signal is raised manually or sent by another process). Patch by Kamil Kisiel. files: Doc/ACKS.txt | 3 ++- Doc/library/os.rst | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -105,6 +105,7 @@ * Robert Kern * Jim Kerr * Jan Kim + * Kamil Kisiel * Greg Kochanski * Guido Kollerie * Peter A. Koren @@ -142,7 +143,7 @@ * Ross Moore * Sjoerd Mullender * Dale Nagata - * Michal Nowikowski + * Michal Nowikowski * Ng Pheng Siong * Koray Oner * Tomas Oppelstrup diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1582,8 +1582,9 @@ Generate a :const:`SIGABRT` signal to the current process. On Unix, the default behavior is to produce a core dump; on Windows, the process immediately returns - an exit code of ``3``. Be aware that programs which use :func:`signal.signal` - to register a handler for :const:`SIGABRT` will behave differently. + an exit code of ``3``. Be aware that calling this function will not call the + Python signal handler registered for :const:`SIGABRT` with + :func:`signal.signal`. Availability: Unix, Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 02:27:18 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 08 Jul 2011 02:27:18 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiAobWVyZ2UgMy4yKSBJc3N1ZSAjMTI0MjM6IEZpeCBvcy5hYm9ydCgpIGRvY3Vt?= =?utf8?q?entation?= Message-ID: http://hg.python.org/cpython/rev/e3c115ba8dc0 changeset: 71251:e3c115ba8dc0 parent: 71247:16cbd84de848 parent: 71250:4e83d8f6d496 user: Victor Stinner date: Fri Jul 08 02:27:06 2011 +0200 summary: (merge 3.2) Issue #12423: Fix os.abort() documentation The Python signal handler for SIGABRT is not called on os.abort() (only if the signal is raised manually or sent by another process). Patch by Kamil Kisiel. files: Doc/ACKS.txt | 3 ++- Doc/library/os.rst | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -105,6 +105,7 @@ * Robert Kern * Jim Kerr * Jan Kim + * Kamil Kisiel * Greg Kochanski * Guido Kollerie * Peter A. Koren @@ -142,7 +143,7 @@ * Ross Moore * Sjoerd Mullender * Dale Nagata - * Michal Nowikowski + * Michal Nowikowski * Ng Pheng Siong * Koray Oner * Tomas Oppelstrup diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2088,8 +2088,9 @@ Generate a :const:`SIGABRT` signal to the current process. On Unix, the default behavior is to produce a core dump; on Windows, the process immediately returns - an exit code of ``3``. Be aware that programs which use :func:`signal.signal` - to register a handler for :const:`SIGABRT` will behave differently. + an exit code of ``3``. Be aware that calling this function will not call the + Python signal handler registered for :const:`SIGABRT` with + :func:`signal.signal`. Availability: Unix, Windows. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 8 05:08:47 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 08 Jul 2011 05:08:47 +0200 Subject: [Python-checkins] Daily reference leaks (e3c115ba8dc0): sum=300 Message-ID: results for e3c115ba8dc0 on branch "default" -------------------------------------------- test_concurrent_futures leaked [54, 0, -54] references, sum=0 test_packaging leaked [100, 100, 100] references, sum=300 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogKQ8FH2', '-x'] From python-checkins at python.org Fri Jul 8 16:28:29 2011 From: python-checkins at python.org (eric.araujo) Date: Fri, 08 Jul 2011 16:28:29 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Improve_reST_target?= Message-ID: http://hg.python.org/cpython/rev/5fea9b9d8b63 changeset: 71252:5fea9b9d8b63 user: ?ric Araujo date: Sat Jul 02 16:58:25 2011 +0200 summary: Improve reST target files: Doc/install/install.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/install/install.rst b/Doc/install/install.rst --- a/Doc/install/install.rst +++ b/Doc/install/install.rst @@ -4,7 +4,7 @@ Installing Python projects: overwiew ==================================== -.. _packaging_packaging-intro: +.. _packaging-install-intro: Introduction ============ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 16:28:30 2011 From: python-checkins at python.org (eric.araujo) Date: Fri, 08 Jul 2011 16:28:30 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Factor_out_code_used_by_pac?= =?utf8?q?kaging_commands_for_HTTP_requests_=28=2312169=29=2E?= Message-ID: http://hg.python.org/cpython/rev/c2785ed52ed4 changeset: 71253:c2785ed52ed4 user: ?ric Araujo date: Fri Jul 08 16:27:12 2011 +0200 summary: Factor out code used by packaging commands for HTTP requests (#12169). We now have one function to prepare multipart POST requests, and we use CRLF, as recommended by the HTTP spec (#10150). Initial patch by John Edmonds. files: Lib/packaging/command/register.py | 24 +---- Lib/packaging/command/upload.py | 50 +-------- Lib/packaging/command/upload_docs.py | 46 +-------- Lib/packaging/tests/test_command_register.py | 10 +- Lib/packaging/tests/test_command_upload_docs.py | 27 +----- Lib/packaging/tests/test_util.py | 26 +++++- Lib/packaging/util.py | 47 +++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 + 9 files changed, 96 insertions(+), 138 deletions(-) diff --git a/Lib/packaging/command/register.py b/Lib/packaging/command/register.py --- a/Lib/packaging/command/register.py +++ b/Lib/packaging/command/register.py @@ -10,7 +10,7 @@ from packaging import logger from packaging.util import (read_pypirc, generate_pypirc, DEFAULT_REPOSITORY, - DEFAULT_REALM, get_pypirc_path) + DEFAULT_REALM, get_pypirc_path, encode_multipart) from packaging.command.cmd import Command class register(Command): @@ -231,29 +231,11 @@ 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() + content_type, body = encode_multipart(data.items(), []) # build the Request headers = { - 'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary, + 'Content-type': content_type, 'Content-length': str(len(body)) } req = urllib.request.Request(self.repository, body, headers) diff --git a/Lib/packaging/command/upload.py b/Lib/packaging/command/upload.py --- a/Lib/packaging/command/upload.py +++ b/Lib/packaging/command/upload.py @@ -14,7 +14,7 @@ from packaging import logger from packaging.errors import PackagingOptionError from packaging.util import (spawn, read_pypirc, DEFAULT_REPOSITORY, - DEFAULT_REALM) + DEFAULT_REALM, encode_multipart) from packaging.command.cmd import Command @@ -131,54 +131,22 @@ 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() + files = [] + for key in ('content', 'gpg_signature'): + if key in data: + filename_, value = data.pop(key) + files.append((key, filename_, value)) - 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() + content_type, body = encode_multipart(data.items(), files) logger.info("Submitting %s to %s", filename, self.repository) # build the Request - headers = {'Content-type': - 'multipart/form-data; boundary=%s' % - boundary.decode('ascii'), + headers = {'Content-type': content_type, 'Content-length': str(len(body)), 'Authorization': auth} - request = Request(self.repository, data=body, - headers=headers) + request = Request(self.repository, body, headers) # send the data try: result = urlopen(request) diff --git a/Lib/packaging/command/upload_docs.py b/Lib/packaging/command/upload_docs.py --- a/Lib/packaging/command/upload_docs.py +++ b/Lib/packaging/command/upload_docs.py @@ -10,7 +10,8 @@ from io import BytesIO from packaging import logger -from packaging.util import read_pypirc, DEFAULT_REPOSITORY, DEFAULT_REALM +from packaging.util import (read_pypirc, DEFAULT_REPOSITORY, DEFAULT_REALM, + encode_multipart) from packaging.errors import PackagingFileError from packaging.command.cmd import Command @@ -28,49 +29,6 @@ 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" diff --git a/Lib/packaging/tests/test_command_register.py b/Lib/packaging/tests/test_command_register.py --- a/Lib/packaging/tests/test_command_register.py +++ b/Lib/packaging/tests/test_command_register.py @@ -152,7 +152,7 @@ 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) + self.assertIn(b'xxx', self.conn.reqs[1].data) def test_password_not_in_file(self): @@ -180,8 +180,8 @@ 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) + self.assertEqual(headers['Content-length'], '628') + self.assertIn(b'tarek', req.data) def test_password_reset(self): # this test runs choice 3 @@ -195,8 +195,8 @@ 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) + self.assertEqual(headers['Content-length'], '298') + self.assertIn(b'tarek', req.data) @unittest.skipUnless(DOCUTILS_SUPPORT, 'needs docutils') def test_strict(self): diff --git a/Lib/packaging/tests/test_command_upload_docs.py b/Lib/packaging/tests/test_command_upload_docs.py --- a/Lib/packaging/tests/test_command_upload_docs.py +++ b/Lib/packaging/tests/test_command_upload_docs.py @@ -9,8 +9,7 @@ _ssl = None from packaging.command import upload_docs as upload_docs_mod -from packaging.command.upload_docs import (upload_docs, zip_dir, - encode_multipart) +from packaging.command.upload_docs import upload_docs, zip_dir from packaging.dist import Distribution from packaging.errors import PackagingFileError, PackagingOptionError @@ -23,23 +22,6 @@ PyPIServerTestCase = object -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 @@ -108,13 +90,6 @@ 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() diff --git a/Lib/packaging/tests/test_util.py b/Lib/packaging/tests/test_util.py --- a/Lib/packaging/tests/test_util.py +++ b/Lib/packaging/tests/test_util.py @@ -19,7 +19,7 @@ get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages, spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob, RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging, - get_install_method, cfg_to_args) + get_install_method, cfg_to_args, encode_multipart) PYPIRC = """\ @@ -54,6 +54,23 @@ password:xxx """ +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'', +] + class FakePopen: test_class = None @@ -525,6 +542,13 @@ self.assertEqual(args['scripts'], dist.scripts) self.assertEqual(args['py_modules'], dist.py_modules) + 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')) + class GlobTestCaseBase(support.TempdirManager, support.LoggingCatcher, diff --git a/Lib/packaging/util.py b/Lib/packaging/util.py --- a/Lib/packaging/util.py +++ b/Lib/packaging/util.py @@ -1487,3 +1487,50 @@ _path_created.add(abs_head) return created_dirs + + +def encode_multipart(fields, files, boundary=None): + """Prepare a multipart HTTP request. + + *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. + """ + # Taken from + # http://code.activestate.com/recipes/146306-http-client-to-post-using-multipartform-data/ + + if boundary is None: + boundary = b'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + elif not isinstance(boundary, bytes): + raise TypeError('boundary must be bytes, not %r' % type(boundary)) + + l = [] + for key, values in fields: + # handle multiple entries for the same name + if not isinstance(values, (tuple, list)): + values=[values] + + for value in values: + 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 diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -263,6 +263,7 @@ Walter D?rwald Hans Eckardt Rodolpho Eckhardt +John Edmonds Grant Edwards John Ehresman Eric Eisner diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -219,6 +219,9 @@ Library ------- +- Issues #12169 and #10510: Factor out code used by various packaging commands + to make HTTP POST requests, and make sure it uses CRLF. + - Issue #12016: Multibyte CJK decoders now resynchronize faster. They only ignore the first byte of an invalid byte sequence. For example, b'\xff\n'.decode('gb2312', 'replace') gives '\ufffd\n' instead of '\ufffd'. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 17:22:39 2011 From: python-checkins at python.org (eric.araujo) Date: Fri, 08 Jul 2011 17:22:39 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_file_handles_in_a_tim?= =?utf8?q?ely_manner_in_packaging=2Edatabase_=28=2312504=29=2E?= Message-ID: http://hg.python.org/cpython/rev/2b9a0a091566 changeset: 71254:2b9a0a091566 user: ?ric Araujo date: Fri Jul 08 17:22:19 2011 +0200 summary: Close file handles in a timely manner in packaging.database (#12504). This fixes a bug with the remove (uninstall) feature on Windows. Patch by Thomas Holmes. files: Lib/packaging/database.py | 12 +++++++----- Lib/packaging/tests/test_uninstall.py | 2 -- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Lib/packaging/database.py b/Lib/packaging/database.py --- a/Lib/packaging/database.py +++ b/Lib/packaging/database.py @@ -158,17 +158,18 @@ self.name, self.version, self.path) def _get_records(self, local=False): + results = [] with self.get_distinfo_file('RECORD') as record: record_reader = csv.reader(record, delimiter=',', lineterminator='\n') - # XXX needs an explaining comment for row in record_reader: - path, checksum, size = (row[:] + - [None for i in range(len(row), 3)]) + missing = [None for i in range(len(row), 3)] + path, checksum, size = row + missing if local: path = path.replace('/', os.sep) path = os.path.join(sys.prefix, path) - yield path, checksum, size + results.append((path, checksum, size)) + return results def get_resource_path(self, relative_path): with self.get_distinfo_file('RESOURCES') as resources_file: @@ -197,7 +198,8 @@ :type local: boolean :returns: iterator of (path, md5, size) """ - return self._get_records(local) + for result in self._get_records(local): + yield result def uses(self, path): """ diff --git a/Lib/packaging/tests/test_uninstall.py b/Lib/packaging/tests/test_uninstall.py --- a/Lib/packaging/tests/test_uninstall.py +++ b/Lib/packaging/tests/test_uninstall.py @@ -93,7 +93,6 @@ self.assertRaises(PackagingError, remove, 'Foo', paths=[self.root_dir]) - @unittest.skipIf(sys.platform == 'win32', 'deactivated for now') def test_uninstall(self): dist, install_lib = self.install_dist() self.assertIsFile(install_lib, 'foo', '__init__.py') @@ -103,7 +102,6 @@ self.assertIsNotFile(install_lib, 'foo', 'sub', '__init__.py') self.assertIsNotFile(install_lib, 'Foo-0.1.dist-info', 'RECORD') - @unittest.skipIf(sys.platform == 'win32', 'deactivated for now') def test_remove_issue(self): # makes sure if there are OSErrors (like permission denied) # remove() stops and display a clean error diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -419,6 +419,7 @@ Gerrit Holl Shane Holloway Rune Holm +Thomas Holmes Philip Homburg Naofumi Honda Jeffrey Honig diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -219,6 +219,9 @@ Library ------- +- Issue #12504: Close file handles in a timely manner in packaging.database. + This fixes a bug with the remove (uninstall) feature on Windows. + - Issues #12169 and #10510: Factor out code used by various packaging commands to make HTTP POST requests, and make sure it uses CRLF. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 18:50:17 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 18:50:17 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyNDQw?= =?utf8?q?=3A_When_testing_whether_some_bits_in_SSLContext=2Eoptions_can_b?= =?utf8?q?e?= Message-ID: http://hg.python.org/cpython/rev/52ed0c6bb461 changeset: 71255:52ed0c6bb461 branch: 3.2 parent: 71250:4e83d8f6d496 user: Antoine Pitrou date: Fri Jul 08 18:47:06 2011 +0200 summary: Issue #12440: When testing whether some bits in SSLContext.options can be reset, check the version of the OpenSSL headers Python was compiled against, rather than the runtime version of the OpenSSL library. files: Lib/ssl.py | 2 + Lib/test/test_ssl.py | 2 +- Misc/NEWS | 4 +++ Modules/_ssl.c | 34 +++++++++++++++++++++++-------- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -77,6 +77,8 @@ ) from _ssl import HAS_SNI from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 +from _ssl import _OPENSSL_API_VERSION + _PROTOCOL_NAMES = { PROTOCOL_TLSv1: "TLSv1", PROTOCOL_SSLv23: "SSLv23", 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 @@ -60,7 +60,7 @@ def can_clear_options(): # 0.9.8m or higher - return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 13, 15) + return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15) def no_sslv2_implies_sslv3_hello(): # 0.9.7h or higher diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,10 @@ Tests ----- +- Issue #12440: When testing whether some bits in SSLContext.options can be + reset, check the version of the OpenSSL headers Python was compiled against, + rather than the runtime version of the OpenSSL library. + - Issue #12497: Install test/data to prevent failures of the various codecmaps tests. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2037,6 +2037,24 @@ NULL }; + +static void +parse_openssl_version(unsigned long libver, + unsigned int *major, unsigned int *minor, + unsigned int *fix, unsigned int *patch, + unsigned int *status) +{ + *status = libver & 0xF; + libver >>= 4; + *patch = libver & 0xFF; + libver >>= 8; + *fix = libver & 0xFF; + libver >>= 8; + *minor = libver & 0xFF; + libver >>= 8; + *major = libver & 0xFF; +} + PyMODINIT_FUNC PyInit__ssl(void) { @@ -2149,15 +2167,7 @@ return NULL; if (PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) return NULL; - status = libver & 0xF; - libver >>= 4; - patch = libver & 0xFF; - libver >>= 8; - fix = libver & 0xFF; - libver >>= 8; - minor = libver & 0xFF; - libver >>= 8; - major = libver & 0xFF; + parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); r = Py_BuildValue("IIIII", major, minor, fix, patch, status); if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) return NULL; @@ -2165,5 +2175,11 @@ if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) return NULL; + libver = OPENSSL_VERSION_NUMBER; + parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); + r = Py_BuildValue("IIIII", major, minor, fix, patch, status); + if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) + return NULL; + return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 18:50:17 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 18:50:17 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2312440=3A_When_testing_whether_some_bits_in_SSLConte?= =?utf8?q?xt=2Eoptions_can_be?= Message-ID: http://hg.python.org/cpython/rev/4120cd8a86f4 changeset: 71256:4120cd8a86f4 parent: 71254:2b9a0a091566 parent: 71255:52ed0c6bb461 user: Antoine Pitrou date: Fri Jul 08 18:49:07 2011 +0200 summary: Issue #12440: When testing whether some bits in SSLContext.options can be reset, check the version of the OpenSSL headers Python was compiled against, rather than the runtime version of the OpenSSL library. files: Lib/ssl.py | 2 + Lib/test/test_ssl.py | 2 +- Misc/NEWS | 4 +++ Modules/_ssl.c | 34 +++++++++++++++++++++++-------- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -78,6 +78,8 @@ from _ssl import HAS_SNI from _ssl import (PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1) +from _ssl import _OPENSSL_API_VERSION + _PROTOCOL_NAMES = { PROTOCOL_TLSv1: "TLSv1", PROTOCOL_SSLv23: "SSLv23", 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 @@ -60,7 +60,7 @@ def can_clear_options(): # 0.9.8m or higher - return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 13, 15) + return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15) def no_sslv2_implies_sslv3_hello(): # 0.9.7h or higher diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1004,6 +1004,10 @@ Tests ----- +- Issue #12440: When testing whether some bits in SSLContext.options can be + reset, check the version of the OpenSSL headers Python was compiled against, + rather than the runtime version of the OpenSSL library. + - Issue #11512: Add a test suite for the cgitb module. Patch by Robbie Clemons. - Issue #12497: Install test/data to prevent failures of the various codecmaps diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2101,6 +2101,24 @@ NULL }; + +static void +parse_openssl_version(unsigned long libver, + unsigned int *major, unsigned int *minor, + unsigned int *fix, unsigned int *patch, + unsigned int *status) +{ + *status = libver & 0xF; + libver >>= 4; + *patch = libver & 0xFF; + libver >>= 8; + *fix = libver & 0xFF; + libver >>= 8; + *minor = libver & 0xFF; + libver >>= 8; + *major = libver & 0xFF; +} + PyMODINIT_FUNC PyInit__ssl(void) { @@ -2213,15 +2231,7 @@ return NULL; if (PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) return NULL; - status = libver & 0xF; - libver >>= 4; - patch = libver & 0xFF; - libver >>= 8; - fix = libver & 0xFF; - libver >>= 8; - minor = libver & 0xFF; - libver >>= 8; - major = libver & 0xFF; + parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); r = Py_BuildValue("IIIII", major, minor, fix, patch, status); if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) return NULL; @@ -2229,5 +2239,11 @@ if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) return NULL; + libver = OPENSSL_VERSION_NUMBER; + parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); + r = Py_BuildValue("IIIII", major, minor, fix, patch, status); + if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) + return NULL; + return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 19:15:15 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 19:15:15 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Avoid_failing_i?= =?utf8?q?n_test=5Furllibnet=2Etest=5Fbad=5Faddress_when_some_overzealous?= Message-ID: http://hg.python.org/cpython/rev/3eaf019aa017 changeset: 71257:3eaf019aa017 branch: 2.7 parent: 71249:1ac21a715c5d user: Antoine Pitrou date: Fri Jul 08 19:14:19 2011 +0200 summary: Avoid failing in test_urllibnet.test_bad_address when some overzealous DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test is now skipped instead. files: Lib/test/test_urllibnet.py | 8 ++++++++ Misc/NEWS | 4 ++++ 2 files changed, 12 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py --- a/Lib/test/test_urllibnet.py +++ b/Lib/test/test_urllibnet.py @@ -131,6 +131,14 @@ def test_bad_address(self): # Make sure proper exception is raised when connecting to a bogus # address. + bogus_domain = "sadflkjsasf.i.nvali.d" + try: + socket.gethostbyname(bogus_domain) + except socket.gaierror: + pass + else: + # This happens with some overzealous DNS providers such as OpenDNS + self.skipTest("%r should not resolve for test to work" % bogus_domain) self.assertRaises(IOError, # SF patch 809915: In Sep 2003, VeriSign started # highjacking invalid .com and .net addresses to diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,10 @@ Tests ----- +- Avoid failing in test_urllibnet.test_bad_address when some overzealous + DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test + is now skipped instead. + - Issue #8716: Avoid crashes caused by Aqua Tk on OSX when attempting to run test_tk or test_ttk_guionly under a username that is not currently logged in to the console windowserver (as may be the case under buildbot or ssh). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 19:23:27 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 19:23:27 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Avoid_failing_i?= =?utf8?q?n_test=5Furllibnet=2Etest=5Fbad=5Faddress_when_some_overzealous?= Message-ID: http://hg.python.org/cpython/rev/6adab7448272 changeset: 71258:6adab7448272 branch: 3.2 parent: 71255:52ed0c6bb461 user: Antoine Pitrou date: Fri Jul 08 19:19:57 2011 +0200 summary: Avoid failing in test_urllibnet.test_bad_address when some overzealous DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test is now skipped instead. files: Lib/test/test_urllibnet.py | 8 ++++++++ Misc/NEWS | 4 ++++ 2 files changed, 12 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py --- a/Lib/test/test_urllibnet.py +++ b/Lib/test/test_urllibnet.py @@ -113,6 +113,14 @@ def test_bad_address(self): # Make sure proper exception is raised when connecting to a bogus # address. + bogus_domain = "sadflkjsasf.i.nvali.d" + try: + socket.gethostbyname(bogus_domain) + except socket.gaierror: + pass + else: + # This happens with some overzealous DNS providers such as OpenDNS + self.skipTest("%r should not resolve for test to work" % bogus_domain) self.assertRaises(IOError, # SF patch 809915: In Sep 2003, VeriSign started # highjacking invalid .com and .net addresses to diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,10 @@ Tests ----- +- Avoid failing in test_urllibnet.test_bad_address when some overzealous + DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test + is now skipped instead. + - Issue #12440: When testing whether some bits in SSLContext.options can be reset, check the version of the OpenSSL headers Python was compiled against, rather than the runtime version of the OpenSSL library. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 19:23:28 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 19:23:28 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Avoid_failing_in_test=5Furllibnet=2Etest=5Fbad=5Faddress_whe?= =?utf8?q?n_some_overzealous?= Message-ID: http://hg.python.org/cpython/rev/99d20a3e3c29 changeset: 71259:99d20a3e3c29 parent: 71256:4120cd8a86f4 parent: 71258:6adab7448272 user: Antoine Pitrou date: Fri Jul 08 19:22:31 2011 +0200 summary: Avoid failing in test_urllibnet.test_bad_address when some overzealous DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test is now skipped instead. files: Lib/test/test_urllibnet.py | 8 ++++++++ Misc/NEWS | 4 ++++ 2 files changed, 12 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py --- a/Lib/test/test_urllibnet.py +++ b/Lib/test/test_urllibnet.py @@ -113,6 +113,14 @@ def test_bad_address(self): # Make sure proper exception is raised when connecting to a bogus # address. + bogus_domain = "sadflkjsasf.i.nvali.d" + try: + socket.gethostbyname(bogus_domain) + except socket.gaierror: + pass + else: + # This happens with some overzealous DNS providers such as OpenDNS + self.skipTest("%r should not resolve for test to work" % bogus_domain) self.assertRaises(IOError, # SF patch 809915: In Sep 2003, VeriSign started # highjacking invalid .com and .net addresses to diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1004,6 +1004,10 @@ Tests ----- +- Avoid failing in test_urllibnet.test_bad_address when some overzealous + DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test + is now skipped instead. + - Issue #12440: When testing whether some bits in SSLContext.options can be reset, check the version of the OpenSSL headers Python was compiled against, rather than the runtime version of the OpenSSL library. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 19:41:11 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 19:41:11 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Avoid_failing_i?= =?utf8?q?n_test=5Frobotparser_when_mueblesmoraleda=2Ecom_is_flaky_and?= Message-ID: http://hg.python.org/cpython/rev/e6e37f1e29ca changeset: 71260:e6e37f1e29ca branch: 2.7 parent: 71257:3eaf019aa017 user: Antoine Pitrou date: Fri Jul 08 19:40:15 2011 +0200 summary: Avoid failing in test_robotparser when mueblesmoraleda.com is flaky and an overzealous DNS service (e.g. OpenDNS) redirects to a placeholder Web site. files: Lib/test/test_robotparser.py | 17 ++++++++++++++++- Misc/NEWS | 4 ++++ 2 files changed, 20 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py --- a/Lib/test/test_robotparser.py +++ b/Lib/test/test_robotparser.py @@ -1,5 +1,6 @@ import unittest, StringIO, robotparser from test import test_support +from urllib2 import urlopen, HTTPError class RobotTestCase(unittest.TestCase): def __init__(self, index, parser, url, good, agent): @@ -234,13 +235,27 @@ test_support.requires('network') with test_support.transient_internet('mueblesmoraleda.com'): url = 'http://mueblesmoraleda.com' + robots_url = url + "/robots.txt" + # First check the URL is usable for our purposes, since the + # test site is a bit flaky. + try: + urlopen(robots_url) + except HTTPError as e: + if e.code not in {401, 403}: + self.skipTest( + "%r should return a 401 or 403 HTTP error, not %r" + % (robots_url, e.code)) + else: + self.skipTest( + "%r should return a 401 or 403 HTTP error, not succeed" + % (robots_url)) parser = robotparser.RobotFileParser() parser.set_url(url) try: parser.read() except IOError: self.skipTest('%s is unavailable' % url) - self.assertEqual(parser.can_fetch("*", url+"/robots.txt"), False) + self.assertEqual(parser.can_fetch("*", robots_url), False) def testPythonOrg(self): test_support.requires('network') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,10 @@ Tests ----- +- Avoid failing in test_robotparser when mueblesmoraleda.com is flaky and + an overzealous DNS service (e.g. OpenDNS) redirects to a placeholder + Web site. + - Avoid failing in test_urllibnet.test_bad_address when some overzealous DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test is now skipped instead. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 19:45:51 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 19:45:51 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Avoid_failing_i?= =?utf8?q?n_test=5Frobotparser_when_mueblesmoraleda=2Ecom_is_flaky_and?= Message-ID: http://hg.python.org/cpython/rev/6e72490bbff6 changeset: 71261:6e72490bbff6 branch: 3.2 parent: 71258:6adab7448272 user: Antoine Pitrou date: Fri Jul 08 19:43:51 2011 +0200 summary: Avoid failing in test_robotparser when mueblesmoraleda.com is flaky and an overzealous DNS service (e.g. OpenDNS) redirects to a placeholder Web site. files: Lib/test/test_robotparser.py | 19 +++++++++++++++++-- Misc/NEWS | 4 ++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py --- a/Lib/test/test_robotparser.py +++ b/Lib/test/test_robotparser.py @@ -1,7 +1,8 @@ import io import unittest import urllib.robotparser -from urllib.error import URLError +from urllib.error import URLError, HTTPError +from urllib.request import urlopen from test import support class RobotTestCase(unittest.TestCase): @@ -237,13 +238,27 @@ support.requires('network') with support.transient_internet('mueblesmoraleda.com'): url = 'http://mueblesmoraleda.com' + robots_url = url + "/robots.txt" + # First check the URL is usable for our purposes, since the + # test site is a bit flaky. + try: + urlopen(robots_url) + except HTTPError as e: + if e.code not in {401, 403}: + self.skipTest( + "%r should return a 401 or 403 HTTP error, not %r" + % (robots_url, e.code)) + else: + self.skipTest( + "%r should return a 401 or 403 HTTP error, not succeed" + % (robots_url)) parser = urllib.robotparser.RobotFileParser() parser.set_url(url) try: parser.read() except URLError: self.skipTest('%s is unavailable' % url) - self.assertEqual(parser.can_fetch("*", url+"/robots.txt"), False) + self.assertEqual(parser.can_fetch("*", robots_url), False) def testPythonOrg(self): support.requires('network') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,10 @@ Tests ----- +- Avoid failing in test_robotparser when mueblesmoraleda.com is flaky and + an overzealous DNS service (e.g. OpenDNS) redirects to a placeholder + Web site. + - Avoid failing in test_urllibnet.test_bad_address when some overzealous DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test is now skipped instead. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 19:45:52 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 19:45:52 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Avoid_failing_in_test=5Frobotparser_when_mueblesmoraleda=2Ec?= =?utf8?q?om_is_flaky_and?= Message-ID: http://hg.python.org/cpython/rev/71fed8437db1 changeset: 71262:71fed8437db1 parent: 71259:99d20a3e3c29 parent: 71261:6e72490bbff6 user: Antoine Pitrou date: Fri Jul 08 19:44:55 2011 +0200 summary: Avoid failing in test_robotparser when mueblesmoraleda.com is flaky and an overzealous DNS service (e.g. OpenDNS) redirects to a placeholder Web site. files: Lib/test/test_robotparser.py | 19 +++++++++++++++++-- Misc/NEWS | 4 ++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py --- a/Lib/test/test_robotparser.py +++ b/Lib/test/test_robotparser.py @@ -1,7 +1,8 @@ import io import unittest import urllib.robotparser -from urllib.error import URLError +from urllib.error import URLError, HTTPError +from urllib.request import urlopen from test import support class RobotTestCase(unittest.TestCase): @@ -237,13 +238,27 @@ support.requires('network') with support.transient_internet('mueblesmoraleda.com'): url = 'http://mueblesmoraleda.com' + robots_url = url + "/robots.txt" + # First check the URL is usable for our purposes, since the + # test site is a bit flaky. + try: + urlopen(robots_url) + except HTTPError as e: + if e.code not in {401, 403}: + self.skipTest( + "%r should return a 401 or 403 HTTP error, not %r" + % (robots_url, e.code)) + else: + self.skipTest( + "%r should return a 401 or 403 HTTP error, not succeed" + % (robots_url)) parser = urllib.robotparser.RobotFileParser() parser.set_url(url) try: parser.read() except URLError: self.skipTest('%s is unavailable' % url) - self.assertEqual(parser.can_fetch("*", url+"/robots.txt"), False) + self.assertEqual(parser.can_fetch("*", robots_url), False) def testPythonOrg(self): support.requires('network') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1004,6 +1004,10 @@ Tests ----- +- Avoid failing in test_robotparser when mueblesmoraleda.com is flaky and + an overzealous DNS service (e.g. OpenDNS) redirects to a placeholder + Web site. + - Avoid failing in test_urllibnet.test_bad_address when some overzealous DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test is now skipped instead. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 20:34:31 2011 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 08 Jul 2011 20:34:31 +0200 Subject: [Python-checkins] =?utf8?q?release=3A_normalize_the_version_to_al?= =?utf8?q?ways_have_patch_level?= Message-ID: http://hg.python.org/release/rev/ccd9861ad360 changeset: 58:ccd9861ad360 user: Benjamin Peterson date: Fri Jul 08 13:38:52 2011 -0500 summary: normalize the version to always have patch level files: release.py | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -344,13 +344,16 @@ for i, thing in enumerate(data): if thing is None: data[i] = 0 - self.text = tag_name - self.next_text = tag_name self.major = int(data[0]) self.minor = int(data[1]) self.patch = int(data[2]) self.level = data[3] self.serial = int(data[4]) + # This has the effect of normalizing the version. + self.text = "{}.{}.{}".format(self.major, self.minor, self.patch) + if self.level != "f": + self.text += self.level + str(self.serial) + self.next_text = tag_name self.basic_version = '%s.%s' % (self.major, self.minor) def __str__(self): -- Repository URL: http://hg.python.org/release From python-checkins at python.org Fri Jul 8 20:35:31 2011 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 08 Jul 2011 20:35:31 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_add_patchlevel_to_version_s?= =?utf8?q?tring?= Message-ID: http://hg.python.org/cpython/rev/2ebcbdca0dee changeset: 71263:2ebcbdca0dee parent: 71244:71a1f53c8203 user: Benjamin Peterson date: Fri Jul 08 13:39:35 2011 -0500 summary: add patchlevel to version string files: Include/patchlevel.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.3a0" +#define PY_VERSION "3.3.0a0" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 20:35:32 2011 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 08 Jul 2011 20:35:32 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/1ca24391c8b1 changeset: 71264:1ca24391c8b1 parent: 71263:2ebcbdca0dee parent: 71262:71fed8437db1 user: Benjamin Peterson date: Fri Jul 08 13:39:56 2011 -0500 summary: merge heads files: Doc/ACKS.txt | 3 +- Doc/install/install.rst | 2 +- Doc/library/os.rst | 5 +- Doc/whatsnew/3.3.rst | 23 ++ Lib/packaging/command/register.py | 24 +-- Lib/packaging/command/upload.py | 50 +---- Lib/packaging/command/upload_docs.py | 46 +---- Lib/packaging/database.py | 12 +- Lib/packaging/install.py | 12 +- Lib/packaging/tests/test_command_register.py | 10 +- Lib/packaging/tests/test_command_upload_docs.py | 27 +-- Lib/packaging/tests/test_uninstall.py | 2 - Lib/packaging/tests/test_util.py | 26 ++- Lib/packaging/util.py | 47 ++++ Lib/ssl.py | 2 + Lib/test/test_codecencodings_cn.py | 21 +- Lib/test/test_codecencodings_hk.py | 4 +- Lib/test/test_codecencodings_jp.py | 96 ++++++--- Lib/test/test_codecencodings_kr.py | 25 +- Lib/test/test_codecencodings_tw.py | 4 +- Lib/test/test_codecmaps_tw.py | 3 + Lib/test/test_robotparser.py | 19 +- Lib/test/test_ssl.py | 2 +- Lib/test/test_urllibnet.py | 8 + Misc/ACKS | 2 + Misc/NEWS | 22 ++ Modules/_ssl.c | 34 ++- Modules/cjkcodecs/_codecs_cn.c | 14 +- Modules/cjkcodecs/_codecs_hk.c | 2 +- Modules/cjkcodecs/_codecs_jp.c | 34 +- Modules/cjkcodecs/_codecs_kr.c | 18 +- Modules/cjkcodecs/_codecs_tw.c | 4 +- Modules/md5module.c | 2 +- Modules/sha1module.c | 2 +- 34 files changed, 344 insertions(+), 263 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -105,6 +105,7 @@ * Robert Kern * Jim Kerr * Jan Kim + * Kamil Kisiel * Greg Kochanski * Guido Kollerie * Peter A. Koren @@ -142,7 +143,7 @@ * Ross Moore * Sjoerd Mullender * Dale Nagata - * Michal Nowikowski + * Michal Nowikowski * Ng Pheng Siong * Koray Oner * Tomas Oppelstrup diff --git a/Doc/install/install.rst b/Doc/install/install.rst --- a/Doc/install/install.rst +++ b/Doc/install/install.rst @@ -4,7 +4,7 @@ Installing Python projects: overwiew ==================================== -.. _packaging_packaging-intro: +.. _packaging-install-intro: Introduction ============ diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2088,8 +2088,9 @@ Generate a :const:`SIGABRT` signal to the current process. On Unix, the default behavior is to produce a core dump; on Windows, the process immediately returns - an exit code of ``3``. Be aware that programs which use :func:`signal.signal` - to register a handler for :const:`SIGABRT` will behave differently. + an exit code of ``3``. Be aware that calling this function will not call the + Python signal handler registered for :const:`SIGABRT` with + :func:`signal.signal`. Availability: Unix, Windows. 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 @@ -68,6 +68,29 @@ * Stub +codecs +------ + +Multibyte CJK decoders now resynchronize faster. They only ignore the first +byte of an invalid byte sequence. For example, b'\xff\n'.decode('gb2312', +'replace') gives '?\n' instead of '?'. + +(http://bugs.python.org/issue12016) + +Don't reset incremental encoders of CJK codecs at each call to their encode() +method anymore. For example: :: + + $ ./python -q + >>> import codecs + >>> encoder = codecs.getincrementalencoder('hz')('strict') + >>> b''.join(encoder.encode(x) for x in '\u52ff\u65bd\u65bc\u4eba\u3002 Bye.') + b'~{NpJ)l6HK!#~} Bye.' + +This example gives b'~{Np~}~{J)~}~{l6~}~{HK~}~{!#~} Bye.' with older Python +versions. + +(http://bugs.python.org/issue12100) + faulthandler ------------ diff --git a/Lib/packaging/command/register.py b/Lib/packaging/command/register.py --- a/Lib/packaging/command/register.py +++ b/Lib/packaging/command/register.py @@ -10,7 +10,7 @@ from packaging import logger from packaging.util import (read_pypirc, generate_pypirc, DEFAULT_REPOSITORY, - DEFAULT_REALM, get_pypirc_path) + DEFAULT_REALM, get_pypirc_path, encode_multipart) from packaging.command.cmd import Command class register(Command): @@ -231,29 +231,11 @@ 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() + content_type, body = encode_multipart(data.items(), []) # build the Request headers = { - 'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary, + 'Content-type': content_type, 'Content-length': str(len(body)) } req = urllib.request.Request(self.repository, body, headers) diff --git a/Lib/packaging/command/upload.py b/Lib/packaging/command/upload.py --- a/Lib/packaging/command/upload.py +++ b/Lib/packaging/command/upload.py @@ -14,7 +14,7 @@ from packaging import logger from packaging.errors import PackagingOptionError from packaging.util import (spawn, read_pypirc, DEFAULT_REPOSITORY, - DEFAULT_REALM) + DEFAULT_REALM, encode_multipart) from packaging.command.cmd import Command @@ -131,54 +131,22 @@ 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() + files = [] + for key in ('content', 'gpg_signature'): + if key in data: + filename_, value = data.pop(key) + files.append((key, filename_, value)) - 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() + content_type, body = encode_multipart(data.items(), files) logger.info("Submitting %s to %s", filename, self.repository) # build the Request - headers = {'Content-type': - 'multipart/form-data; boundary=%s' % - boundary.decode('ascii'), + headers = {'Content-type': content_type, 'Content-length': str(len(body)), 'Authorization': auth} - request = Request(self.repository, data=body, - headers=headers) + request = Request(self.repository, body, headers) # send the data try: result = urlopen(request) diff --git a/Lib/packaging/command/upload_docs.py b/Lib/packaging/command/upload_docs.py --- a/Lib/packaging/command/upload_docs.py +++ b/Lib/packaging/command/upload_docs.py @@ -10,7 +10,8 @@ from io import BytesIO from packaging import logger -from packaging.util import read_pypirc, DEFAULT_REPOSITORY, DEFAULT_REALM +from packaging.util import (read_pypirc, DEFAULT_REPOSITORY, DEFAULT_REALM, + encode_multipart) from packaging.errors import PackagingFileError from packaging.command.cmd import Command @@ -28,49 +29,6 @@ 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" diff --git a/Lib/packaging/database.py b/Lib/packaging/database.py --- a/Lib/packaging/database.py +++ b/Lib/packaging/database.py @@ -158,17 +158,18 @@ self.name, self.version, self.path) def _get_records(self, local=False): + results = [] with self.get_distinfo_file('RECORD') as record: record_reader = csv.reader(record, delimiter=',', lineterminator='\n') - # XXX needs an explaining comment for row in record_reader: - path, checksum, size = (row[:] + - [None for i in range(len(row), 3)]) + missing = [None for i in range(len(row), 3)] + path, checksum, size = row + missing if local: path = path.replace('/', os.sep) path = os.path.join(sys.prefix, path) - yield path, checksum, size + results.append((path, checksum, size)) + return results def get_resource_path(self, relative_path): with self.get_distinfo_file('RESOURCES') as resources_file: @@ -197,7 +198,8 @@ :type local: boolean :returns: iterator of (path, md5, size) """ - return self._get_records(local) + for result in self._get_records(local): + yield result def uses(self, path): """ diff --git a/Lib/packaging/install.py b/Lib/packaging/install.py --- a/Lib/packaging/install.py +++ b/Lib/packaging/install.py @@ -42,10 +42,7 @@ :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: filename = os.path.split(old)[-1] @@ -126,8 +123,11 @@ elif _is_archive_file(path): logger.info('Installing from archive: %s', path) _unpacked_dir = tempfile.mkdtemp() - shutil.unpack_archive(path, _unpacked_dir) - return _run_install_from_archive(_unpacked_dir) + try: + shutil.unpack_archive(path, _unpacked_dir) + return _run_install_from_archive(_unpacked_dir) + finally: + shutil.rmtree(_unpacked_dir) else: logger.warning('No projects to install.') return False @@ -179,8 +179,6 @@ :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: diff --git a/Lib/packaging/tests/test_command_register.py b/Lib/packaging/tests/test_command_register.py --- a/Lib/packaging/tests/test_command_register.py +++ b/Lib/packaging/tests/test_command_register.py @@ -152,7 +152,7 @@ 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) + self.assertIn(b'xxx', self.conn.reqs[1].data) def test_password_not_in_file(self): @@ -180,8 +180,8 @@ 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) + self.assertEqual(headers['Content-length'], '628') + self.assertIn(b'tarek', req.data) def test_password_reset(self): # this test runs choice 3 @@ -195,8 +195,8 @@ 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) + self.assertEqual(headers['Content-length'], '298') + self.assertIn(b'tarek', req.data) @unittest.skipUnless(DOCUTILS_SUPPORT, 'needs docutils') def test_strict(self): diff --git a/Lib/packaging/tests/test_command_upload_docs.py b/Lib/packaging/tests/test_command_upload_docs.py --- a/Lib/packaging/tests/test_command_upload_docs.py +++ b/Lib/packaging/tests/test_command_upload_docs.py @@ -9,8 +9,7 @@ _ssl = None from packaging.command import upload_docs as upload_docs_mod -from packaging.command.upload_docs import (upload_docs, zip_dir, - encode_multipart) +from packaging.command.upload_docs import upload_docs, zip_dir from packaging.dist import Distribution from packaging.errors import PackagingFileError, PackagingOptionError @@ -23,23 +22,6 @@ PyPIServerTestCase = object -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 @@ -108,13 +90,6 @@ 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() diff --git a/Lib/packaging/tests/test_uninstall.py b/Lib/packaging/tests/test_uninstall.py --- a/Lib/packaging/tests/test_uninstall.py +++ b/Lib/packaging/tests/test_uninstall.py @@ -93,7 +93,6 @@ self.assertRaises(PackagingError, remove, 'Foo', paths=[self.root_dir]) - @unittest.skipIf(sys.platform == 'win32', 'deactivated for now') def test_uninstall(self): dist, install_lib = self.install_dist() self.assertIsFile(install_lib, 'foo', '__init__.py') @@ -103,7 +102,6 @@ self.assertIsNotFile(install_lib, 'foo', 'sub', '__init__.py') self.assertIsNotFile(install_lib, 'Foo-0.1.dist-info', 'RECORD') - @unittest.skipIf(sys.platform == 'win32', 'deactivated for now') def test_remove_issue(self): # makes sure if there are OSErrors (like permission denied) # remove() stops and display a clean error diff --git a/Lib/packaging/tests/test_util.py b/Lib/packaging/tests/test_util.py --- a/Lib/packaging/tests/test_util.py +++ b/Lib/packaging/tests/test_util.py @@ -19,7 +19,7 @@ get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages, spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob, RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging, - get_install_method, cfg_to_args) + get_install_method, cfg_to_args, encode_multipart) PYPIRC = """\ @@ -54,6 +54,23 @@ password:xxx """ +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'', +] + class FakePopen: test_class = None @@ -525,6 +542,13 @@ self.assertEqual(args['scripts'], dist.scripts) self.assertEqual(args['py_modules'], dist.py_modules) + 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')) + class GlobTestCaseBase(support.TempdirManager, support.LoggingCatcher, diff --git a/Lib/packaging/util.py b/Lib/packaging/util.py --- a/Lib/packaging/util.py +++ b/Lib/packaging/util.py @@ -1487,3 +1487,50 @@ _path_created.add(abs_head) return created_dirs + + +def encode_multipart(fields, files, boundary=None): + """Prepare a multipart HTTP request. + + *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. + """ + # Taken from + # http://code.activestate.com/recipes/146306-http-client-to-post-using-multipartform-data/ + + if boundary is None: + boundary = b'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + elif not isinstance(boundary, bytes): + raise TypeError('boundary must be bytes, not %r' % type(boundary)) + + l = [] + for key, values in fields: + # handle multiple entries for the same name + if not isinstance(values, (tuple, list)): + values=[values] + + for value in values: + 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 diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -78,6 +78,8 @@ from _ssl import HAS_SNI from _ssl import (PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1) +from _ssl import _OPENSSL_API_VERSION + _PROTOCOL_NAMES = { PROTOCOL_TLSv1: "TLSv1", PROTOCOL_SSLv23: "SSLv23", diff --git a/Lib/test/test_codecencodings_cn.py b/Lib/test/test_codecencodings_cn.py --- a/Lib/test/test_codecencodings_cn.py +++ b/Lib/test/test_codecencodings_cn.py @@ -15,8 +15,8 @@ # invalid bytes (b"abc\x81\x81\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x81\x81\xc1\xc4", "replace", "abc\ufffd\u804a"), - (b"abc\x81\x81\xc1\xc4\xc8", "replace", "abc\ufffd\u804a\ufffd"), + (b"abc\x81\x81\xc1\xc4", "replace", "abc\ufffd\ufffd\u804a"), + (b"abc\x81\x81\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u804a\ufffd"), (b"abc\x81\x81\xc1\xc4", "ignore", "abc\u804a"), (b"\xc1\x64", "strict", None), ) @@ -28,8 +28,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u804a"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u804a\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u804a"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u804a\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u804a"), (b"\x83\x34\x83\x31", "strict", None), ("\u30fb", "strict", None), @@ -42,11 +42,14 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u804a"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u804a\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u804a"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u804a\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u804a"), - (b"abc\x84\x39\x84\x39\xc1\xc4", "replace", "abc\ufffd\u804a"), + (b"abc\x84\x39\x84\x39\xc1\xc4", "replace", "abc\ufffd9\ufffd9\u804a"), ("\u30fb", "strict", b"\x819\xa79"), + (b"abc\x84\x32\x80\x80def", "replace", 'abc\ufffd2\ufffd\ufffddef'), + (b"abc\x81\x30\x81\x30def", "strict", 'abc\x80def'), + (b"abc\x86\x30\x81\x30def", "replace", 'abc\ufffd0\ufffd0def'), ) has_iso10646 = True @@ -74,9 +77,11 @@ '\u5df1\u6240\u4e0d\u6b32\uff0c\u52ff\u65bd\u65bc\u4eba\u3002' 'Bye.\n'), # invalid bytes - (b'ab~cd', 'replace', 'ab\uFFFDd'), + (b'ab~cd', 'replace', 'ab\uFFFDcd'), (b'ab\xffcd', 'replace', 'ab\uFFFDcd'), (b'ab~{\x81\x81\x41\x44~}cd', 'replace', 'ab\uFFFD\uFFFD\u804Acd'), + (b'ab~{\x41\x44~}cd', 'replace', 'ab\u804Acd'), + (b"ab~{\x79\x79\x41\x44~}cd", "replace", "ab\ufffd\ufffd\u804acd"), ) def test_main(): diff --git a/Lib/test/test_codecencodings_hk.py b/Lib/test/test_codecencodings_hk.py --- a/Lib/test/test_codecencodings_hk.py +++ b/Lib/test/test_codecencodings_hk.py @@ -15,8 +15,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u8b10"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u8b10\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u8b10"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u8b10\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u8b10"), ) diff --git a/Lib/test/test_codecencodings_jp.py b/Lib/test/test_codecencodings_jp.py --- a/Lib/test/test_codecencodings_jp.py +++ b/Lib/test/test_codecencodings_jp.py @@ -15,50 +15,57 @@ # invalid bytes (b"abc\x81\x00\x81\x00\x82\x84", "strict", None), (b"abc\xf8", "strict", None), - (b"abc\x81\x00\x82\x84", "replace", "abc\ufffd\uff44"), - (b"abc\x81\x00\x82\x84\x88", "replace", "abc\ufffd\uff44\ufffd"), - (b"abc\x81\x00\x82\x84", "ignore", "abc\uff44"), + (b"abc\x81\x00\x82\x84", "replace", "abc\ufffd\x00\uff44"), + (b"abc\x81\x00\x82\x84\x88", "replace", "abc\ufffd\x00\uff44\ufffd"), + (b"abc\x81\x00\x82\x84", "ignore", "abc\x00\uff44"), + (b"ab\xEBxy", "replace", "ab\uFFFDxy"), + (b"ab\xF0\x39xy", "replace", "ab\uFFFD9xy"), + (b"ab\xEA\xF0xy", "replace", 'ab\ufffd\ue038y'), # sjis vs cp932 (b"\\\x7e", "replace", "\\\x7e"), (b"\x81\x5f\x81\x61\x81\x7c", "replace", "\uff3c\u2225\uff0d"), ) +euc_commontests = ( + # invalid bytes + (b"abc\x80\x80\xc1\xc4", "strict", None), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u7956"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u7956\ufffd"), + (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u7956"), + (b"abc\xc8", "strict", None), + (b"abc\x8f\x83\x83", "replace", "abc\ufffd\ufffd\ufffd"), + (b"\x82\xFCxy", "replace", "\ufffd\ufffdxy"), + (b"\xc1\x64", "strict", None), + (b"\xa1\xc0", "strict", "\uff3c"), + (b"\xa1\xc0\\", "strict", "\uff3c\\"), + (b"\x8eXY", "replace", "\ufffdXY"), +) + +class Test_EUC_JIS_2004(test_multibytecodec_support.TestBase, + unittest.TestCase): + encoding = 'euc_jis_2004' + tstring = test_multibytecodec_support.load_teststring('euc_jisx0213') + codectests = euc_commontests + xmlcharnametest = ( + "\xab\u211c\xbb = \u2329\u1234\u232a", + b"\xa9\xa8ℜ\xa9\xb2 = ⟨ሴ⟩" + ) + class Test_EUC_JISX0213(test_multibytecodec_support.TestBase, unittest.TestCase): encoding = 'euc_jisx0213' tstring = test_multibytecodec_support.load_teststring('euc_jisx0213') - codectests = ( - # invalid bytes - (b"abc\x80\x80\xc1\xc4", "strict", None), - (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u7956"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u7956\ufffd"), - (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u7956"), - (b"abc\x8f\x83\x83", "replace", "abc\ufffd"), - (b"\xc1\x64", "strict", None), - (b"\xa1\xc0", "strict", "\uff3c"), - ) + codectests = euc_commontests xmlcharnametest = ( "\xab\u211c\xbb = \u2329\u1234\u232a", b"\xa9\xa8ℜ\xa9\xb2 = ⟨ሴ⟩" ) -eucjp_commontests = ( - (b"abc\x80\x80\xc1\xc4", "strict", None), - (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u7956"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u7956\ufffd"), - (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u7956"), - (b"abc\x8f\x83\x83", "replace", "abc\ufffd"), - (b"\xc1\x64", "strict", None), -) - class Test_EUC_JP_COMPAT(test_multibytecodec_support.TestBase, unittest.TestCase): encoding = 'euc_jp' tstring = test_multibytecodec_support.load_teststring('euc_jp') - codectests = eucjp_commontests + ( - (b"\xa1\xc0\\", "strict", "\uff3c\\"), + codectests = euc_commontests + ( ("\xa5", "strict", b"\x5c"), ("\u203e", "strict", b"\x7e"), ) @@ -66,8 +73,6 @@ shiftjis_commonenctests = ( (b"abc\x80\x80\x82\x84", "strict", None), (b"abc\xf8", "strict", None), - (b"abc\x80\x80\x82\x84", "replace", "abc\ufffd\uff44"), - (b"abc\x80\x80\x82\x84\x88", "replace", "abc\ufffd\uff44\ufffd"), (b"abc\x80\x80\x82\x84def", "ignore", "abc\uff44def"), ) @@ -75,20 +80,41 @@ encoding = 'shift_jis' tstring = test_multibytecodec_support.load_teststring('shift_jis') codectests = shiftjis_commonenctests + ( + (b"abc\x80\x80\x82\x84", "replace", "abc\ufffd\ufffd\uff44"), + (b"abc\x80\x80\x82\x84\x88", "replace", "abc\ufffd\ufffd\uff44\ufffd"), + (b"\\\x7e", "strict", "\\\x7e"), (b"\x81\x5f\x81\x61\x81\x7c", "strict", "\uff3c\u2016\u2212"), + (b"abc\x81\x39", "replace", "abc\ufffd9"), + (b"abc\xEA\xFC", "replace", "abc\ufffd\ufffd"), + (b"abc\xFF\x58", "replace", "abc\ufffdX"), + ) + +class Test_SJIS_2004(test_multibytecodec_support.TestBase, unittest.TestCase): + encoding = 'shift_jis_2004' + tstring = test_multibytecodec_support.load_teststring('shift_jis') + codectests = shiftjis_commonenctests + ( + (b"\\\x7e", "strict", "\xa5\u203e"), + (b"\x81\x5f\x81\x61\x81\x7c", "strict", "\\\u2016\u2212"), + (b"abc\xEA\xFC", "strict", "abc\u64bf"), + (b"\x81\x39xy", "replace", "\ufffd9xy"), + (b"\xFF\x58xy", "replace", "\ufffdXxy"), + (b"\x80\x80\x82\x84xy", "replace", "\ufffd\ufffd\uff44xy"), + (b"\x80\x80\x82\x84\x88xy", "replace", "\ufffd\ufffd\uff44\u5864y"), + (b"\xFC\xFBxy", "replace", '\ufffd\u95b4y'), + ) + xmlcharnametest = ( + "\xab\u211c\xbb = \u2329\u1234\u232a", + b"\x85Gℜ\x85Q = ⟨ሴ⟩" ) class Test_SJISX0213(test_multibytecodec_support.TestBase, unittest.TestCase): encoding = 'shift_jisx0213' tstring = test_multibytecodec_support.load_teststring('shift_jisx0213') - codectests = ( - # invalid bytes - (b"abc\x80\x80\x82\x84", "strict", None), - (b"abc\xf8", "strict", None), - (b"abc\x80\x80\x82\x84", "replace", "abc\ufffd\uff44"), - (b"abc\x80\x80\x82\x84\x88", "replace", "abc\ufffd\uff44\ufffd"), - (b"abc\x80\x80\x82\x84def", "ignore", "abc\uff44def"), + codectests = shiftjis_commonenctests + ( + (b"abc\x80\x80\x82\x84", "replace", "abc\ufffd\ufffd\uff44"), + (b"abc\x80\x80\x82\x84\x88", "replace", "abc\ufffd\ufffd\uff44\ufffd"), + # sjis vs cp932 (b"\\\x7e", "replace", "\xa5\u203e"), (b"\x81\x5f\x81\x61\x81\x7c", "replace", "\x5c\u2016\u2212"), diff --git a/Lib/test/test_codecencodings_kr.py b/Lib/test/test_codecencodings_kr.py --- a/Lib/test/test_codecencodings_kr.py +++ b/Lib/test/test_codecencodings_kr.py @@ -15,8 +15,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\uc894"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\uc894\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\uc894"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\uc894\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\uc894"), ) @@ -27,8 +27,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\uc894"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\uc894\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", 'abc\ufffd\ufffd\uc894'), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\uc894\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\uc894"), # composed make-up sequence errors @@ -40,13 +40,14 @@ (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4", "strict", None), (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xd4", "strict", "\uc4d4"), (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xd4x", "strict", "\uc4d4x"), - (b"a\xa4\xd4\xa4\xb6\xa4", "replace", "a\ufffd"), + (b"a\xa4\xd4\xa4\xb6\xa4", "replace", 'a\ufffd'), (b"\xa4\xd4\xa3\xb6\xa4\xd0\xa4\xd4", "strict", None), (b"\xa4\xd4\xa4\xb6\xa3\xd0\xa4\xd4", "strict", None), (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa3\xd4", "strict", None), - (b"\xa4\xd4\xa4\xff\xa4\xd0\xa4\xd4", "replace", "\ufffd"), - (b"\xa4\xd4\xa4\xb6\xa4\xff\xa4\xd4", "replace", "\ufffd"), - (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xff", "replace", "\ufffd"), + (b"\xa4\xd4\xa4\xff\xa4\xd0\xa4\xd4", "replace", '\ufffd\u6e21\ufffd\u3160\ufffd'), + (b"\xa4\xd4\xa4\xb6\xa4\xff\xa4\xd4", "replace", '\ufffd\u6e21\ub544\ufffd\ufffd'), + (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xff", "replace", '\ufffd\u6e21\ub544\u572d\ufffd'), + (b"\xa4\xd4\xff\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xd4", "replace", '\ufffd\ufffd\ufffd\uc4d4'), (b"\xc1\xc4", "strict", "\uc894"), ) @@ -57,9 +58,13 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ucd27"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ucd27\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\ucd27"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\ucd27\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\ucd27"), + (b"\xD8abc", "replace", "\uFFFDabc"), + (b"\xD8\xFFabc", "replace", "\uFFFD\uFFFDabc"), + (b"\x84bxy", "replace", "\uFFFDbxy"), + (b"\x8CBxy", "replace", "\uFFFDBxy"), ) def test_main(): diff --git a/Lib/test/test_codecencodings_tw.py b/Lib/test/test_codecencodings_tw.py --- a/Lib/test/test_codecencodings_tw.py +++ b/Lib/test/test_codecencodings_tw.py @@ -15,8 +15,8 @@ # invalid bytes (b"abc\x80\x80\xc1\xc4", "strict", None), (b"abc\xc8", "strict", None), - (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\u8b10"), - (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\u8b10\ufffd"), + (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\ufffd\u8b10"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\ufffd\u8b10\ufffd"), (b"abc\x80\x80\xc1\xc4", "ignore", "abc\u8b10"), ) diff --git a/Lib/test/test_codecmaps_tw.py b/Lib/test/test_codecmaps_tw.py --- a/Lib/test/test_codecmaps_tw.py +++ b/Lib/test/test_codecmaps_tw.py @@ -23,6 +23,9 @@ (b'\xa2\xcc', '\u5341'), (b'\xa2\xce', '\u5345'), ] + codectests = ( + (b"\xFFxy", "replace", "\ufffdxy"), + ) def test_main(): support.run_unittest(__name__) diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py --- a/Lib/test/test_robotparser.py +++ b/Lib/test/test_robotparser.py @@ -1,7 +1,8 @@ import io import unittest import urllib.robotparser -from urllib.error import URLError +from urllib.error import URLError, HTTPError +from urllib.request import urlopen from test import support class RobotTestCase(unittest.TestCase): @@ -237,13 +238,27 @@ support.requires('network') with support.transient_internet('mueblesmoraleda.com'): url = 'http://mueblesmoraleda.com' + robots_url = url + "/robots.txt" + # First check the URL is usable for our purposes, since the + # test site is a bit flaky. + try: + urlopen(robots_url) + except HTTPError as e: + if e.code not in {401, 403}: + self.skipTest( + "%r should return a 401 or 403 HTTP error, not %r" + % (robots_url, e.code)) + else: + self.skipTest( + "%r should return a 401 or 403 HTTP error, not succeed" + % (robots_url)) parser = urllib.robotparser.RobotFileParser() parser.set_url(url) try: parser.read() except URLError: self.skipTest('%s is unavailable' % url) - self.assertEqual(parser.can_fetch("*", url+"/robots.txt"), False) + self.assertEqual(parser.can_fetch("*", robots_url), False) def testPythonOrg(self): support.requires('network') 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 @@ -60,7 +60,7 @@ def can_clear_options(): # 0.9.8m or higher - return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 13, 15) + return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15) def no_sslv2_implies_sslv3_hello(): # 0.9.7h or higher diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py --- a/Lib/test/test_urllibnet.py +++ b/Lib/test/test_urllibnet.py @@ -113,6 +113,14 @@ def test_bad_address(self): # Make sure proper exception is raised when connecting to a bogus # address. + bogus_domain = "sadflkjsasf.i.nvali.d" + try: + socket.gethostbyname(bogus_domain) + except socket.gaierror: + pass + else: + # This happens with some overzealous DNS providers such as OpenDNS + self.skipTest("%r should not resolve for test to work" % bogus_domain) self.assertRaises(IOError, # SF patch 809915: In Sep 2003, VeriSign started # highjacking invalid .com and .net addresses to diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -263,6 +263,7 @@ Walter D?rwald Hans Eckardt Rodolpho Eckhardt +John Edmonds Grant Edwards John Ehresman Eric Eisner @@ -418,6 +419,7 @@ Gerrit Holl Shane Holloway Rune Holm +Thomas Holmes Philip Homburg Naofumi Honda Jeffrey Honig diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -219,6 +219,16 @@ Library ------- +- Issue #12504: Close file handles in a timely manner in packaging.database. + This fixes a bug with the remove (uninstall) feature on Windows. + +- Issues #12169 and #10510: Factor out code used by various packaging commands + to make HTTP POST requests, and make sure it uses CRLF. + +- Issue #12016: Multibyte CJK decoders now resynchronize faster. They only + ignore the first byte of an invalid byte sequence. For example, + b'\xff\n'.decode('gb2312', 'replace') gives '\ufffd\n' instead of '\ufffd'. + - Issue #12459: time.sleep() now raises a ValueError if the sleep length is negative, instead of an infinite sleep on Windows or raising an IOError on Linux for example, to have the same behaviour on all platforms. @@ -994,6 +1004,18 @@ Tests ----- +- Avoid failing in test_robotparser when mueblesmoraleda.com is flaky and + an overzealous DNS service (e.g. OpenDNS) redirects to a placeholder + Web site. + +- Avoid failing in test_urllibnet.test_bad_address when some overzealous + DNS service (e.g. OpenDNS) resolves a non-existent domain name. The test + is now skipped instead. + +- Issue #12440: When testing whether some bits in SSLContext.options can be + reset, check the version of the OpenSSL headers Python was compiled against, + rather than the runtime version of the OpenSSL library. + - Issue #11512: Add a test suite for the cgitb module. Patch by Robbie Clemons. - Issue #12497: Install test/data to prevent failures of the various codecmaps diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2101,6 +2101,24 @@ NULL }; + +static void +parse_openssl_version(unsigned long libver, + unsigned int *major, unsigned int *minor, + unsigned int *fix, unsigned int *patch, + unsigned int *status) +{ + *status = libver & 0xF; + libver >>= 4; + *patch = libver & 0xFF; + libver >>= 8; + *fix = libver & 0xFF; + libver >>= 8; + *minor = libver & 0xFF; + libver >>= 8; + *major = libver & 0xFF; +} + PyMODINIT_FUNC PyInit__ssl(void) { @@ -2213,15 +2231,7 @@ return NULL; if (PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) return NULL; - status = libver & 0xF; - libver >>= 4; - patch = libver & 0xFF; - libver >>= 8; - fix = libver & 0xFF; - libver >>= 8; - minor = libver & 0xFF; - libver >>= 8; - major = libver & 0xFF; + parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); r = Py_BuildValue("IIIII", major, minor, fix, patch, status); if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) return NULL; @@ -2229,5 +2239,11 @@ if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) return NULL; + libver = OPENSSL_VERSION_NUMBER; + parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); + r = Py_BuildValue("IIIII", major, minor, fix, patch, status); + if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) + return NULL; + return m; } diff --git a/Modules/cjkcodecs/_codecs_cn.c b/Modules/cjkcodecs/_codecs_cn.c --- a/Modules/cjkcodecs/_codecs_cn.c +++ b/Modules/cjkcodecs/_codecs_cn.c @@ -85,7 +85,7 @@ TRYMAP_DEC(gb2312, **outbuf, c ^ 0x80, IN2 ^ 0x80) { NEXT(2, 1) } - else return 2; + else return 1; } return 0; @@ -141,7 +141,7 @@ REQUIRE_INBUF(2) GBK_DECODE(c, IN2, **outbuf) - else return 2; + else return 1; NEXT(2, 1) } @@ -267,7 +267,7 @@ c3 = IN3; c4 = IN4; if (c < 0x81 || c3 < 0x81 || c4 < 0x30 || c4 > 0x39) - return 4; + return 1; c -= 0x81; c2 -= 0x30; c3 -= 0x81; c4 -= 0x30; @@ -292,12 +292,12 @@ continue; } } - return 4; + return 1; } GBK_DECODE(c, c2, **outbuf) else TRYMAP_DEC(gb18030ext, **outbuf, c, c2); - else return 2; + else return 1; NEXT(2, 1) } @@ -400,7 +400,7 @@ else if (c2 == '\n') ; /* line-continuation */ else - return 2; + return 1; NEXT(2, 0); continue; } @@ -419,7 +419,7 @@ NEXT(2, 1) } else - return 2; + return 1; } } diff --git a/Modules/cjkcodecs/_codecs_hk.c b/Modules/cjkcodecs/_codecs_hk.c --- a/Modules/cjkcodecs/_codecs_hk.c +++ b/Modules/cjkcodecs/_codecs_hk.c @@ -161,7 +161,7 @@ case 0x8864: WRITE2(0x00ca, 0x030c); break; case 0x88a3: WRITE2(0x00ea, 0x0304); break; case 0x88a5: WRITE2(0x00ea, 0x030c); break; - default: return 2; + default: return 1; } NEXT(2, 2) /* all decoded codepoints are pairs, above. */ diff --git a/Modules/cjkcodecs/_codecs_jp.c b/Modules/cjkcodecs/_codecs_jp.c --- a/Modules/cjkcodecs/_codecs_jp.c +++ b/Modules/cjkcodecs/_codecs_jp.c @@ -112,7 +112,7 @@ TRYMAP_DEC(cp932ext, **outbuf, c, c2); else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)){ if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) - return 2; + return 1; c = (c < 0xe0 ? c - 0x81 : c - 0xc1); c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); @@ -120,7 +120,7 @@ c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21; TRYMAP_DEC(jisx0208, **outbuf, c, c2); - else return 2; + else return 1; } else if (c >= 0xf0 && c <= 0xf9) { if ((c2 >= 0x40 && c2 <= 0x7e) || @@ -128,10 +128,10 @@ OUT1(0xe000 + 188 * (c - 0xf0) + (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41)) else - return 2; + return 1; } else - return 2; + return 1; NEXT(2, 1) } @@ -256,7 +256,7 @@ NEXT(2, 1) } else - return 2; + return 1; } else if (c == 0x8f) { unsigned char c2, c3; @@ -274,7 +274,7 @@ continue; } else TRYMAP_DEC(jisx0212, **outbuf, c2, c3) ; - else return 3; + else return 1; NEXT(3, 1) } else { @@ -300,7 +300,7 @@ NEXT(2, 2) continue; } - else return 2; + else return 1; NEXT(2, 1) } } @@ -388,7 +388,7 @@ NEXT(2, 1) } else - return 2; + return 1; } else if (c == 0x8f) { unsigned char c2, c3; @@ -401,7 +401,7 @@ NEXT(3, 1) } else - return 3; + return 1; } else { unsigned char c2; @@ -417,7 +417,7 @@ #endif TRYMAP_DEC(jisx0208, **outbuf, c ^ 0x80, c2 ^ 0x80) ; - else return 2; + else return 1; NEXT(2, 1) } } @@ -502,7 +502,7 @@ REQUIRE_INBUF(2) c2 = IN2; if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) - return 2; + return 1; c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1); c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); @@ -522,10 +522,10 @@ continue; } else - return 2; + return 1; } else - return 2; + return 1; NEXT(1, 1) /* JIS X 0201 */ } @@ -645,7 +645,7 @@ REQUIRE_INBUF(2) c2 = IN2; if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) - return 2; + return 1; c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1); c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); @@ -671,7 +671,7 @@ NEXT_OUT(2) } else - return 2; + return 1; NEXT_IN(2) } else { /* Plane 2 */ @@ -689,13 +689,13 @@ continue; } else - return 2; + return 1; NEXT(2, 1) } continue; } else - return 2; + return 1; NEXT(1, 1) /* JIS X 0201 */ } diff --git a/Modules/cjkcodecs/_codecs_kr.c b/Modules/cjkcodecs/_codecs_kr.c --- a/Modules/cjkcodecs/_codecs_kr.c +++ b/Modules/cjkcodecs/_codecs_kr.c @@ -123,7 +123,7 @@ if ((*inbuf)[2] != EUCKR_JAMO_FIRSTBYTE || (*inbuf)[4] != EUCKR_JAMO_FIRSTBYTE || (*inbuf)[6] != EUCKR_JAMO_FIRSTBYTE) - return 8; + return 1; c = (*inbuf)[3]; if (0xa1 <= c && c <= 0xbe) @@ -143,7 +143,7 @@ jong = NONE; if (cho == NONE || jung == NONE || jong == NONE) - return 8; + return 1; OUT1(0xac00 + cho*588 + jung*28 + jong); NEXT(8, 1) @@ -152,7 +152,7 @@ NEXT(2, 1) } else - return 2; + return 1; } return 0; @@ -208,7 +208,7 @@ REQUIRE_INBUF(2) TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80); else TRYMAP_DEC(cp949ext, **outbuf, c, IN2); - else return 2; + else return 1; NEXT(2, 1) } @@ -375,7 +375,7 @@ i_jong = johabidx_jongseong[c_jong]; if (i_cho == NONE || i_jung == NONE || i_jong == NONE) - return 2; + return 1; /* we don't use U+1100 hangul jamo yet. */ if (i_cho == FILL) { @@ -391,7 +391,7 @@ OUT1(0x3100 | johabjamo_jungseong[c_jung]) else - return 2; + return 1; } } else { if (i_jung == FILL) { @@ -399,7 +399,7 @@ OUT1(0x3100 | johabjamo_choseong[c_cho]) else - return 2; + return 1; } else OUT1(0xac00 + @@ -414,7 +414,7 @@ c2 < 0x31 || (c2 >= 0x80 && c2 < 0x91) || (c2 & 0x7f) == 0x7f || (c == 0xda && (c2 >= 0xa1 && c2 <= 0xd3))) - return 2; + return 1; else { unsigned char t1, t2; @@ -425,7 +425,7 @@ t2 = (t2 < 0x5e ? t2 : t2 - 0x5e) + 0x21; TRYMAP_DEC(ksx1001, **outbuf, t1, t2); - else return 2; + else return 1; NEXT(2, 1) } } diff --git a/Modules/cjkcodecs/_codecs_tw.c b/Modules/cjkcodecs/_codecs_tw.c --- a/Modules/cjkcodecs/_codecs_tw.c +++ b/Modules/cjkcodecs/_codecs_tw.c @@ -55,7 +55,7 @@ TRYMAP_DEC(big5, **outbuf, c, IN2) { NEXT(2, 1) } - else return 2; + else return 1; } return 0; @@ -109,7 +109,7 @@ TRYMAP_DEC(cp950ext, **outbuf, c, IN2); else TRYMAP_DEC(big5, **outbuf, c, IN2); - else return 2; + else return 1; NEXT(2, 1) } diff --git a/Modules/md5module.c b/Modules/md5module.c --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -243,7 +243,7 @@ in += MD5_BLOCKSIZE; inlen -= MD5_BLOCKSIZE; } else { - n = MIN(inlen, (MD5_BLOCKSIZE - md5->curlen)); + n = MIN(inlen, (Py_ssize_t)(MD5_BLOCKSIZE - md5->curlen)); memcpy(md5->buf + md5->curlen, in, (size_t)n); md5->curlen += n; in += n; diff --git a/Modules/sha1module.c b/Modules/sha1module.c --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -218,7 +218,7 @@ in += SHA1_BLOCKSIZE; inlen -= SHA1_BLOCKSIZE; } else { - n = MIN(inlen, (SHA1_BLOCKSIZE - sha1->curlen)); + n = MIN(inlen, (Py_ssize_t)(SHA1_BLOCKSIZE - sha1->curlen)); memcpy(sha1->buf + sha1->curlen, in, (size_t)n); sha1->curlen += n; in += n; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 23:38:35 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 23:38:35 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2311863=3A_remove_un?= =?utf8?q?used_file_Python/thread=5Fwince=2Eh?= Message-ID: http://hg.python.org/cpython/rev/638039a4fef3 changeset: 71265:638039a4fef3 user: Antoine Pitrou date: Fri Jul 08 23:37:39 2011 +0200 summary: Issue #11863: remove unused file Python/thread_wince.h files: Python/thread_wince.h | 136 ------------------------------ 1 files changed, 0 insertions(+), 136 deletions(-) diff --git a/Python/thread_wince.h b/Python/thread_wince.h deleted file mode 100644 --- a/Python/thread_wince.h +++ /dev/null @@ -1,136 +0,0 @@ - -/* This code implemented by Mark Hammond (MHammond at skippinet.com.au) */ - -#include -#include -#include - -long PyThread_get_thread_ident(void); - -/* - * Change all headers to pure ANSI as no one will use K&R style on an - * NT - */ - -/* - * Initialization of the C package, should not be needed. - */ -static void PyThread__init_thread(void) -{ -} - -/* - * Thread support. - */ -long PyThread_start_new_thread(void (*func)(void *), void *arg) -{ - long rv; - int success = -1; - - dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident())); - if (!initialized) - PyThread_init_thread(); - - rv = _beginthread(func, 0, arg); /* use default stack size */ - - if (rv != -1) { - success = 0; - dprintf(("%ld: PyThread_start_new_thread succeeded:\n", PyThread_get_thread_ident())); - } - - return success; -} - -/* - * Return the thread Id instead of an handle. The Id is said to uniquely identify the - * thread in the system - */ -long PyThread_get_thread_ident(void) -{ - if (!initialized) - PyThread_init_thread(); - - return GetCurrentThreadId(); -} - -void PyThread_exit_thread(void) -{ - dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident())); - if (!initialized) - exit(0); - _endthread(); -} - -/* - * Lock support. It has to be implemented using Mutexes, as - * CE doesnt support semaphores. Therefore we use some hacks to - * simulate the non reentrant requirements of Python locks - */ -PyThread_type_lock PyThread_allocate_lock(void) -{ - HANDLE aLock; - - dprintf(("PyThread_allocate_lock called\n")); - if (!initialized) - PyThread_init_thread(); - - aLock = CreateEvent(NULL, /* Security attributes */ - 0, /* Manual-Reset */ - 1, /* Is initially signalled */ - NULL); /* Name of event */ - - dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock)); - - return (PyThread_type_lock) aLock; -} - -void PyThread_free_lock(PyThread_type_lock aLock) -{ - dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); - - CloseHandle(aLock); -} - -/* - * Return 1 on success if the lock was acquired - * - * and 0 if the lock was not acquired. This means a 0 is returned - * if the lock has already been acquired by this thread! - */ -int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) -{ - int success = 1; - DWORD waitResult; - - dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag)); - -#ifndef DEBUG - waitResult = WaitForSingleObject(aLock, (waitflag ? INFINITE : 0)); -#else - /* To aid in debugging, we regularly wake up. This allows us to - break into the debugger */ - while (TRUE) { - waitResult = WaitForSingleObject(aLock, waitflag ? 3000 : 0); - if (waitflag==0 || (waitflag && waitResult == WAIT_OBJECT_0)) - break; - } -#endif - - if (waitResult != WAIT_OBJECT_0) { - success = 0; /* We failed */ - } - - dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success)); - - return success; -} - -void PyThread_release_lock(PyThread_type_lock aLock) -{ - dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); - - if (!SetEvent(aLock)) - dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", PyThread_get_thread_ident(), aLock, GetLastError())); -} - - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 8 23:52:45 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 08 Jul 2011 23:52:45 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2311863=3A_Remove_su?= =?utf8?q?pport_for_legacy_systems_deprecated_in_Python_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/0aa3f90f0830 changeset: 71266:0aa3f90f0830 user: Antoine Pitrou date: Fri Jul 08 23:47:50 2011 +0200 summary: Issue #11863: Remove support for legacy systems deprecated in Python 3.2 (following PEP 11). These systems are systems using Mach C Threads, SunOS lightweight processes, GNU pth threads and IRIX threads. files: Include/Python.h | 5 - Misc/NEWS | 4 + PC/pyconfig.h | 3 - Python/thread.c | 43 - Python/thread_cthread.h | 112 ----- Python/thread_lwp.h | 113 ----- Python/thread_sgi.h | 259 ----------- Python/thread_solaris.h | 130 ----- configure | 627 +++++++++++++-------------- configure.in | 16 +- pyconfig.h.in | 12 - 11 files changed, 315 insertions(+), 1009 deletions(-) diff --git a/Include/Python.h b/Include/Python.h --- a/Include/Python.h +++ b/Include/Python.h @@ -151,11 +151,6 @@ #define Py_file_input 257 #define Py_eval_input 258 -#ifdef HAVE_PTH -/* GNU pth user-space thread support */ -#include -#endif - /* Define macros for inline documentation. */ #define PyDoc_VAR(name) static char name[] #define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -948,6 +948,10 @@ Build ----- +- Issue #11863: Remove support for legacy systems deprecated in Python 3.2 + (following PEP 11). These systems are systems using Mach C Threads, + SunOS lightweight processes, GNU pth threads and IRIX threads. + - Issue #8746: Correct faulty configure checks so that os.chflags() and os.lchflags() are once again built on systems that support these functions (*BSD and OS X). Also add new stat file flags for OS X diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -711,9 +711,6 @@ /* Define if you have the header file. */ /* #define HAVE_SYS_UTSNAME_H 1 */ -/* Define if you have the header file. */ -/* #undef HAVE_THREAD_H */ - /* Define if you have the header file. */ /* #define HAVE_UNISTD_H 1 */ diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -26,18 +26,6 @@ #ifndef _POSIX_THREADS -#ifdef __sgi -#define SGI_THREADS -#endif - -#ifdef HAVE_THREAD_H -#define SOLARIS_THREADS -#endif - -#if defined(sun) && !defined(SOLARIS_THREADS) -#define SUN_LWP -#endif - /* Check if we're running on HP-UX and _SC_THREADS is defined. If so, then enough of the Posix threads package is implemented to support python threads. @@ -93,37 +81,11 @@ or the size specified by the THREAD_STACK_SIZE macro. */ static size_t _pythread_stacksize = 0; -#ifdef SGI_THREADS -#error SGI Irix threads are now unsupported, and code will be removed in 3.3. -#include "thread_sgi.h" -#endif - -#ifdef SOLARIS_THREADS -#define PYTHREAD_NAME "solaris" -#include "thread_solaris.h" -#endif - -#ifdef SUN_LWP -#error SunOS lightweight processes are now unsupported, and code will be removed in 3.3. -#include "thread_lwp.h" -#endif - -#ifdef HAVE_PTH -#error GNU pth threads are now unsupported, and code will be removed in 3.3. -#include "thread_pth.h" -#undef _POSIX_THREADS -#endif - #ifdef _POSIX_THREADS #define PYTHREAD_NAME "pthread" #include "thread_pthread.h" #endif -#ifdef C_THREADS -#error Mach C Threads are now unsupported, and code will be removed in 3.3. -#include "thread_cthread.h" -#endif - #ifdef NT_THREADS #define PYTHREAD_NAME "nt" #include "thread_nt.h" @@ -134,11 +96,6 @@ #include "thread_os2.h" #endif -#ifdef PLAN9_THREADS -#define PYTHREAD_NAME "plan9" -#include "thread_plan9.h" -#endif - /* #ifdef FOOBAR_THREADS #include "thread_foobar.h" diff --git a/Python/thread_cthread.h b/Python/thread_cthread.h deleted file mode 100644 --- a/Python/thread_cthread.h +++ /dev/null @@ -1,112 +0,0 @@ - -#ifdef MACH_C_THREADS -#include -#endif - -#ifdef HURD_C_THREADS -#include -#endif - -/* - * Initialization. - */ -static void -PyThread__init_thread(void) -{ -#ifndef HURD_C_THREADS - /* Roland McGrath said this should not be used since this is - done while linking to threads */ - cthread_init(); -#else -/* do nothing */ - ; -#endif -} - -/* - * Thread support. - */ -long -PyThread_start_new_thread(void (*func)(void *), void *arg) -{ - int success = 0; /* init not needed when SOLARIS_THREADS and */ - /* C_THREADS implemented properly */ - - dprintf(("PyThread_start_new_thread called\n")); - if (!initialized) - PyThread_init_thread(); - /* looks like solaris detaches the thread to never rejoin - * so well do it here - */ - cthread_detach(cthread_fork((cthread_fn_t) func, arg)); - return success < 0 ? -1 : 0; -} - -long -PyThread_get_thread_ident(void) -{ - if (!initialized) - PyThread_init_thread(); - return (long) cthread_self(); -} - -void -PyThread_exit_thread(void) -{ - dprintf(("PyThread_exit_thread called\n")); - if (!initialized) - exit(0); - cthread_exit(0); -} - -/* - * Lock support. - */ -PyThread_type_lock -PyThread_allocate_lock(void) -{ - mutex_t lock; - - dprintf(("PyThread_allocate_lock called\n")); - if (!initialized) - PyThread_init_thread(); - - lock = mutex_alloc(); - if (mutex_init(lock)) { - perror("mutex_init"); - free((void *) lock); - lock = 0; - } - dprintf(("PyThread_allocate_lock() -> %p\n", lock)); - return (PyThread_type_lock) lock; -} - -void -PyThread_free_lock(PyThread_type_lock lock) -{ - dprintf(("PyThread_free_lock(%p) called\n", lock)); - mutex_free(lock); -} - -int -PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) -{ - int success = FALSE; - - dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); - if (waitflag) { /* blocking */ - mutex_lock((mutex_t)lock); - success = TRUE; - } else { /* non blocking */ - success = mutex_try_lock((mutex_t)lock); - } - dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); - return success; -} - -void -PyThread_release_lock(PyThread_type_lock lock) -{ - dprintf(("PyThread_release_lock(%p) called\n", lock)); - mutex_unlock((mutex_t )lock); -} diff --git a/Python/thread_lwp.h b/Python/thread_lwp.h deleted file mode 100644 --- a/Python/thread_lwp.h +++ /dev/null @@ -1,113 +0,0 @@ - -#include -#include -#include - -#define STACKSIZE 1000 /* stacksize for a thread */ -#define NSTACKS 2 /* # stacks to be put in cache initially */ - -struct lock { - int lock_locked; - cv_t lock_condvar; - mon_t lock_monitor; -}; - - -/* - * Initialization. - */ -static void PyThread__init_thread(void) -{ - lwp_setstkcache(STACKSIZE, NSTACKS); -} - -/* - * Thread support. - */ - - -long PyThread_start_new_thread(void (*func)(void *), void *arg) -{ - thread_t tid; - int success; - dprintf(("PyThread_start_new_thread called\n")); - if (!initialized) - PyThread_init_thread(); - success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg); - return success < 0 ? -1 : 0; -} - -long PyThread_get_thread_ident(void) -{ - thread_t tid; - if (!initialized) - PyThread_init_thread(); - if (lwp_self(&tid) < 0) - return -1; - return tid.thread_id; -} - -void PyThread_exit_thread(void) -{ - dprintf(("PyThread_exit_thread called\n")); - if (!initialized) - exit(0); - lwp_destroy(SELF); -} - -/* - * Lock support. - */ -PyThread_type_lock PyThread_allocate_lock(void) -{ - struct lock *lock; - extern char *malloc(size_t); - - dprintf(("PyThread_allocate_lock called\n")); - if (!initialized) - PyThread_init_thread(); - - lock = (struct lock *) malloc(sizeof(struct lock)); - lock->lock_locked = 0; - (void) mon_create(&lock->lock_monitor); - (void) cv_create(&lock->lock_condvar, lock->lock_monitor); - dprintf(("PyThread_allocate_lock() -> %p\n", lock)); - return (PyThread_type_lock) lock; -} - -void PyThread_free_lock(PyThread_type_lock lock) -{ - dprintf(("PyThread_free_lock(%p) called\n", lock)); - mon_destroy(((struct lock *) lock)->lock_monitor); - free((char *) lock); -} - -int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) -{ - int success; - - dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); - success = 0; - - (void) mon_enter(((struct lock *) lock)->lock_monitor); - if (waitflag) - while (((struct lock *) lock)->lock_locked) - cv_wait(((struct lock *) lock)->lock_condvar); - if (!((struct lock *) lock)->lock_locked) { - success = 1; - ((struct lock *) lock)->lock_locked = 1; - } - cv_broadcast(((struct lock *) lock)->lock_condvar); - mon_exit(((struct lock *) lock)->lock_monitor); - dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); - return success; -} - -void PyThread_release_lock(PyThread_type_lock lock) -{ - dprintf(("PyThread_release_lock(%p) called\n", lock)); - (void) mon_enter(((struct lock *) lock)->lock_monitor); - ((struct lock *) lock)->lock_locked = 0; - cv_broadcast(((struct lock *) lock)->lock_condvar); - mon_exit(((struct lock *) lock)->lock_monitor); -} diff --git a/Python/thread_sgi.h b/Python/thread_sgi.h deleted file mode 100644 --- a/Python/thread_sgi.h +++ /dev/null @@ -1,259 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define HDR_SIZE 2680 /* sizeof(ushdr_t) */ -#define MAXPROC 100 /* max # of threads that can be started */ - -static usptr_t *shared_arena; -static ulock_t count_lock; /* protection for some variables */ -static ulock_t wait_lock; /* lock used to wait for other threads */ -static int waiting_for_threads; /* protected by count_lock */ -static int nthreads; /* protected by count_lock */ -static int exit_status; -static int exiting; /* we're already exiting (for maybe_exit) */ -static pid_t my_pid; /* PID of main thread */ -static struct pidlist { - pid_t parent; - pid_t child; -} pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */ -static int maxpidindex; /* # of PIDs in pidlist */ -/* - * Initialization. - */ -static void PyThread__init_thread(void) -{ -#ifdef USE_DL - long addr, size; -#endif /* USE_DL */ - - -#ifdef USE_DL - if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0) - perror("usconfig - CONF_INITSIZE (check)"); - if (usconfig(CONF_INITSIZE, size) < 0) - perror("usconfig - CONF_INITSIZE (reset)"); - addr = (long) dl_getrange(size + HDR_SIZE); - dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size)); - errno = 0; - if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0) - perror("usconfig - CONF_ATTACHADDR (set)"); -#endif /* USE_DL */ - if (usconfig(CONF_INITUSERS, 16) < 0) - perror("usconfig - CONF_INITUSERS"); - my_pid = getpid(); /* so that we know which is the main thread */ - if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) - perror("usconfig - CONF_ARENATYPE"); - usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */ -#ifdef Py_DEBUG - if (thread_debug & 4) - usconfig(CONF_LOCKTYPE, US_DEBUGPLUS); - else if (thread_debug & 2) - usconfig(CONF_LOCKTYPE, US_DEBUG); -#endif /* Py_DEBUG */ - if ((shared_arena = usinit(tmpnam(0))) == 0) - perror("usinit"); -#ifdef USE_DL - if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */ - perror("usconfig - CONF_ATTACHADDR (reset)"); -#endif /* USE_DL */ - if ((count_lock = usnewlock(shared_arena)) == NULL) - perror("usnewlock (count_lock)"); - (void) usinitlock(count_lock); - if ((wait_lock = usnewlock(shared_arena)) == NULL) - perror("usnewlock (wait_lock)"); - dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena))); -} - -/* - * Thread support. - */ - -static void clean_threads(void) -{ - int i, j; - pid_t mypid, pid; - - /* clean up any exited threads */ - mypid = getpid(); - i = 0; - while (i < maxpidindex) { - if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) { - pid = waitpid(pid, 0, WNOHANG); - if (pid > 0) { - /* a thread has exited */ - pidlist[i] = pidlist[--maxpidindex]; - /* remove references to children of dead proc */ - for (j = 0; j < maxpidindex; j++) - if (pidlist[j].parent == pid) - pidlist[j].child = -1; - continue; /* don't increment i */ - } - } - i++; - } - /* clean up the list */ - i = 0; - while (i < maxpidindex) { - if (pidlist[i].child == -1) { - pidlist[i] = pidlist[--maxpidindex]; - continue; /* don't increment i */ - } - i++; - } -} - -long PyThread_start_new_thread(void (*func)(void *), void *arg) -{ -#ifdef USE_DL - long addr, size; - static int local_initialized = 0; -#endif /* USE_DL */ - int success = 0; /* init not needed when SOLARIS_THREADS and */ - /* C_THREADS implemented properly */ - - dprintf(("PyThread_start_new_thread called\n")); - if (!initialized) - PyThread_init_thread(); - switch (ussetlock(count_lock)) { - case 0: return 0; - case -1: perror("ussetlock (count_lock)"); - } - if (maxpidindex >= MAXPROC) - success = -1; - else { -#ifdef USE_DL - if (!local_initialized) { - if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0) - perror("usconfig - CONF_INITSIZE (check)"); - if (usconfig(CONF_INITSIZE, size) < 0) - perror("usconfig - CONF_INITSIZE (reset)"); - addr = (long) dl_getrange(size + HDR_SIZE); - dprintf(("trying to use addr %p-%p for sproc\n", - addr, addr+size)); - errno = 0; - if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && - errno != 0) - perror("usconfig - CONF_ATTACHADDR (set)"); - } -#endif /* USE_DL */ - clean_threads(); - if ((success = sproc(func, PR_SALL, arg)) < 0) - perror("sproc"); -#ifdef USE_DL - if (!local_initialized) { - if (usconfig(CONF_ATTACHADDR, addr) < 0) - /* reset address */ - perror("usconfig - CONF_ATTACHADDR (reset)"); - local_initialized = 1; - } -#endif /* USE_DL */ - if (success >= 0) { - nthreads++; - pidlist[maxpidindex].parent = getpid(); - pidlist[maxpidindex++].child = success; - dprintf(("pidlist[%d] = %d\n", - maxpidindex-1, success)); - } - } - if (usunsetlock(count_lock) < 0) - perror("usunsetlock (count_lock)"); - return success; -} - -long PyThread_get_thread_ident(void) -{ - return getpid(); -} - -void PyThread_exit_thread(void) -{ - dprintf(("PyThread_exit_thread called\n")); - if (!initialized) - exit(0); - if (ussetlock(count_lock) < 0) - perror("ussetlock (count_lock)"); - nthreads--; - if (getpid() == my_pid) { - /* main thread; wait for other threads to exit */ - exiting = 1; - waiting_for_threads = 1; - if (ussetlock(wait_lock) < 0) - perror("ussetlock (wait_lock)"); - for (;;) { - if (nthreads < 0) { - dprintf(("really exit (%d)\n", exit_status)); - exit(exit_status); - } - if (usunsetlock(count_lock) < 0) - perror("usunsetlock (count_lock)"); - dprintf(("waiting for other threads (%d)\n", nthreads)); - if (ussetlock(wait_lock) < 0) - perror("ussetlock (wait_lock)"); - if (ussetlock(count_lock) < 0) - perror("ussetlock (count_lock)"); - } - } - /* not the main thread */ - if (waiting_for_threads) { - dprintf(("main thread is waiting\n")); - if (usunsetlock(wait_lock) < 0) - perror("usunsetlock (wait_lock)"); - } - if (usunsetlock(count_lock) < 0) - perror("usunsetlock (count_lock)"); - _exit(0); -} - -/* - * Lock support. - */ -PyThread_type_lock PyThread_allocate_lock(void) -{ - ulock_t lock; - - dprintf(("PyThread_allocate_lock called\n")); - if (!initialized) - PyThread_init_thread(); - - if ((lock = usnewlock(shared_arena)) == NULL) - perror("usnewlock"); - (void) usinitlock(lock); - dprintf(("PyThread_allocate_lock() -> %p\n", lock)); - return (PyThread_type_lock) lock; -} - -void PyThread_free_lock(PyThread_type_lock lock) -{ - dprintf(("PyThread_free_lock(%p) called\n", lock)); - usfreelock((ulock_t) lock, shared_arena); -} - -int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) -{ - int success; - - dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); - errno = 0; /* clear it just in case */ - if (waitflag) - success = ussetlock((ulock_t) lock); - else - success = uscsetlock((ulock_t) lock, 1); /* Try it once */ - if (success < 0) - perror(waitflag ? "ussetlock" : "uscsetlock"); - dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); - return success; -} - -void PyThread_release_lock(PyThread_type_lock lock) -{ - dprintf(("PyThread_release_lock(%p) called\n", lock)); - if (usunsetlock((ulock_t) lock) < 0) - perror("usunsetlock"); -} diff --git a/Python/thread_solaris.h b/Python/thread_solaris.h deleted file mode 100644 --- a/Python/thread_solaris.h +++ /dev/null @@ -1,130 +0,0 @@ - -#include -#include -#include -#include -#undef _POSIX_THREADS - - -/* - * Initialization. - */ -static void PyThread__init_thread(void) -{ -} - -/* - * Thread support. - */ -struct func_arg { - void (*func)(void *); - void *arg; -}; - -static void * -new_func(void *funcarg) -{ - void (*func)(void *); - void *arg; - - func = ((struct func_arg *) funcarg)->func; - arg = ((struct func_arg *) funcarg)->arg; - free(funcarg); - (*func)(arg); - return 0; -} - - -long -PyThread_start_new_thread(void (*func)(void *), void *arg) -{ - thread_t tid; - struct func_arg *funcarg; - - dprintf(("PyThread_start_new_thread called\n")); - if (!initialized) - PyThread_init_thread(); - funcarg = (struct func_arg *) malloc(sizeof(struct func_arg)); - funcarg->func = func; - funcarg->arg = arg; - if (thr_create(0, 0, new_func, funcarg, - THR_DETACHED | THR_NEW_LWP, &tid)) { - perror("thr_create"); - free((void *) funcarg); - return -1; - } - return tid; -} - -long -PyThread_get_thread_ident(void) -{ - if (!initialized) - PyThread_init_thread(); - return thr_self(); -} - -void -PyThread_exit_thread(void) -{ - dprintf(("PyThread_exit_thread called\n")); - if (!initialized) - exit(0); - thr_exit(0); -} - -/* - * Lock support. - */ -PyThread_type_lock -PyThread_allocate_lock(void) -{ - mutex_t *lock; - - dprintf(("PyThread_allocate_lock called\n")); - if (!initialized) - PyThre