[Jython-checkins] jython: Update lib-python to latest 2.7 revision 82552:a8047d1376d5
frank.wierzbicki
jython-checkins at python.org
Mon Mar 11 18:23:41 CET 2013
http://hg.python.org/jython/rev/f763cd15ee2b
changeset: 7074:f763cd15ee2b
parent: 7070:e80a189574d0
user: Frank Wierzbicki <fwierzbicki at gmail.com>
date: Fri Mar 08 16:17:33 2013 -0800
summary:
Update lib-python to latest 2.7 revision 82552:a8047d1376d5
files:
lib-python/2.7/BaseHTTPServer.py | 6 +-
lib-python/2.7/CGIHTTPServer.py | 61 +-
lib-python/2.7/Cookie.py | 4 +-
lib-python/2.7/HTMLParser.py | 6 +-
lib-python/2.7/SocketServer.py | 22 +-
lib-python/2.7/StringIO.py | 2 +-
lib-python/2.7/_LWPCookieJar.py | 4 +-
lib-python/2.7/__future__.py | 2 +-
lib-python/2.7/_pyio.py | 20 +-
lib-python/2.7/_strptime.py | 15 +-
lib-python/2.7/aifc.py | 38 +-
lib-python/2.7/argparse.py | 44 +-
lib-python/2.7/asyncore.py | 20 +-
lib-python/2.7/bdb.py | 15 +-
lib-python/2.7/calendar.py | 7 +-
lib-python/2.7/cgi.py | 1 -
lib-python/2.7/cgitb.py | 11 +-
lib-python/2.7/cmd.py | 1 +
lib-python/2.7/collections.py | 187 +-
lib-python/2.7/compiler/consts.py | 2 +-
lib-python/2.7/compiler/pycodegen.py | 4 +-
lib-python/2.7/compiler/symbols.py | 4 +-
lib-python/2.7/ctypes/test/test_bitfields.py | 20 +
lib-python/2.7/ctypes/test/test_numbers.py | 10 +
lib-python/2.7/ctypes/test/test_returnfuncptrs.py | 30 +
lib-python/2.7/ctypes/test/test_structures.py | 9 +
lib-python/2.7/ctypes/test/test_win32.py | 5 +-
lib-python/2.7/ctypes/util.py | 29 +
lib-python/2.7/curses/__init__.py | 2 +-
lib-python/2.7/decimal.py | 8 +-
lib-python/2.7/distutils/__init__.py | 2 +-
lib-python/2.7/distutils/ccompiler.py | 2 +
lib-python/2.7/distutils/command/check.py | 3 +
lib-python/2.7/distutils/config.py | 7 +-
lib-python/2.7/distutils/dir_util.py | 4 +
lib-python/2.7/distutils/sysconfig.py | 118 +-
lib-python/2.7/distutils/tests/test_build_ext.py | 5 +-
lib-python/2.7/distutils/tests/test_dir_util.py | 18 +
lib-python/2.7/distutils/tests/test_msvc9compiler.py | 2 +-
lib-python/2.7/distutils/tests/test_register.py | 33 +-
lib-python/2.7/distutils/tests/test_sdist.py | 7 +-
lib-python/2.7/distutils/tests/test_sysconfig.py | 29 +
lib-python/2.7/distutils/unixccompiler.py | 70 +-
lib-python/2.7/distutils/util.py | 96 +-
lib-python/2.7/doctest.py | 17 +-
lib-python/2.7/email/_parseaddr.py | 8 +-
lib-python/2.7/email/base64mime.py | 2 +-
lib-python/2.7/email/feedparser.py | 4 +-
lib-python/2.7/email/generator.py | 12 +-
lib-python/2.7/email/test/test_email.py | 29 +
lib-python/2.7/email/test/test_email_renamed.py | 32 +
lib-python/2.7/email/utils.py | 4 +-
lib-python/2.7/ftplib.py | 11 +-
lib-python/2.7/glob.py | 25 +-
lib-python/2.7/gzip.py | 81 +-
lib-python/2.7/hashlib.py | 2 +-
lib-python/2.7/heapq.py | 84 +-
lib-python/2.7/httplib.py | 25 +-
lib-python/2.7/idlelib/CallTips.py | 33 +-
lib-python/2.7/idlelib/ColorDelegator.py | 9 +-
lib-python/2.7/idlelib/EditorWindow.py | 56 +-
lib-python/2.7/idlelib/FormatParagraph.py | 3 +-
lib-python/2.7/idlelib/HyperParser.py | 5 +
lib-python/2.7/idlelib/IOBinding.py | 37 +-
lib-python/2.7/idlelib/NEWS.txt | 35 +-
lib-python/2.7/idlelib/OutputWindow.py | 6 +-
lib-python/2.7/idlelib/PyShell.py | 130 +-
lib-python/2.7/idlelib/ReplaceDialog.py | 30 +-
lib-python/2.7/idlelib/config-extensions.def | 2 +
lib-python/2.7/idlelib/configDialog.py | 18 +-
lib-python/2.7/idlelib/configHandler.py | 53 +-
lib-python/2.7/idlelib/help.txt | 24 +-
lib-python/2.7/idlelib/idlever.py | 2 +-
lib-python/2.7/idlelib/macosxSupport.py | 16 +-
lib-python/2.7/idlelib/run.py | 22 +-
lib-python/2.7/io.py | 11 +-
lib-python/2.7/json/__init__.py | 50 +-
lib-python/2.7/json/decoder.py | 17 +-
lib-python/2.7/json/encoder.py | 17 +-
lib-python/2.7/json/tests/test_decode.py | 9 +
lib-python/2.7/json/tests/test_dump.py | 9 +
lib-python/2.7/json/tests/test_fail.py | 24 +-
lib-python/2.7/json/tests/test_float.py | 15 +
lib-python/2.7/json/tests/test_pass1.py | 20 +-
lib-python/2.7/json/tool.py | 17 +-
lib-python/2.7/lib-tk/Tkinter.py | 74 +-
lib-python/2.7/lib-tk/test/test_ttk/test_functions.py | 40 +-
lib-python/2.7/lib-tk/test/test_ttk/test_widgets.py | 8 +
lib-python/2.7/lib-tk/tkSimpleDialog.py | 2 +-
lib-python/2.7/lib-tk/ttk.py | 126 +-
lib-python/2.7/lib2to3/fixer_util.py | 16 +-
lib-python/2.7/lib2to3/pgen2/driver.py | 17 +
lib-python/2.7/lib2to3/refactor.py | 2 +-
lib-python/2.7/lib2to3/tests/test_fixers.py | 12 +
lib-python/2.7/locale.py | 10 +-
lib-python/2.7/logging/__init__.py | 17 +-
lib-python/2.7/logging/handlers.py | 72 +-
lib-python/2.7/mailbox.py | 76 +-
lib-python/2.7/mimetypes.py | 3 +-
lib-python/2.7/multiprocessing/connection.py | 11 +-
lib-python/2.7/multiprocessing/dummy/__init__.py | 3 +-
lib-python/2.7/multiprocessing/forking.py | 20 +-
lib-python/2.7/multiprocessing/pool.py | 35 +-
lib-python/2.7/multiprocessing/process.py | 6 +-
lib-python/2.7/multiprocessing/util.py | 39 +-
lib-python/2.7/plat-generic/regen | 2 +-
lib-python/2.7/platform.py | 37 +-
lib-python/2.7/posixpath.py | 96 +-
lib-python/2.7/pstats.py | 10 +-
lib-python/2.7/py_compile.py | 2 +-
lib-python/2.7/pyclbr.py | 2 +
lib-python/2.7/pydoc.py | 7 +-
lib-python/2.7/random.py | 20 +-
lib-python/2.7/rfc822.py | 2 +-
lib-python/2.7/rlcompleter.py | 36 +-
lib-python/2.7/runpy.py | 2 +-
lib-python/2.7/shutil.py | 8 +-
lib-python/2.7/smtplib.py | 4 +-
lib-python/2.7/socket.py | 4 +-
lib-python/2.7/sqlite3/dbapi2.py | 4 +-
lib-python/2.7/sqlite3/dump.py | 9 +-
lib-python/2.7/sqlite3/test/dump.py | 23 +
lib-python/2.7/sqlite3/test/hooks.py | 19 +
lib-python/2.7/sqlite3/test/regression.py | 28 +-
lib-python/2.7/sqlite3/test/userfunctions.py | 60 +-
lib-python/2.7/sre_compile.py | 1 +
lib-python/2.7/sre_constants.py | 4 +-
lib-python/2.7/sre_parse.py | 19 +-
lib-python/2.7/ssl.py | 20 +-
lib-python/2.7/string.py | 8 +-
lib-python/2.7/subprocess.py | 55 +-
lib-python/2.7/sysconfig.py | 158 +--
lib-python/2.7/tarfile.py | 16 +-
lib-python/2.7/telnetlib.py | 130 ++
lib-python/2.7/tempfile.py | 43 +-
lib-python/2.7/test/keycert.pem | 59 +-
lib-python/2.7/test/pickletester.py | 35 +-
lib-python/2.7/test/regrtest.py | 8 +-
lib-python/2.7/test/script_helper.py | 8 +-
lib-python/2.7/test/sha256.pem | 233 ++--
lib-python/2.7/test/string_tests.py | 18 +
lib-python/2.7/test/subprocessdata/sigchild_ignore.py | 11 +-
lib-python/2.7/test/test_StringIO.py | 42 +
lib-python/2.7/test/test_aifc.py | 7 +
lib-python/2.7/test/test_argparse.py | 137 ++-
lib-python/2.7/test/test_array.py | 13 +
lib-python/2.7/test/test_ast.py | 6 +
lib-python/2.7/test/test_asyncore.py | 27 +-
lib-python/2.7/test/test_audioop.py | 405 +++++--
lib-python/2.7/test/test_bigmem.py | 8 +-
lib-python/2.7/test/test_bisect.py | 53 +-
lib-python/2.7/test/test_builtin.py | 6 +-
lib-python/2.7/test/test_bytes.py | 21 +
lib-python/2.7/test/test_bz2.py | 81 +-
lib-python/2.7/test/test_calendar.py | 26 +-
lib-python/2.7/test/test_capi.py | 56 +-
lib-python/2.7/test/test_cmd.py | 8 +-
lib-python/2.7/test/test_cmd_line.py | 38 +-
lib-python/2.7/test/test_cmd_line_script.py | 18 +-
lib-python/2.7/test/test_codeccallbacks.py | 6 +-
lib-python/2.7/test/test_codecs.py | 410 +++++++-
lib-python/2.7/test/test_codeop.py | 2 +-
lib-python/2.7/test/test_compile.py | 28 +
lib-python/2.7/test/test_cookie.py | 15 +-
lib-python/2.7/test/test_cpickle.py | 17 +-
lib-python/2.7/test/test_csv.py | 9 +
lib-python/2.7/test/test_decimal.py | 12 +
lib-python/2.7/test/test_deque.py | 16 +
lib-python/2.7/test/test_descr.py | 26 +-
lib-python/2.7/test/test_dict.py | 8 +
lib-python/2.7/test/test_dictcomps.py | 117 +-
lib-python/2.7/test/test_doctest.py | 29 +-
lib-python/2.7/test/test_docxmlrpc.py | 2 +-
lib-python/2.7/test/test_email.py | 2 +
lib-python/2.7/test/test_exceptions.py | 12 +
lib-python/2.7/test/test_fcntl.py | 21 +
lib-python/2.7/test/test_file2k.py | 147 ++-
lib-python/2.7/test/test_fileio.py | 49 +-
lib-python/2.7/test/test_format.py | 10 +
lib-python/2.7/test/test_functools.py | 21 +-
lib-python/2.7/test/test_gc.py | 69 +
lib-python/2.7/test/test_gdb.py | 75 +-
lib-python/2.7/test/test_generators.py | 3 +-
lib-python/2.7/test/test_genexps.py | 3 +-
lib-python/2.7/test/test_glob.py | 115 +-
lib-python/2.7/test/test_gzip.py | 25 +
lib-python/2.7/test/test_hashlib.py | 50 +-
lib-python/2.7/test/test_heapq.py | 26 +
lib-python/2.7/test/test_htmlparser.py | 10 +
lib-python/2.7/test/test_httplib.py | 69 +-
lib-python/2.7/test/test_httpservers.py | 76 +-
lib-python/2.7/test/test_imaplib.py | 2 +-
lib-python/2.7/test/test_import.py | 103 +-
lib-python/2.7/test/test_int.py | 63 +-
lib-python/2.7/test/test_io.py | 165 ++-
lib-python/2.7/test/test_iter.py | 15 +
lib-python/2.7/test/test_itertools.py | 6 +
lib-python/2.7/test/test_logging.py | 49 +-
lib-python/2.7/test/test_long.py | 6 +-
lib-python/2.7/test/test_mailbox.py | 208 ++-
lib-python/2.7/test/test_marshal.py | 51 +-
lib-python/2.7/test/test_memoryio.py | 16 +-
lib-python/2.7/test/test_minidom.py | 2 +-
lib-python/2.7/test/test_mmap.py | 20 +
lib-python/2.7/test/test_multiprocessing.py | 173 +++-
lib-python/2.7/test/test_mutex.py | 2 +-
lib-python/2.7/test/test_old_mailbox.py | 16 +-
lib-python/2.7/test/test_optparse.py | 7 +
lib-python/2.7/test/test_os.py | 16 +-
lib-python/2.7/test/test_parser.py | 61 +-
lib-python/2.7/test/test_pdb.py | 61 +-
lib-python/2.7/test/test_peepholer.py | 13 +-
lib-python/2.7/test/test_pickle.py | 20 +-
lib-python/2.7/test/test_poll.py | 10 +
lib-python/2.7/test/test_posix.py | 133 +-
lib-python/2.7/test/test_posixpath.py | 103 +-
lib-python/2.7/test/test_property.py | 4 +-
lib-python/2.7/test/test_pty.py | 2 +-
lib-python/2.7/test/test_pwd.py | 9 +
lib-python/2.7/test/test_pyclbr.py | 5 +
lib-python/2.7/test/test_pydoc.py | 43 +-
lib-python/2.7/test/test_pyexpat.py | 55 +-
lib-python/2.7/test/test_random.py | 56 +-
lib-python/2.7/test/test_re.py | 94 +
lib-python/2.7/test/test_readline.py | 4 +
lib-python/2.7/test/test_resource.py | 17 +
lib-python/2.7/test/test_sax.py | 166 ++-
lib-python/2.7/test/test_select.py | 9 +
lib-python/2.7/test/test_shutil.py | 30 +
lib-python/2.7/test/test_signal.py | 16 +-
lib-python/2.7/test/test_socket.py | 111 +-
lib-python/2.7/test/test_socketserver.py | 41 +-
lib-python/2.7/test/test_ssl.py | 50 +-
lib-python/2.7/test/test_str.py | 27 +
lib-python/2.7/test/test_strptime.py | 8 +
lib-python/2.7/test/test_struct.py | 26 +-
lib-python/2.7/test/test_subprocess.py | 82 +
lib-python/2.7/test/test_support.py | 152 ++-
lib-python/2.7/test/test_sys.py | 207 +--
lib-python/2.7/test/test_sys_settrace.py | 13 +-
lib-python/2.7/test/test_sysconfig.py | 9 +
lib-python/2.7/test/test_tarfile.py | 32 +-
lib-python/2.7/test/test_tcl.py | 22 +
lib-python/2.7/test/test_telnetlib.py | 92 +-
lib-python/2.7/test/test_tempfile.py | 87 +-
lib-python/2.7/test/test_textwrap.py | 62 +-
lib-python/2.7/test/test_thread.py | 23 +
lib-python/2.7/test/test_threading.py | 29 +
lib-python/2.7/test/test_time.py | 2 +-
lib-python/2.7/test/test_tokenize.py | 29 +
lib-python/2.7/test/test_tools.py | 339 ++++++-
lib-python/2.7/test/test_ucn.py | 23 +
lib-python/2.7/test/test_unicode.py | 27 +
lib-python/2.7/test/test_urllib.py | 21 +
lib-python/2.7/test/test_urllib2.py | 58 +-
lib-python/2.7/test/test_urllib2_localnet.py | 8 +
lib-python/2.7/test/test_urllib2net.py | 4 +-
lib-python/2.7/test/test_urlparse.py | 49 +
lib-python/2.7/test/test_uu.py | 4 +-
lib-python/2.7/test/test_weakref.py | 101 +-
lib-python/2.7/test/test_winreg.py | 45 +-
lib-python/2.7/test/test_winsound.py | 1 +
lib-python/2.7/test/test_wsgiref.py | 108 +-
lib-python/2.7/test/test_xml_etree.py | 20 +
lib-python/2.7/test/test_xrange.py | 75 +
lib-python/2.7/test/test_zipfile.py | 141 ++-
lib-python/2.7/test/test_zipimport_support.py | 26 +-
lib-python/2.7/test/test_zlib.py | 37 +
lib-python/2.7/test/testtar.tar | Bin
lib-python/2.7/textwrap.py | 12 +-
lib-python/2.7/threading.py | 7 +-
lib-python/2.7/tokenize.py | 14 +-
lib-python/2.7/traceback.py | 2 +-
lib-python/2.7/unittest/case.py | 17 +-
lib-python/2.7/unittest/main.py | 5 +-
lib-python/2.7/unittest/runner.py | 2 +-
lib-python/2.7/unittest/signals.py | 16 +-
lib-python/2.7/unittest/test/test_break.py | 32 +
lib-python/2.7/unittest/test/test_discovery.py | 14 +
lib-python/2.7/unittest/test/test_runner.py | 13 +
lib-python/2.7/unittest/test/test_skipping.py | 30 +
lib-python/2.7/urllib2.py | 11 +-
lib-python/2.7/urlparse.py | 33 +-
lib-python/2.7/wave.py | 12 +-
lib-python/2.7/wsgiref/handlers.py | 12 +-
lib-python/2.7/wsgiref/validate.py | 4 +-
lib-python/2.7/xml/dom/minidom.py | 5 +-
lib-python/2.7/xml/etree/ElementTree.py | 7 +-
lib-python/2.7/xml/sax/_exceptions.py | 6 +-
lib-python/2.7/xml/sax/expatreader.py | 5 +-
lib-python/2.7/xml/sax/saxutils.py | 114 +-
lib-python/2.7/xml/sax/xmlreader.py | 2 +-
lib-python/2.7/xmlrpclib.py | 2 +-
lib-python/2.7/zipfile.py | 551 +++++----
294 files changed, 8597 insertions(+), 2566 deletions(-)
diff --git a/lib-python/2.7/BaseHTTPServer.py b/lib-python/2.7/BaseHTTPServer.py
--- a/lib-python/2.7/BaseHTTPServer.py
+++ b/lib-python/2.7/BaseHTTPServer.py
@@ -447,13 +447,13 @@
specified as subsequent arguments (it's just like
printf!).
- The client host and current date/time are prefixed to
- every message.
+ The client ip address and current date/time are prefixed to every
+ message.
"""
sys.stderr.write("%s - - [%s] %s\n" %
- (self.address_string(),
+ (self.client_address[0],
self.log_date_time_string(),
format%args))
diff --git a/lib-python/2.7/CGIHTTPServer.py b/lib-python/2.7/CGIHTTPServer.py
--- a/lib-python/2.7/CGIHTTPServer.py
+++ b/lib-python/2.7/CGIHTTPServer.py
@@ -84,9 +84,11 @@
path begins with one of the strings in self.cgi_directories
(and the next character is a '/' or the end of the string).
"""
- splitpath = _url_collapse_path_split(self.path)
- if splitpath[0] in self.cgi_directories:
- self.cgi_info = splitpath
+ collapsed_path = _url_collapse_path(self.path)
+ dir_sep = collapsed_path.find('/', 1)
+ head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep+1:]
+ if head in self.cgi_directories:
+ self.cgi_info = head, tail
return True
return False
@@ -298,51 +300,46 @@
self.log_message("CGI script exited OK")
-# TODO(gregory.p.smith): Move this into an appropriate library.
-def _url_collapse_path_split(path):
+def _url_collapse_path(path):
"""
Given a URL path, remove extra '/'s and '.' path elements and collapse
- any '..' references.
+ any '..' references and returns a colllapsed path.
Implements something akin to RFC-2396 5.2 step 6 to parse relative paths.
+ The utility of this function is limited to is_cgi method and helps
+ preventing some security attacks.
Returns: A tuple of (head, tail) where tail is everything after the final /
and head is everything before it. Head will always start with a '/' and,
if it contains anything else, never have a trailing '/'.
Raises: IndexError if too many '..' occur within the path.
+
"""
# Similar to os.path.split(os.path.normpath(path)) but specific to URL
# path semantics rather than local operating system semantics.
- path_parts = []
- for part in path.split('/'):
- if part == '.':
- path_parts.append('')
- else:
- path_parts.append(part)
- # Filter out blank non trailing parts before consuming the '..'.
- path_parts = [part for part in path_parts[:-1] if part] + path_parts[-1:]
+ path_parts = path.split('/')
+ head_parts = []
+ for part in path_parts[:-1]:
+ if part == '..':
+ head_parts.pop() # IndexError if more '..' than prior parts
+ elif part and part != '.':
+ head_parts.append( part )
if path_parts:
- # Special case for CGI's for PATH_INFO
- if path.startswith('/cgi-bin') or path.startswith('/htbin'):
- tail_part = []
- while path_parts[-1] not in ('cgi-bin','htbin'):
- tail_part.insert(0,path_parts.pop())
- tail_part = "/".join(tail_part)
- else:
- tail_part = path_parts.pop()
+ tail_part = path_parts.pop()
+ if tail_part:
+ if tail_part == '..':
+ head_parts.pop()
+ tail_part = ''
+ elif tail_part == '.':
+ tail_part = ''
else:
tail_part = ''
- head_parts = []
- for part in path_parts:
- if part == '..':
- head_parts.pop()
- else:
- head_parts.append(part)
- if tail_part and tail_part == '..':
- head_parts.pop()
- tail_part = ''
- return ('/' + '/'.join(head_parts), tail_part)
+
+ splitpath = ('/' + '/'.join(head_parts), tail_part)
+ collapsed_path = "/".join(splitpath)
+
+ return collapsed_path
nobody = None
diff --git a/lib-python/2.7/Cookie.py b/lib-python/2.7/Cookie.py
--- a/lib-python/2.7/Cookie.py
+++ b/lib-python/2.7/Cookie.py
@@ -390,7 +390,7 @@
from time import gmtime, time
now = time()
year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
- return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
+ return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % \
(weekdayname[wd], day, monthname[month], year, hh, mm, ss)
@@ -539,7 +539,7 @@
r"(?P<val>" # Start of group 'val'
r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
r"|" # or
- r"\w{3},\s[\w\d-]{9,11}\s[\d:]{8}\sGMT" # Special case for "expires" attr
+ r"\w{3},\s[\s\w\d-]{9,11}\s[\d:]{8}\sGMT" # Special case for "expires" attr
r"|" # or
""+ _LegalCharsPatt +"*" # Any word or empty string
r")" # End of group 'val'
diff --git a/lib-python/2.7/HTMLParser.py b/lib-python/2.7/HTMLParser.py
--- a/lib-python/2.7/HTMLParser.py
+++ b/lib-python/2.7/HTMLParser.py
@@ -22,13 +22,13 @@
starttagopen = re.compile('<[a-zA-Z]')
piclose = re.compile('>')
commentclose = re.compile(r'--\s*>')
-tagfind = re.compile('[a-zA-Z][-.a-zA-Z0-9:_]*')
+tagfind = re.compile('([a-zA-Z][-.a-zA-Z0-9:_]*)(?:\s|/(?!>))*')
# see http://www.w3.org/TR/html5/tokenization.html#tag-open-state
# and http://www.w3.org/TR/html5/tokenization.html#tag-name-state
tagfind_tolerant = re.compile('[a-zA-Z][^\t\n\r\f />\x00]*')
attrfind = re.compile(
- r'[\s/]*((?<=[\'"\s/])[^\s/>][^\s/=>]*)(\s*=+\s*'
+ r'((?<=[\'"\s/])[^\s/>][^\s/=>]*)(\s*=+\s*'
r'(\'[^\']*\'|"[^"]*"|(?![\'"])[^>\s]*))?(?:\s|/(?!>))*')
locatestarttagend = re.compile(r"""
@@ -289,7 +289,7 @@
match = tagfind.match(rawdata, i+1)
assert match, 'unexpected call to parse_starttag()'
k = match.end()
- self.lasttag = tag = rawdata[i+1:k].lower()
+ self.lasttag = tag = match.group(1).lower()
while k < endpos:
m = attrfind.match(rawdata, k)
diff --git a/lib-python/2.7/SocketServer.py b/lib-python/2.7/SocketServer.py
--- a/lib-python/2.7/SocketServer.py
+++ b/lib-python/2.7/SocketServer.py
@@ -133,6 +133,7 @@
import select
import sys
import os
+import errno
try:
import threading
except ImportError:
@@ -147,6 +148,15 @@
"ThreadingUnixStreamServer",
"ThreadingUnixDatagramServer"])
+def _eintr_retry(func, *args):
+ """restart a system call interrupted by EINTR"""
+ while True:
+ try:
+ return func(*args)
+ except (OSError, select.error) as e:
+ if e.args[0] != errno.EINTR:
+ raise
+
class BaseServer:
"""Base class for server classes.
@@ -222,7 +232,8 @@
# connecting to the socket to wake this up instead of
# polling. Polling reduces our responsiveness to a
# shutdown request and wastes cpu at all other times.
- r, w, e = select.select([self], [], [], poll_interval)
+ r, w, e = _eintr_retry(select.select, [self], [], [],
+ poll_interval)
if self in r:
self._handle_request_noblock()
finally:
@@ -262,7 +273,7 @@
timeout = self.timeout
elif self.timeout is not None:
timeout = min(timeout, self.timeout)
- fd_sets = select.select([self], [], [], timeout)
+ fd_sets = _eintr_retry(select.select, [self], [], [], timeout)
if not fd_sets[0]:
self.handle_timeout()
return
@@ -690,7 +701,12 @@
def finish(self):
if not self.wfile.closed:
- self.wfile.flush()
+ try:
+ self.wfile.flush()
+ except socket.error:
+ # An final socket error may have occurred here, such as
+ # the local error ECONNABORTED.
+ pass
self.wfile.close()
self.rfile.close()
diff --git a/lib-python/2.7/StringIO.py b/lib-python/2.7/StringIO.py
--- a/lib-python/2.7/StringIO.py
+++ b/lib-python/2.7/StringIO.py
@@ -158,7 +158,7 @@
newpos = self.len
else:
newpos = i+1
- if length is not None and length > 0:
+ if length is not None and length >= 0:
if self.pos + length < newpos:
newpos = self.pos + length
r = self.buf[self.pos:newpos]
diff --git a/lib-python/2.7/_LWPCookieJar.py b/lib-python/2.7/_LWPCookieJar.py
--- a/lib-python/2.7/_LWPCookieJar.py
+++ b/lib-python/2.7/_LWPCookieJar.py
@@ -48,7 +48,7 @@
class LWPCookieJar(FileCookieJar):
"""
- The LWPCookieJar saves a sequence of"Set-Cookie3" lines.
+ The LWPCookieJar saves a sequence of "Set-Cookie3" lines.
"Set-Cookie3" is the format used by the libwww-perl libary, not known
to be compatible with any browser, but which is easy to read and
doesn't lose information about RFC 2965 cookies.
@@ -60,7 +60,7 @@
"""
def as_lwp_str(self, ignore_discard=True, ignore_expires=True):
- """Return cookies as a string of "\n"-separated "Set-Cookie3" headers.
+ """Return cookies as a string of "\\n"-separated "Set-Cookie3" headers.
ignore_discard and ignore_expires: see docstring for FileCookieJar.save
diff --git a/lib-python/2.7/__future__.py b/lib-python/2.7/__future__.py
--- a/lib-python/2.7/__future__.py
+++ b/lib-python/2.7/__future__.py
@@ -112,7 +112,7 @@
CO_FUTURE_DIVISION)
absolute_import = _Feature((2, 5, 0, "alpha", 1),
- (2, 7, 0, "alpha", 0),
+ (3, 0, 0, "alpha", 0),
CO_FUTURE_ABSOLUTE_IMPORT)
with_statement = _Feature((2, 5, 0, "alpha", 1),
diff --git a/lib-python/2.7/_pyio.py b/lib-python/2.7/_pyio.py
--- a/lib-python/2.7/_pyio.py
+++ b/lib-python/2.7/_pyio.py
@@ -340,8 +340,10 @@
This method has no effect if the file is already closed.
"""
if not self.__closed:
- self.flush()
- self.__closed = True
+ try:
+ self.flush()
+ finally:
+ self.__closed = True
def __del__(self):
"""Destructor. Calls close()."""
@@ -883,12 +885,18 @@
return pos
def readable(self):
+ if self.closed:
+ raise ValueError("I/O operation on closed file.")
return True
def writable(self):
+ if self.closed:
+ raise ValueError("I/O operation on closed file.")
return True
def seekable(self):
+ if self.closed:
+ raise ValueError("I/O operation on closed file.")
return True
@@ -1546,6 +1554,8 @@
return self._buffer
def seekable(self):
+ if self.closed:
+ raise ValueError("I/O operation on closed file.")
return self._seekable
def readable(self):
@@ -1560,8 +1570,10 @@
def close(self):
if self.buffer is not None and not self.closed:
- self.flush()
- self.buffer.close()
+ try:
+ self.flush()
+ finally:
+ self.buffer.close()
@property
def closed(self):
diff --git a/lib-python/2.7/_strptime.py b/lib-python/2.7/_strptime.py
--- a/lib-python/2.7/_strptime.py
+++ b/lib-python/2.7/_strptime.py
@@ -326,7 +326,8 @@
if len(data_string) != found.end():
raise ValueError("unconverted data remains: %s" %
data_string[found.end():])
- year = 1900
+
+ year = None
month = day = 1
hour = minute = second = fraction = 0
tz = -1
@@ -425,6 +426,12 @@
else:
tz = value
break
+ leap_year_fix = False
+ if year is None and month == 2 and day == 29:
+ year = 1904 # 1904 is first leap year of 20th century
+ leap_year_fix = True
+ elif year is None:
+ year = 1900
# If we know the week of the year and what day of that week, we can figure
# out the Julian day of the year.
if julian == -1 and week_of_year != -1 and weekday != -1:
@@ -446,6 +453,12 @@
day = datetime_result.day
if weekday == -1:
weekday = datetime_date(year, month, day).weekday()
+ if leap_year_fix:
+ # the caller didn't supply a year but asked for Feb 29th. We couldn't
+ # use the default of 1900 for computations. We set it back to ensure
+ # that February 29th is smaller than March 1st.
+ year = 1900
+
return (time.struct_time((year, month, day,
hour, minute, second,
weekday, julian, tz)), fraction)
diff --git a/lib-python/2.7/aifc.py b/lib-python/2.7/aifc.py
--- a/lib-python/2.7/aifc.py
+++ b/lib-python/2.7/aifc.py
@@ -732,22 +732,28 @@
self._patchheader()
def close(self):
- self._ensure_header_written(0)
- if self._datawritten & 1:
- # quick pad to even size
- self._file.write(chr(0))
- self._datawritten = self._datawritten + 1
- self._writemarkers()
- if self._nframeswritten != self._nframes or \
- self._datalength != self._datawritten or \
- self._marklength:
- self._patchheader()
- if self._comp:
- self._comp.CloseCompressor()
- self._comp = None
- # Prevent ref cycles
- self._convert = None
- self._file.close()
+ if self._file is None:
+ return
+ try:
+ self._ensure_header_written(0)
+ if self._datawritten & 1:
+ # quick pad to even size
+ self._file.write(chr(0))
+ self._datawritten = self._datawritten + 1
+ self._writemarkers()
+ if self._nframeswritten != self._nframes or \
+ self._datalength != self._datawritten or \
+ self._marklength:
+ self._patchheader()
+ if self._comp:
+ self._comp.CloseCompressor()
+ self._comp = None
+ finally:
+ # Prevent ref cycles
+ self._convert = None
+ f = self._file
+ self._file = None
+ f.close()
#
# Internal methods.
diff --git a/lib-python/2.7/argparse.py b/lib-python/2.7/argparse.py
--- a/lib-python/2.7/argparse.py
+++ b/lib-python/2.7/argparse.py
@@ -740,10 +740,10 @@
- default -- The value to be produced if the option is not specified.
- - type -- The type which the command-line arguments should be converted
- to, should be one of 'string', 'int', 'float', 'complex' or a
- callable object that accepts a single string argument. If None,
- 'string' is assumed.
+ - type -- A callable that accepts a single string argument, and
+ returns the converted value. The standard Python types str, int,
+ float, and complex are useful examples of such callables. If None,
+ str is used.
- choices -- A container of values that should be allowed. If not None,
after a command-line argument has been converted to the appropriate
@@ -1692,9 +1692,12 @@
return args
def parse_known_args(self, args=None, namespace=None):
- # args default to the system args
if args is None:
+ # args default to the system args
args = _sys.argv[1:]
+ else:
+ # make sure that args are mutable
+ args = list(args)
# default Namespace built from parser defaults
if namespace is None:
@@ -1705,10 +1708,7 @@
if action.dest is not SUPPRESS:
if not hasattr(namespace, action.dest):
if action.default is not SUPPRESS:
- default = action.default
- if isinstance(action.default, basestring):
- default = self._get_value(action, default)
- setattr(namespace, action.dest, default)
+ setattr(namespace, action.dest, action.default)
# add any parser defaults that aren't present
for dest in self._defaults:
@@ -1936,12 +1936,23 @@
if positionals:
self.error(_('too few arguments'))
- # make sure all required actions were present
+ # make sure all required actions were present, and convert defaults.
for action in self._actions:
- if action.required:
- if action not in seen_actions:
+ if action not in seen_actions:
+ if action.required:
name = _get_action_name(action)
self.error(_('argument %s is required') % name)
+ else:
+ # Convert action default now instead of doing it before
+ # parsing arguments to avoid calling convert functions
+ # twice (which may fail) if the argument was given, but
+ # only if it was defined already in the namespace
+ if (action.default is not None and
+ isinstance(action.default, basestring) and
+ hasattr(namespace, action.dest) and
+ action.default is getattr(namespace, action.dest)):
+ setattr(namespace, action.dest,
+ self._get_value(action, action.default))
# make sure all required groups had one option present
for group in self._mutually_exclusive_groups:
@@ -1967,7 +1978,7 @@
for arg_string in arg_strings:
# for regular arguments, just add them back into the list
- if arg_string[0] not in self.fromfile_prefix_chars:
+ if not arg_string or arg_string[0] not in self.fromfile_prefix_chars:
new_arg_strings.append(arg_string)
# replace arguments referencing files with the file content
@@ -2174,9 +2185,12 @@
# Value conversion methods
# ========================
def _get_values(self, action, arg_strings):
- # for everything but PARSER args, strip out '--'
+ # for everything but PARSER, REMAINDER args, strip out first '--'
if action.nargs not in [PARSER, REMAINDER]:
- arg_strings = [s for s in arg_strings if s != '--']
+ try:
+ arg_strings.remove('--')
+ except ValueError:
+ pass
# optional argument produces a default when not present
if not arg_strings and action.nargs == OPTIONAL:
diff --git a/lib-python/2.7/asyncore.py b/lib-python/2.7/asyncore.py
--- a/lib-python/2.7/asyncore.py
+++ b/lib-python/2.7/asyncore.py
@@ -225,6 +225,7 @@
debug = False
connected = False
accepting = False
+ connecting = False
closing = False
addr = None
ignore_log_types = frozenset(['warning'])
@@ -248,7 +249,7 @@
try:
self.addr = sock.getpeername()
except socket.error, err:
- if err.args[0] == ENOTCONN:
+ if err.args[0] in (ENOTCONN, EINVAL):
# To handle the case where we got an unconnected
# socket.
self.connected = False
@@ -342,9 +343,11 @@
def connect(self, address):
self.connected = False
+ self.connecting = True
err = self.socket.connect_ex(address)
if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \
or err == EINVAL and os.name in ('nt', 'ce'):
+ self.addr = address
return
if err in (0, EISCONN):
self.addr = address
@@ -390,7 +393,7 @@
else:
return data
except socket.error, why:
- # winsock sometimes throws ENOTCONN
+ # winsock sometimes raises ENOTCONN
if why.args[0] in _DISCONNECTED:
self.handle_close()
return ''
@@ -400,6 +403,7 @@
def close(self):
self.connected = False
self.accepting = False
+ self.connecting = False
self.del_channel()
try:
self.socket.close()
@@ -438,7 +442,8 @@
# sockets that are connected
self.handle_accept()
elif not self.connected:
- self.handle_connect_event()
+ if self.connecting:
+ self.handle_connect_event()
self.handle_read()
else:
self.handle_read()
@@ -449,6 +454,7 @@
raise socket.error(err, _strerror(err))
self.handle_connect()
self.connected = True
+ self.connecting = False
def handle_write_event(self):
if self.accepting:
@@ -457,12 +463,8 @@
return
if not self.connected:
- #check for errors
- err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
- if err != 0:
- raise socket.error(err, _strerror(err))
-
- self.handle_connect_event()
+ if self.connecting:
+ self.handle_connect_event()
self.handle_write()
def handle_expt_event(self):
diff --git a/lib-python/2.7/bdb.py b/lib-python/2.7/bdb.py
--- a/lib-python/2.7/bdb.py
+++ b/lib-python/2.7/bdb.py
@@ -24,6 +24,7 @@
self.skip = set(skip) if skip else None
self.breaks = {}
self.fncache = {}
+ self.frame_returning = None
def canonic(self, filename):
if filename == "<" + filename[1:-1] + ">":
@@ -82,7 +83,11 @@
def dispatch_return(self, frame, arg):
if self.stop_here(frame) or frame == self.returnframe:
- self.user_return(frame, arg)
+ try:
+ self.frame_returning = frame
+ self.user_return(frame, arg)
+ finally:
+ self.frame_returning = None
if self.quitting: raise BdbQuit
return self.trace_dispatch
@@ -186,6 +191,14 @@
def set_step(self):
"""Stop after one line of code."""
+ # Issue #13183: pdb skips frames after hitting a breakpoint and running
+ # step commands.
+ # Restore the trace function in the caller (that may not have been set
+ # for performance reasons) when returning from the current frame.
+ if self.frame_returning:
+ caller_frame = self.frame_returning.f_back
+ if caller_frame and not caller_frame.f_trace:
+ caller_frame.f_trace = self.trace_dispatch
self._set_stopinfo(None, None)
def set_next(self, frame):
diff --git a/lib-python/2.7/calendar.py b/lib-python/2.7/calendar.py
--- a/lib-python/2.7/calendar.py
+++ b/lib-python/2.7/calendar.py
@@ -161,7 +161,11 @@
oneday = datetime.timedelta(days=1)
while True:
yield date
- date += oneday
+ try:
+ date += oneday
+ except OverflowError:
+ # Adding one day could fail after datetime.MAXYEAR
+ break
if date.month != month and date.weekday() == self.firstweekday:
break
@@ -488,6 +492,7 @@
def __enter__(self):
self.oldlocale = _locale.getlocale(_locale.LC_TIME)
_locale.setlocale(_locale.LC_TIME, self.locale)
+ return _locale.getlocale(_locale.LC_TIME)[1]
def __exit__(self, *args):
_locale.setlocale(_locale.LC_TIME, self.oldlocale)
diff --git a/lib-python/2.7/cgi.py b/lib-python/2.7/cgi.py
--- a/lib-python/2.7/cgi.py
+++ b/lib-python/2.7/cgi.py
@@ -37,7 +37,6 @@
from operator import attrgetter
import sys
import os
-import urllib
import UserDict
import urlparse
diff --git a/lib-python/2.7/cgitb.py b/lib-python/2.7/cgitb.py
--- a/lib-python/2.7/cgitb.py
+++ b/lib-python/2.7/cgitb.py
@@ -295,14 +295,19 @@
if self.logdir is not None:
suffix = ['.txt', '.html'][self.format=="html"]
(fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir)
+
try:
file = os.fdopen(fd, 'w')
file.write(doc)
file.close()
- msg = '<p> %s contains the description of this error.' % path
+ msg = '%s contains the description of this error.' % path
except:
- msg = '<p> Tried to save traceback to %s, but failed.' % path
- self.file.write(msg + '\n')
+ msg = 'Tried to save traceback to %s, but failed.' % path
+
+ if self.format == 'html':
+ self.file.write('<p>%s</p>\n' % msg)
+ else:
+ self.file.write(msg + '\n')
try:
self.file.flush()
except: pass
diff --git a/lib-python/2.7/cmd.py b/lib-python/2.7/cmd.py
--- a/lib-python/2.7/cmd.py
+++ b/lib-python/2.7/cmd.py
@@ -294,6 +294,7 @@
return list(commands | topics)
def do_help(self, arg):
+ 'List available commands with "help" or detailed help with "help cmd".'
if arg:
# XXX check arg syntax
try:
diff --git a/lib-python/2.7/collections.py b/lib-python/2.7/collections.py
--- a/lib-python/2.7/collections.py
+++ b/lib-python/2.7/collections.py
@@ -6,11 +6,12 @@
__all__ += _abcoll.__all__
from _collections import deque, defaultdict
-from operator import itemgetter as _itemgetter
+from operator import itemgetter as _itemgetter, eq as _eq
from keyword import iskeyword as _iskeyword
import sys as _sys
import heapq as _heapq
from itertools import repeat as _repeat, chain as _chain, starmap as _starmap
+from itertools import imap as _imap
try:
from thread import get_ident as _get_ident
@@ -50,49 +51,45 @@
self.__map = {}
self.__update(*args, **kwds)
- def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__):
+ def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link at the end of the linked list,
# and the inherited dictionary is updated with the new key/value pair.
if key not in self:
root = self.__root
- last = root[PREV]
- last[NEXT] = root[PREV] = self.__map[key] = [last, root, key]
- dict_setitem(self, key, value)
+ last = root[0]
+ last[1] = root[0] = self.__map[key] = [last, root, key]
+ return dict_setitem(self, key, value)
- def __delitem__(self, key, PREV=0, NEXT=1, dict_delitem=dict.__delitem__):
+ def __delitem__(self, key, dict_delitem=dict.__delitem__):
'od.__delitem__(y) <==> del od[y]'
# Deleting an existing item uses self.__map to find the link which gets
# removed by updating the links in the predecessor and successor nodes.
dict_delitem(self, key)
link_prev, link_next, key = self.__map.pop(key)
- link_prev[NEXT] = link_next
- link_next[PREV] = link_prev
+ link_prev[1] = link_next # update link_prev[NEXT]
+ link_next[0] = link_prev # update link_next[PREV]
def __iter__(self):
'od.__iter__() <==> iter(od)'
# Traverse the linked list in order.
- NEXT, KEY = 1, 2
root = self.__root
- curr = root[NEXT]
+ curr = root[1] # start at the first node
while curr is not root:
- yield curr[KEY]
- curr = curr[NEXT]
+ yield curr[2] # yield the curr[KEY]
+ curr = curr[1] # move to next node
def __reversed__(self):
'od.__reversed__() <==> reversed(od)'
# Traverse the linked list in reverse order.
- PREV, KEY = 0, 2
root = self.__root
- curr = root[PREV]
+ curr = root[0] # start at the last node
while curr is not root:
- yield curr[KEY]
- curr = curr[PREV]
+ yield curr[2] # yield the curr[KEY]
+ curr = curr[0] # move to previous node
def clear(self):
'od.clear() -> None. Remove all items from od.'
- for node in self.__map.itervalues():
- del node[:]
root = self.__root
root[:] = [root, root, None]
self.__map.clear()
@@ -208,7 +205,7 @@
'''
if isinstance(other, OrderedDict):
- return len(self)==len(other) and self.items() == other.items()
+ return dict.__eq__(self, other) and all(_imap(_eq, self, other))
return dict.__eq__(self, other)
def __ne__(self, other):
@@ -234,10 +231,60 @@
### namedtuple
################################################################################
+_class_template = '''\
+class {typename}(tuple):
+ '{typename}({arg_list})'
+
+ __slots__ = ()
+
+ _fields = {field_names!r}
+
+ def __new__(_cls, {arg_list}):
+ 'Create new instance of {typename}({arg_list})'
+ return _tuple.__new__(_cls, ({arg_list}))
+
+ @classmethod
+ def _make(cls, iterable, new=tuple.__new__, len=len):
+ 'Make a new {typename} object from a sequence or iterable'
+ result = new(cls, iterable)
+ if len(result) != {num_fields:d}:
+ raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result))
+ return result
+
+ def __repr__(self):
+ 'Return a nicely formatted representation string'
+ return '{typename}({repr_fmt})' % self
+
+ def _asdict(self):
+ 'Return a new OrderedDict which maps field names to their values'
+ return OrderedDict(zip(self._fields, self))
+
+ __dict__ = property(_asdict)
+
+ def _replace(_self, **kwds):
+ 'Return a new {typename} object replacing specified fields with new values'
+ result = _self._make(map(kwds.pop, {field_names!r}, _self))
+ if kwds:
+ raise ValueError('Got unexpected field names: %r' % kwds.keys())
+ return result
+
+ def __getnewargs__(self):
+ 'Return self as a plain tuple. Used by copy and pickle.'
+ return tuple(self)
+
+{field_defs}
+'''
+
+_repr_template = '{name}=%r'
+
+_field_template = '''\
+ {name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}')
+'''
+
def namedtuple(typename, field_names, verbose=False, rename=False):
"""Returns a new subclass of tuple with named fields.
- >>> Point = namedtuple('Point', 'x y')
+ >>> Point = namedtuple('Point', ['x', 'y'])
>>> Point.__doc__ # docstring for the new class
'Point(x, y)'
>>> p = Point(11, y=22) # instantiate with positional args or keywords
@@ -258,83 +305,63 @@
"""
- # Parse and validate the field names. Validation serves two purposes,
- # generating informative error messages and preventing template injection attacks.
+ # Validate the field names. At the user's option, either generate an error
+ # message or automatically replace the field name with a valid name.
if isinstance(field_names, basestring):
- field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas
- field_names = tuple(map(str, field_names))
+ field_names = field_names.replace(',', ' ').split()
+ field_names = map(str, field_names)
if rename:
- names = list(field_names)
seen = set()
- for i, name in enumerate(names):
- if (not all(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
- or not name or name[0].isdigit() or name.startswith('_')
+ for index, name in enumerate(field_names):
+ if (not all(c.isalnum() or c=='_' for c in name)
+ or _iskeyword(name)
+ or not name
+ or name[0].isdigit()
+ or name.startswith('_')
or name in seen):
- names[i] = '_%d' % i
+ field_names[index] = '_%d' % index
seen.add(name)
- field_names = tuple(names)
- for name in (typename,) + field_names:
+ for name in [typename] + field_names:
if not all(c.isalnum() or c=='_' for c in name):
- raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
+ raise ValueError('Type names and field names can only contain '
+ 'alphanumeric characters and underscores: %r' % name)
if _iskeyword(name):
- raise ValueError('Type names and field names cannot be a keyword: %r' % name)
+ raise ValueError('Type names and field names cannot be a '
+ 'keyword: %r' % name)
if name[0].isdigit():
- raise ValueError('Type names and field names cannot start with a number: %r' % name)
- seen_names = set()
+ raise ValueError('Type names and field names cannot start with '
+ 'a number: %r' % name)
+ seen = set()
for name in field_names:
if name.startswith('_') and not rename:
- raise ValueError('Field names cannot start with an underscore: %r' % name)
- if name in seen_names:
+ raise ValueError('Field names cannot start with an underscore: '
+ '%r' % name)
+ if name in seen:
raise ValueError('Encountered duplicate field name: %r' % name)
- seen_names.add(name)
+ seen.add(name)
- # Create and fill-in the class template
- numfields = len(field_names)
- argtxt = repr(field_names).replace("'", "")[1:-1] # tuple repr without parens or quotes
- reprtxt = ', '.join('%s=%%r' % name for name in field_names)
- template = '''class %(typename)s(tuple):
- '%(typename)s(%(argtxt)s)' \n
- __slots__ = () \n
- _fields = %(field_names)r \n
- def __new__(_cls, %(argtxt)s):
- 'Create new instance of %(typename)s(%(argtxt)s)'
- return _tuple.__new__(_cls, (%(argtxt)s)) \n
- @classmethod
- def _make(cls, iterable, new=tuple.__new__, len=len):
- 'Make a new %(typename)s object from a sequence or iterable'
- result = new(cls, iterable)
- if len(result) != %(numfields)d:
- raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
- return result \n
- def __repr__(self):
- 'Return a nicely formatted representation string'
- return '%(typename)s(%(reprtxt)s)' %% self \n
- def _asdict(self):
- 'Return a new OrderedDict which maps field names to their values'
- return OrderedDict(zip(self._fields, self)) \n
- __dict__ = property(_asdict) \n
- def _replace(_self, **kwds):
- 'Return a new %(typename)s object replacing specified fields with new values'
- result = _self._make(map(kwds.pop, %(field_names)r, _self))
- if kwds:
- raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
- return result \n
- def __getnewargs__(self):
- 'Return self as a plain tuple. Used by copy and pickle.'
- return tuple(self) \n\n''' % locals()
- for i, name in enumerate(field_names):
- template += " %s = _property(_itemgetter(%d), doc='Alias for field number %d')\n" % (name, i, i)
+ # Fill-in the class template
+ class_definition = _class_template.format(
+ typename = typename,
+ field_names = tuple(field_names),
+ num_fields = len(field_names),
+ arg_list = repr(tuple(field_names)).replace("'", "")[1:-1],
+ repr_fmt = ', '.join(_repr_template.format(name=name)
+ for name in field_names),
+ field_defs = '\n'.join(_field_template.format(index=index, name=name)
+ for index, name in enumerate(field_names))
+ )
if verbose:
- print template
+ print class_definition
- # Execute the template string in a temporary namespace and
- # support tracing utilities by setting a value for frame.f_globals['__name__']
+ # Execute the template string in a temporary namespace and support
+ # tracing utilities by setting a value for frame.f_globals['__name__']
namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
OrderedDict=OrderedDict, _property=property, _tuple=tuple)
try:
- exec template in namespace
- except SyntaxError, e:
- raise SyntaxError(e.message + ':\n' + template)
+ exec class_definition in namespace
+ except SyntaxError as e:
+ raise SyntaxError(e.message + ':\n' + class_definition)
result = namespace[typename]
# For pickling to work, the __module__ variable needs to be set to the frame
diff --git a/lib-python/2.7/compiler/consts.py b/lib-python/2.7/compiler/consts.py
--- a/lib-python/2.7/compiler/consts.py
+++ b/lib-python/2.7/compiler/consts.py
@@ -5,7 +5,7 @@
SC_LOCAL = 1
SC_GLOBAL_IMPLICIT = 2
-SC_GLOBAL_EXPLICT = 3
+SC_GLOBAL_EXPLICIT = 3
SC_FREE = 4
SC_CELL = 5
SC_UNKNOWN = 6
diff --git a/lib-python/2.7/compiler/pycodegen.py b/lib-python/2.7/compiler/pycodegen.py
--- a/lib-python/2.7/compiler/pycodegen.py
+++ b/lib-python/2.7/compiler/pycodegen.py
@@ -7,7 +7,7 @@
from compiler import ast, parse, walk, syntax
from compiler import pyassem, misc, future, symbols
-from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICT, \
+from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICIT, \
SC_FREE, SC_CELL
from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,
CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION,
@@ -283,7 +283,7 @@
self.emit(prefix + '_NAME', name)
else:
self.emit(prefix + '_FAST', name)
- elif scope == SC_GLOBAL_EXPLICT:
+ elif scope == SC_GLOBAL_EXPLICIT:
self.emit(prefix + '_GLOBAL', name)
elif scope == SC_GLOBAL_IMPLICIT:
if not self.optimized:
diff --git a/lib-python/2.7/compiler/symbols.py b/lib-python/2.7/compiler/symbols.py
--- a/lib-python/2.7/compiler/symbols.py
+++ b/lib-python/2.7/compiler/symbols.py
@@ -1,7 +1,7 @@
"""Module symbol-table generator"""
from compiler import ast
-from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICT, \
+from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICIT, \
SC_FREE, SC_CELL, SC_UNKNOWN
from compiler.misc import mangle
import types
@@ -90,7 +90,7 @@
The scope of a name could be LOCAL, GLOBAL, FREE, or CELL.
"""
if name in self.globals:
- return SC_GLOBAL_EXPLICT
+ return SC_GLOBAL_EXPLICIT
if name in self.cells:
return SC_CELL
if name in self.defs:
diff --git a/lib-python/2.7/ctypes/test/test_bitfields.py b/lib-python/2.7/ctypes/test/test_bitfields.py
--- a/lib-python/2.7/ctypes/test/test_bitfields.py
+++ b/lib-python/2.7/ctypes/test/test_bitfields.py
@@ -240,5 +240,25 @@
_anonymous_ = ["_"]
_fields_ = [("_", X)]
+ @unittest.skipUnless(hasattr(ctypes, "c_uint32"), "c_int32 is required")
+ def test_uint32(self):
+ class X(Structure):
+ _fields_ = [("a", c_uint32, 32)]
+ x = X()
+ x.a = 10
+ self.assertEqual(x.a, 10)
+ x.a = 0xFDCBA987
+ self.assertEqual(x.a, 0xFDCBA987)
+
+ @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required")
+ def test_uint64(self):
+ class X(Structure):
+ _fields_ = [("a", c_uint64, 64)]
+ x = X()
+ x.a = 10
+ self.assertEqual(x.a, 10)
+ x.a = 0xFEDCBA9876543211
+ self.assertEqual(x.a, 0xFEDCBA9876543211)
+
if __name__ == "__main__":
unittest.main()
diff --git a/lib-python/2.7/ctypes/test/test_numbers.py b/lib-python/2.7/ctypes/test/test_numbers.py
--- a/lib-python/2.7/ctypes/test/test_numbers.py
+++ b/lib-python/2.7/ctypes/test/test_numbers.py
@@ -216,6 +216,16 @@
# probably be changed:
self.assertRaises(TypeError, c_int, c_long(42))
+ def test_float_overflow(self):
+ import sys
+ big_int = int(sys.float_info.max) * 2
+ for t in float_types + [c_longdouble]:
+ self.assertRaises(OverflowError, t, big_int)
+ if (hasattr(t, "__ctype_be__")):
+ self.assertRaises(OverflowError, t.__ctype_be__, big_int)
+ if (hasattr(t, "__ctype_le__")):
+ self.assertRaises(OverflowError, t.__ctype_le__, big_int)
+
## def test_perf(self):
## check_perf()
diff --git a/lib-python/2.7/ctypes/test/test_returnfuncptrs.py b/lib-python/2.7/ctypes/test/test_returnfuncptrs.py
--- a/lib-python/2.7/ctypes/test/test_returnfuncptrs.py
+++ b/lib-python/2.7/ctypes/test/test_returnfuncptrs.py
@@ -1,5 +1,6 @@
import unittest
from ctypes import *
+import os
import _ctypes_test
@@ -31,5 +32,34 @@
self.assertRaises(ArgumentError, strchr, "abcdef", 3)
self.assertRaises(TypeError, strchr, "abcdef")
+ def test_from_dll(self):
+ dll = CDLL(_ctypes_test.__file__)
+ # _CFuncPtr instances are now callable with a tuple argument
+ # which denotes a function name and a dll:
+ strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(("my_strchr", dll))
+ self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
+ self.assertEqual(strchr(b"abcdef", b"x"), None)
+ self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
+ self.assertRaises(TypeError, strchr, b"abcdef")
+
+ # Issue 6083: Reference counting bug
+ def test_from_dll_refcount(self):
+ class BadSequence(tuple):
+ def __getitem__(self, key):
+ if key == 0:
+ return "my_strchr"
+ if key == 1:
+ return CDLL(_ctypes_test.__file__)
+ raise IndexError
+
+ # _CFuncPtr instances are now callable with a tuple argument
+ # which denotes a function name and a dll:
+ strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(
+ BadSequence(("my_strchr", CDLL(_ctypes_test.__file__))))
+ self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
+ self.assertEqual(strchr(b"abcdef", b"x"), None)
+ self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
+ self.assertRaises(TypeError, strchr, b"abcdef")
+
if __name__ == "__main__":
unittest.main()
diff --git a/lib-python/2.7/ctypes/test/test_structures.py b/lib-python/2.7/ctypes/test/test_structures.py
--- a/lib-python/2.7/ctypes/test/test_structures.py
+++ b/lib-python/2.7/ctypes/test/test_structures.py
@@ -1,6 +1,7 @@
import unittest
from ctypes import *
from struct import calcsize
+import _testcapi
class SubclassesTest(unittest.TestCase):
def test_subclass(self):
@@ -199,6 +200,14 @@
"_pack_": -1}
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
+ # Issue 15989
+ d = {"_fields_": [("a", c_byte)],
+ "_pack_": _testcapi.INT_MAX + 1}
+ self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
+ d = {"_fields_": [("a", c_byte)],
+ "_pack_": _testcapi.UINT_MAX + 2}
+ self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
+
def test_initializers(self):
class Person(Structure):
_fields_ = [("name", c_char*6),
diff --git a/lib-python/2.7/ctypes/test/test_win32.py b/lib-python/2.7/ctypes/test/test_win32.py
--- a/lib-python/2.7/ctypes/test/test_win32.py
+++ b/lib-python/2.7/ctypes/test/test_win32.py
@@ -3,6 +3,7 @@
from ctypes import *
from ctypes.test import is_resource_enabled
import unittest, sys
+from test import test_support as support
import _ctypes_test
@@ -60,7 +61,9 @@
def test_COMError(self):
from _ctypes import COMError
- self.assertEqual(COMError.__doc__, "Raised when a COM method call failed.")
+ if support.HAVE_DOCSTRINGS:
+ self.assertEqual(COMError.__doc__,
+ "Raised when a COM method call failed.")
ex = COMError(-1, "text", ("details",))
self.assertEqual(ex.hresult, -1)
diff --git a/lib-python/2.7/ctypes/util.py b/lib-python/2.7/ctypes/util.py
--- a/lib-python/2.7/ctypes/util.py
+++ b/lib-python/2.7/ctypes/util.py
@@ -180,6 +180,35 @@
res.sort(cmp= lambda x,y: cmp(_num_version(x), _num_version(y)))
return res[-1]
+ elif sys.platform == "sunos5":
+
+ def _findLib_crle(name, is64):
+ if not os.path.exists('/usr/bin/crle'):
+ return None
+
+ if is64:
+ cmd = 'env LC_ALL=C /usr/bin/crle -64 2>/dev/null'
+ else:
+ cmd = 'env LC_ALL=C /usr/bin/crle 2>/dev/null'
+
+ for line in os.popen(cmd).readlines():
+ line = line.strip()
+ if line.startswith('Default Library Path (ELF):'):
+ paths = line.split()[4]
+
+ if not paths:
+ return None
+
+ for dir in paths.split(":"):
+ libfile = os.path.join(dir, "lib%s.so" % name)
+ if os.path.exists(libfile):
+ return libfile
+
+ return None
+
+ def find_library(name, is64 = False):
+ return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name))
+
else:
def _findSoname_ldconfig(name):
diff --git a/lib-python/2.7/curses/__init__.py b/lib-python/2.7/curses/__init__.py
--- a/lib-python/2.7/curses/__init__.py
+++ b/lib-python/2.7/curses/__init__.py
@@ -5,7 +5,7 @@
import curses
from curses import textpad
- curses.initwin()
+ curses.initscr()
...
"""
diff --git a/lib-python/2.7/decimal.py b/lib-python/2.7/decimal.py
--- a/lib-python/2.7/decimal.py
+++ b/lib-python/2.7/decimal.py
@@ -1581,7 +1581,13 @@
def __float__(self):
"""Float representation."""
- return float(str(self))
+ if self._isnan():
+ if self.is_snan():
+ raise ValueError("Cannot convert signaling NaN to float")
+ s = "-nan" if self._sign else "nan"
+ else:
+ s = str(self)
+ return float(s)
def __int__(self):
"""Converts self to an int, truncating if necessary."""
diff --git a/lib-python/2.7/distutils/__init__.py b/lib-python/2.7/distutils/__init__.py
--- a/lib-python/2.7/distutils/__init__.py
+++ b/lib-python/2.7/distutils/__init__.py
@@ -15,5 +15,5 @@
# Updated automatically by the Python release process.
#
#--start constants--
-__version__ = "2.7.3rc2"
+__version__ = "2.7.3"
#--end constants--
diff --git a/lib-python/2.7/distutils/ccompiler.py b/lib-python/2.7/distutils/ccompiler.py
--- a/lib-python/2.7/distutils/ccompiler.py
+++ b/lib-python/2.7/distutils/ccompiler.py
@@ -17,6 +17,8 @@
from distutils.dep_util import newer_group
from distutils.util import split_quoted, execute
from distutils import log
+# following import is for backward compatibility
+from distutils.sysconfig import customize_compiler
class CCompiler:
"""Abstract base class to define the interface that must be implemented
diff --git a/lib-python/2.7/distutils/command/check.py b/lib-python/2.7/distutils/command/check.py
--- a/lib-python/2.7/distutils/command/check.py
+++ b/lib-python/2.7/distutils/command/check.py
@@ -26,6 +26,9 @@
def system_message(self, level, message, *children, **kwargs):
self.messages.append((level, message, children, kwargs))
+ return nodes.system_message(message, level=level,
+ type=self.levels[level],
+ *children, **kwargs)
HAS_DOCUTILS = True
except ImportError:
diff --git a/lib-python/2.7/distutils/config.py b/lib-python/2.7/distutils/config.py
--- a/lib-python/2.7/distutils/config.py
+++ b/lib-python/2.7/distutils/config.py
@@ -42,16 +42,11 @@
def _store_pypirc(self, username, password):
"""Creates a default .pypirc file."""
rc = self._get_rc_file()
- f = open(rc, 'w')
+ f = os.fdopen(os.open(rc, os.O_CREAT | os.O_WRONLY, 0600), 'w')
try:
f.write(DEFAULT_PYPIRC % (username, password))
finally:
f.close()
- try:
- os.chmod(rc, 0600)
- except OSError:
- # should do something better here
- pass
def _read_pypirc(self):
"""Reads the .pypirc file."""
diff --git a/lib-python/2.7/distutils/dir_util.py b/lib-python/2.7/distutils/dir_util.py
--- a/lib-python/2.7/distutils/dir_util.py
+++ b/lib-python/2.7/distutils/dir_util.py
@@ -144,6 +144,10 @@
src_name = os.path.join(src, n)
dst_name = os.path.join(dst, n)
+ if n.startswith('.nfs'):
+ # skip NFS rename files
+ continue
+
if preserve_symlinks and os.path.islink(src_name):
link_dest = os.readlink(src_name)
if verbose >= 1:
diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py
--- a/lib-python/2.7/distutils/sysconfig.py
+++ b/lib-python/2.7/distutils/sysconfig.py
@@ -37,6 +37,11 @@
project_base = os.path.abspath(os.path.join(project_base, os.path.pardir,
os.path.pardir))
+# set for cross builds
+if "_PYTHON_PROJECT_BASE" in os.environ:
+ # this is the build directory, at least for posix
+ project_base = os.path.normpath(os.environ["_PYTHON_PROJECT_BASE"])
+
# python_build: (Boolean) if true, we're either building Python or
# building an extension with an un-installed Python, so we use
# different (hard-wired) directories.
@@ -141,7 +146,7 @@
"I don't know where Python installs its library "
"on platform '%s'" % os.name)
-_USE_CLANG = None
+
def customize_compiler(compiler):
"""Do any platform-specific customization of a CCompiler instance.
@@ -150,6 +155,21 @@
varies across Unices and is stored in Python's Makefile.
"""
if compiler.compiler_type == "unix":
+ if sys.platform == "darwin":
+ # Perform first-time customization of compiler-related
+ # config vars on OS X now that we know we need a compiler.
+ # This is primarily to support Pythons from binary
+ # installers. The kind and paths to build tools on
+ # the user system may vary significantly from the system
+ # that Python itself was built on. Also the user OS
+ # version and build tools may not support the same set
+ # of CPU architectures for universal builds.
+ global _config_vars
+ if not _config_vars.get('CUSTOMIZED_OSX_COMPILER', ''):
+ import _osx_support
+ _osx_support.customize_compiler(_config_vars)
+ _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
+
(cc, cxx, opt, cflags, ccshared, ldshared, so_ext, ar, ar_flags) = \
get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS',
'CCSHARED', 'LDSHARED', 'SO', 'AR',
@@ -157,36 +177,7 @@
newcc = None
if 'CC' in os.environ:
- newcc = os.environ['CC']
- elif sys.platform == 'darwin' and cc == 'gcc-4.2':
- # Issue #13590:
- # Since Apple removed gcc-4.2 in Xcode 4.2, we can no
- # longer assume it is available for extension module builds.
- # If Python was built with gcc-4.2, check first to see if
- # it is available on this system; if not, try to use clang
- # instead unless the caller explicitly set CC.
- global _USE_CLANG
- if _USE_CLANG is None:
- from distutils import log
- from subprocess import Popen, PIPE
- p = Popen("! type gcc-4.2 && type clang && exit 2",
- shell=True, stdout=PIPE, stderr=PIPE)
- p.wait()
- if p.returncode == 2:
- _USE_CLANG = True
- log.warn("gcc-4.2 not found, using clang instead")
- else:
- _USE_CLANG = False
- if _USE_CLANG:
- newcc = 'clang'
- if newcc:
- # On OS X, if CC is overridden, use that as the default
- # command for LDSHARED as well
- if (sys.platform == 'darwin'
- and 'LDSHARED' not in os.environ
- and ldshared.startswith(cc)):
- ldshared = newcc + ldshared[len(cc):]
- cc = newcc
+ cc = os.environ['CC']
if 'CXX' in os.environ:
cxx = os.environ['CXX']
if 'LDSHARED' in os.environ:
@@ -244,7 +235,7 @@
def get_makefile_filename():
"""Return full pathname of installed Makefile from the Python build."""
if python_build:
- return os.path.join(os.path.dirname(sys.executable), "Makefile")
+ return os.path.join(project_base, "Makefile")
lib_dir = get_python_lib(plat_specific=1, standard_lib=1)
return os.path.join(lib_dir, "config", "Makefile")
@@ -518,66 +509,11 @@
_config_vars['prefix'] = PREFIX
_config_vars['exec_prefix'] = EXEC_PREFIX
+ # OS X platforms require special customization to handle
+ # multi-architecture, multi-os-version installers
if sys.platform == 'darwin':
- kernel_version = os.uname()[2] # Kernel version (8.4.3)
- major_version = int(kernel_version.split('.')[0])
-
- if major_version < 8:
- # On Mac OS X before 10.4, check if -arch and -isysroot
- # are in CFLAGS or LDFLAGS and remove them if they are.
- # This is needed when building extensions on a 10.3 system
- # using a universal build of python.
- for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED',
- # a number of derived variables. These need to be
- # patched up as well.
- 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
- flags = _config_vars[key]
- flags = re.sub('-arch\s+\w+\s', ' ', flags)
- flags = re.sub('-isysroot [^ \t]*', ' ', flags)
- _config_vars[key] = flags
-
- else:
-
- # Allow the user to override the architecture flags using
- # an environment variable.
- # NOTE: This name was introduced by Apple in OSX 10.5 and
- # is used by several scripting languages distributed with
- # that OS release.
-
- if 'ARCHFLAGS' in os.environ:
- arch = os.environ['ARCHFLAGS']
- for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED',
- # a number of derived variables. These need to be
- # patched up as well.
- 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
-
- flags = _config_vars[key]
- flags = re.sub('-arch\s+\w+\s', ' ', flags)
- flags = flags + ' ' + arch
- _config_vars[key] = flags
-
- # If we're on OSX 10.5 or later and the user tries to
- # compiles an extension using an SDK that is not present
- # on the current machine it is better to not use an SDK
- # than to fail.
- #
- # The major usecase for this is users using a Python.org
- # binary installer on OSX 10.6: that installer uses
- # the 10.4u SDK, but that SDK is not installed by default
- # when you install Xcode.
- #
- m = re.search('-isysroot\s+(\S+)', _config_vars['CFLAGS'])
- if m is not None:
- sdk = m.group(1)
- if not os.path.exists(sdk):
- for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED',
- # a number of derived variables. These need to be
- # patched up as well.
- 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
-
- flags = _config_vars[key]
- flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
- _config_vars[key] = flags
+ import _osx_support
+ _osx_support.customize_config_vars(_config_vars)
if args:
vals = []
diff --git a/lib-python/2.7/distutils/tests/test_build_ext.py b/lib-python/2.7/distutils/tests/test_build_ext.py
--- a/lib-python/2.7/distutils/tests/test_build_ext.py
+++ b/lib-python/2.7/distutils/tests/test_build_ext.py
@@ -77,8 +77,9 @@
self.assertEqual(xx.foo(2, 5), 7)
self.assertEqual(xx.foo(13,15), 28)
self.assertEqual(xx.new().demo(), None)
- doc = 'This is a template module just for instruction.'
- self.assertEqual(xx.__doc__, doc)
+ if test_support.HAVE_DOCSTRINGS:
+ doc = 'This is a template module just for instruction.'
+ self.assertEqual(xx.__doc__, doc)
self.assertTrue(isinstance(xx.Null(), xx.Null))
self.assertTrue(isinstance(xx.Str(), xx.Str))
diff --git a/lib-python/2.7/distutils/tests/test_dir_util.py b/lib-python/2.7/distutils/tests/test_dir_util.py
--- a/lib-python/2.7/distutils/tests/test_dir_util.py
+++ b/lib-python/2.7/distutils/tests/test_dir_util.py
@@ -101,6 +101,24 @@
remove_tree(self.root_target, verbose=0)
remove_tree(self.target2, verbose=0)
+ def test_copy_tree_skips_nfs_temp_files(self):
+ mkpath(self.target, verbose=0)
+
+ a_file = os.path.join(self.target, 'ok.txt')
+ nfs_file = os.path.join(self.target, '.nfs123abc')
+ for f in a_file, nfs_file:
+ fh = open(f, 'w')
+ try:
+ fh.write('some content')
+ finally:
+ fh.close()
+
+ copy_tree(self.target, self.target2)
+ self.assertEqual(os.listdir(self.target2), ['ok.txt'])
+
+ remove_tree(self.root_target, verbose=0)
+ remove_tree(self.target2, verbose=0)
+
def test_ensure_relative(self):
if os.sep == '/':
self.assertEqual(ensure_relative('/home/foo'), 'home/foo')
diff --git a/lib-python/2.7/distutils/tests/test_msvc9compiler.py b/lib-python/2.7/distutils/tests/test_msvc9compiler.py
--- a/lib-python/2.7/distutils/tests/test_msvc9compiler.py
+++ b/lib-python/2.7/distutils/tests/test_msvc9compiler.py
@@ -104,7 +104,7 @@
unittest.TestCase):
def test_no_compiler(self):
- # makes sure query_vcvarsall throws
+ # makes sure query_vcvarsall raises
# a DistutilsPlatformError if the compiler
# is not found
from distutils.msvc9compiler import query_vcvarsall
diff --git a/lib-python/2.7/distutils/tests/test_register.py b/lib-python/2.7/distutils/tests/test_register.py
--- a/lib-python/2.7/distutils/tests/test_register.py
+++ b/lib-python/2.7/distutils/tests/test_register.py
@@ -1,6 +1,5 @@
# -*- encoding: utf8 -*-
"""Tests for distutils.command.register."""
-import sys
import os
import unittest
import getpass
@@ -11,11 +10,14 @@
from distutils.command import register as register_module
from distutils.command.register import register
-from distutils.core import Distribution
from distutils.errors import DistutilsSetupError
-from distutils.tests import support
-from distutils.tests.test_config import PYPIRC, PyPIRCCommandTestCase
+from distutils.tests.test_config import PyPIRCCommandTestCase
+
+try:
+ import docutils
+except ImportError:
+ docutils = None
PYPIRC_NOPASSWORD = """\
[distutils]
@@ -192,6 +194,7 @@
self.assertEqual(headers['Content-length'], '290')
self.assertTrue('tarek' in req.data)
+ @unittest.skipUnless(docutils is not None, 'needs docutils')
def test_strict(self):
# testing the script option
# when on, the register command stops if
@@ -204,13 +207,6 @@
cmd.strict = 1
self.assertRaises(DistutilsSetupError, cmd.run)
- # we don't test the reSt feature if docutils
- # is not installed
- try:
- import docutils
- except ImportError:
- return
-
# metadata are OK but long_description is broken
metadata = {'url': 'xxx', 'author': 'xxx',
'author_email': u'éxéxé',
@@ -264,6 +260,21 @@
finally:
del register_module.raw_input
+ @unittest.skipUnless(docutils is not None, 'needs docutils')
+ def test_register_invalid_long_description(self):
+ description = ':funkie:`str`' # mimic Sphinx-specific markup
+ metadata = {'url': 'xxx', 'author': 'xxx',
+ 'author_email': 'xxx',
+ 'name': 'xxx', 'version': 'xxx',
+ 'long_description': description}
+ cmd = self._get_cmd(metadata)
+ cmd.ensure_finalized()
+ cmd.strict = True
+ inputs = RawInputs('2', 'tarek', 'tarek at ziade.org')
+ register_module.raw_input = inputs
+ self.addCleanup(delattr, register_module, 'raw_input')
+ self.assertRaises(DistutilsSetupError, cmd.run)
+
def test_check_metadata_deprecated(self):
# makes sure make_metadata is deprecated
cmd = self._get_cmd()
diff --git a/lib-python/2.7/distutils/tests/test_sdist.py b/lib-python/2.7/distutils/tests/test_sdist.py
--- a/lib-python/2.7/distutils/tests/test_sdist.py
+++ b/lib-python/2.7/distutils/tests/test_sdist.py
@@ -91,9 +91,8 @@
@unittest.skipUnless(zlib, "requires zlib")
def test_prune_file_list(self):
- # this test creates a package with some vcs dirs in it
- # and launch sdist to make sure they get pruned
- # on all systems
+ # this test creates a project with some VCS dirs and an NFS rename
+ # file, then launches sdist to check they get pruned on all systems
# creating VCS directories with some files in them
os.mkdir(join(self.tmp_dir, 'somecode', '.svn'))
@@ -107,6 +106,8 @@
self.write_file((self.tmp_dir, 'somecode', '.git',
'ok'), 'xxx')
+ self.write_file((self.tmp_dir, 'somecode', '.nfs0001'), 'xxx')
+
# now building a sdist
dist, cmd = self.get_cmd()
diff --git a/lib-python/2.7/distutils/tests/test_sysconfig.py b/lib-python/2.7/distutils/tests/test_sysconfig.py
--- a/lib-python/2.7/distutils/tests/test_sysconfig.py
+++ b/lib-python/2.7/distutils/tests/test_sysconfig.py
@@ -72,6 +72,35 @@
'OTHER': 'foo'})
+ def test_sysconfig_module(self):
+ import sysconfig as global_sysconfig
+ self.assertEqual(global_sysconfig.get_config_var('CFLAGS'), sysconfig.get_config_var('CFLAGS'))
+ self.assertEqual(global_sysconfig.get_config_var('LDFLAGS'), sysconfig.get_config_var('LDFLAGS'))
+
+ @unittest.skipIf(sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'),'compiler flags customized')
+ def test_sysconfig_compiler_vars(self):
+ # On OS X, binary installers support extension module building on
+ # various levels of the operating system with differing Xcode
+ # configurations. This requires customization of some of the
+ # compiler configuration directives to suit the environment on
+ # the installed machine. Some of these customizations may require
+ # running external programs and, so, are deferred until needed by
+ # the first extension module build. With Python 3.3, only
+ # the Distutils version of sysconfig is used for extension module
+ # builds, which happens earlier in the Distutils tests. This may
+ # cause the following tests to fail since no tests have caused
+ # the global version of sysconfig to call the customization yet.
+ # The solution for now is to simply skip this test in this case.
+ # The longer-term solution is to only have one version of sysconfig.
+
+ import sysconfig as global_sysconfig
+ if sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'):
+ return
+ self.assertEqual(global_sysconfig.get_config_var('LDSHARED'), sysconfig.get_config_var('LDSHARED'))
+ self.assertEqual(global_sysconfig.get_config_var('CC'), sysconfig.get_config_var('CC'))
+
+
+
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(SysconfigTestCase))
diff --git a/lib-python/2.7/distutils/unixccompiler.py b/lib-python/2.7/distutils/unixccompiler.py
--- a/lib-python/2.7/distutils/unixccompiler.py
+++ b/lib-python/2.7/distutils/unixccompiler.py
@@ -26,6 +26,9 @@
DistutilsExecError, CompileError, LibError, LinkError
from distutils import log
+if sys.platform == 'darwin':
+ import _osx_support
+
# XXX Things not currently handled:
# * optimization/debug/warning flags; we just use whatever's in Python's
# Makefile and live with it. Is this adequate? If not, we might
@@ -41,68 +44,6 @@
# should just happily stuff them into the preprocessor/compiler/linker
# options and carry on.
-def _darwin_compiler_fixup(compiler_so, cc_args):
- """
- This function will strip '-isysroot PATH' and '-arch ARCH' from the
- compile flags if the user has specified one them in extra_compile_flags.
-
- This is needed because '-arch ARCH' adds another architecture to the
- build, without a way to remove an architecture. Furthermore GCC will
- barf if multiple '-isysroot' arguments are present.
- """
- stripArch = stripSysroot = 0
-
- compiler_so = list(compiler_so)
- kernel_version = os.uname()[2] # 8.4.3
- major_version = int(kernel_version.split('.')[0])
-
- if major_version < 8:
- # OSX before 10.4.0, these don't support -arch and -isysroot at
- # all.
- stripArch = stripSysroot = True
- else:
- stripArch = '-arch' in cc_args
- stripSysroot = '-isysroot' in cc_args
-
- if stripArch or 'ARCHFLAGS' in os.environ:
- while 1:
- try:
- index = compiler_so.index('-arch')
- # Strip this argument and the next one:
- del compiler_so[index:index+2]
- except ValueError:
- break
-
- if 'ARCHFLAGS' in os.environ and not stripArch:
- # User specified different -arch flags in the environ,
- # see also distutils.sysconfig
- compiler_so = compiler_so + os.environ['ARCHFLAGS'].split()
-
- if stripSysroot:
- try:
- index = compiler_so.index('-isysroot')
- # Strip this argument and the next one:
- del compiler_so[index:index+2]
- except ValueError:
- pass
-
- # Check if the SDK that is used during compilation actually exists,
- # the universal build requires the usage of a universal SDK and not all
- # users have that installed by default.
- sysroot = None
- if '-isysroot' in cc_args:
- idx = cc_args.index('-isysroot')
- sysroot = cc_args[idx+1]
- elif '-isysroot' in compiler_so:
- idx = compiler_so.index('-isysroot')
- sysroot = compiler_so[idx+1]
-
- if sysroot and not os.path.isdir(sysroot):
- log.warn("Compiling with an SDK that doesn't seem to exist: %s",
- sysroot)
- log.warn("Please check your Xcode installation")
-
- return compiler_so
class UnixCCompiler(CCompiler):
@@ -172,7 +113,8 @@
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
compiler_so = self.compiler_so
if sys.platform == 'darwin':
- compiler_so = _darwin_compiler_fixup(compiler_so, cc_args + extra_postargs)
+ compiler_so = _osx_support.compiler_fixup(compiler_so,
+ cc_args + extra_postargs)
try:
self.spawn(compiler_so + cc_args + [src, '-o', obj] +
extra_postargs)
@@ -251,7 +193,7 @@
linker[i] = self.compiler_cxx[i]
if sys.platform == 'darwin':
- linker = _darwin_compiler_fixup(linker, ld_args)
+ linker = _osx_support.compiler_fixup(linker, ld_args)
self.spawn(linker + ld_args)
except DistutilsExecError, msg:
diff --git a/lib-python/2.7/distutils/util.py b/lib-python/2.7/distutils/util.py
--- a/lib-python/2.7/distutils/util.py
+++ b/lib-python/2.7/distutils/util.py
@@ -51,6 +51,10 @@
return 'win-ia64'
return sys.platform
+ # Set for cross builds explicitly
+ if "_PYTHON_HOST_PLATFORM" in os.environ:
+ return os.environ["_PYTHON_HOST_PLATFORM"]
+
if os.name != "posix" or not hasattr(os, 'uname'):
# XXX what about the architecture? NT is Intel or Alpha,
# Mac OS is M68k or PPC, etc.
@@ -93,94 +97,10 @@
if m:
release = m.group()
elif osname[:6] == "darwin":
- #
- # For our purposes, we'll assume that the system version from
- # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
- # to. This makes the compatibility story a bit more sane because the
- # machine is going to compile and link as if it were
- # MACOSX_DEPLOYMENT_TARGET.
- from distutils.sysconfig import get_config_vars
- cfgvars = get_config_vars()
-
- macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
-
- if 1:
- # Always calculate the release of the running machine,
- # needed to determine if we can build fat binaries or not.
-
- macrelease = macver
- # Get the system version. Reading this plist is a documented
- # way to get the system version (see the documentation for
- # the Gestalt Manager)
- try:
- f = open('/System/Library/CoreServices/SystemVersion.plist')
- except IOError:
- # We're on a plain darwin box, fall back to the default
- # behaviour.
- pass
- else:
- try:
- m = re.search(
- r'<key>ProductUserVisibleVersion</key>\s*' +
- r'<string>(.*?)</string>', f.read())
- if m is not None:
- macrelease = '.'.join(m.group(1).split('.')[:2])
- # else: fall back to the default behaviour
- finally:
- f.close()
-
- if not macver:
- macver = macrelease
-
- if macver:
- from distutils.sysconfig import get_config_vars
- release = macver
- osname = "macosx"
-
- if (macrelease + '.') >= '10.4.' and \
- '-arch' in get_config_vars().get('CFLAGS', '').strip():
- # The universal build will build fat binaries, but not on
- # systems before 10.4
- #
- # Try to detect 4-way universal builds, those have machine-type
- # 'universal' instead of 'fat'.
-
- machine = 'fat'
- cflags = get_config_vars().get('CFLAGS')
-
- archs = re.findall('-arch\s+(\S+)', cflags)
- archs = tuple(sorted(set(archs)))
-
- if len(archs) == 1:
- machine = archs[0]
- elif archs == ('i386', 'ppc'):
- machine = 'fat'
- elif archs == ('i386', 'x86_64'):
- machine = 'intel'
- elif archs == ('i386', 'ppc', 'x86_64'):
- machine = 'fat3'
- elif archs == ('ppc64', 'x86_64'):
- machine = 'fat64'
- elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
- machine = 'universal'
- else:
- raise ValueError(
- "Don't know machine value for archs=%r"%(archs,))
-
- elif machine == 'i386':
- # On OSX the machine type returned by uname is always the
- # 32-bit variant, even if the executable architecture is
- # the 64-bit variant
- if sys.maxint >= 2**32:
- machine = 'x86_64'
-
- elif machine in ('PowerPC', 'Power_Macintosh'):
- # Pick a sane name for the PPC architecture.
- machine = 'ppc'
-
- # See 'i386' case
- if sys.maxint >= 2**32:
- machine = 'ppc64'
+ import _osx_support, distutils.sysconfig
+ osname, release, machine = _osx_support.get_platform_osx(
+ distutils.sysconfig.get_config_vars(),
+ osname, release, machine)
return "%s-%s-%s" % (osname, release, machine)
diff --git a/lib-python/2.7/doctest.py b/lib-python/2.7/doctest.py
--- a/lib-python/2.7/doctest.py
+++ b/lib-python/2.7/doctest.py
@@ -2314,7 +2314,8 @@
return "Doctest: " + self._dt_test.name
class SkipDocTestCase(DocTestCase):
- def __init__(self):
+ def __init__(self, module):
+ self.module = module
DocTestCase.__init__(self, None)
def setUp(self):
@@ -2324,7 +2325,10 @@
pass
def shortDescription(self):
- return "Skipping tests from %s" % module.__name__
+ return "Skipping tests from %s" % self.module.__name__
+
+ __str__ = shortDescription
+
def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None,
**options):
@@ -2372,12 +2376,17 @@
if not tests and sys.flags.optimize >=2:
# Skip doctests when running with -O2
suite = unittest.TestSuite()
- suite.addTest(SkipDocTestCase())
+ suite.addTest(SkipDocTestCase(module))
return suite
elif not tests:
# Why do we want to do this? Because it reveals a bug that might
# otherwise be hidden.
- raise ValueError(module, "has no tests")
+ # It is probably a bug that this exception is not also raised if the
+ # number of doctest examples in tests is zero (i.e. if no doctest
+ # examples were found). However, we should probably not be raising
+ # an exception at all here, though it is too late to make this change
+ # for a maintenance release. See also issue #14649.
+ raise ValueError(module, "has no docstrings")
tests.sort()
suite = unittest.TestSuite()
diff --git a/lib-python/2.7/email/_parseaddr.py b/lib-python/2.7/email/_parseaddr.py
--- a/lib-python/2.7/email/_parseaddr.py
+++ b/lib-python/2.7/email/_parseaddr.py
@@ -13,7 +13,7 @@
'quote',
]
-import time
+import time, calendar
SPACE = ' '
EMPTYSTRING = ''
@@ -150,13 +150,13 @@
def mktime_tz(data):
- """Turn a 10-tuple as returned by parsedate_tz() into a UTC timestamp."""
+ """Turn a 10-tuple as returned by parsedate_tz() into a POSIX timestamp."""
if data[9] is None:
# No zone info, so localtime is better assumption than GMT
return time.mktime(data[:8] + (-1,))
else:
- t = time.mktime(data[:8] + (0,))
- return t - data[9] - time.timezone
+ t = calendar.timegm(data)
+ return t - data[9]
def quote(str):
diff --git a/lib-python/2.7/email/base64mime.py b/lib-python/2.7/email/base64mime.py
--- a/lib-python/2.7/email/base64mime.py
+++ b/lib-python/2.7/email/base64mime.py
@@ -130,7 +130,7 @@
verbatim (this is the default).
Each line of encoded text will end with eol, which defaults to "\\n". Set
- this to "\r\n" if you will be using the result of this function directly
+ this to "\\r\\n" if you will be using the result of this function directly
in an email.
"""
if not s:
diff --git a/lib-python/2.7/email/feedparser.py b/lib-python/2.7/email/feedparser.py
--- a/lib-python/2.7/email/feedparser.py
+++ b/lib-python/2.7/email/feedparser.py
@@ -13,7 +13,7 @@
data. When you have no more data to push into the parser, call .close().
This completes the parsing and returns the root message object.
-The other advantage of this parser is that it will never throw a parsing
+The other advantage of this parser is that it will never raise a parsing
exception. Instead, when it finds something unexpected, it adds a 'defect' to
the current message. Defects are just instances that live on the message
object's .defects attribute.
@@ -214,7 +214,7 @@
# supposed to see in the body of the message.
self._parse_headers(headers)
# Headers-only parsing is a backwards compatibility hack, which was
- # necessary in the older parser, which could throw errors. All
+ # necessary in the older parser, which could raise errors. All
# remaining lines in the input are thrown into the message body.
if self._headersonly:
lines = []
diff --git a/lib-python/2.7/email/generator.py b/lib-python/2.7/email/generator.py
--- a/lib-python/2.7/email/generator.py
+++ b/lib-python/2.7/email/generator.py
@@ -212,7 +212,11 @@
msg.set_boundary(boundary)
# If there's a preamble, write it out, with a trailing CRLF
if msg.preamble is not None:
- print >> self._fp, msg.preamble
+ if self._mangle_from_:
+ preamble = fcre.sub('>From ', msg.preamble)
+ else:
+ preamble = msg.preamble
+ print >> self._fp, preamble
# dash-boundary transport-padding CRLF
print >> self._fp, '--' + boundary
# body-part
@@ -230,7 +234,11 @@
self._fp.write('\n--' + boundary + '--')
if msg.epilogue is not None:
print >> self._fp
- self._fp.write(msg.epilogue)
+ if self._mangle_from_:
+ epilogue = fcre.sub('>From ', msg.epilogue)
+ else:
+ epilogue = msg.epilogue
+ self._fp.write(epilogue)
def _handle_multipart_signed(self, msg):
# The contents of signed parts has to stay unmodified in order to keep
diff --git a/lib-python/2.7/email/test/test_email.py b/lib-python/2.7/email/test/test_email.py
--- a/lib-python/2.7/email/test/test_email.py
+++ b/lib-python/2.7/email/test/test_email.py
@@ -9,6 +9,7 @@
import difflib
import unittest
import warnings
+import textwrap
from cStringIO import StringIO
import email
@@ -948,6 +949,28 @@
Blah blah blah
""")
+ def test_mangle_from_in_preamble_and_epilog(self):
+ s = StringIO()
+ g = Generator(s, mangle_from_=True)
+ msg = email.message_from_string(textwrap.dedent("""\
+ From: foo at bar.com
+ Mime-Version: 1.0
+ Content-Type: multipart/mixed; boundary=XXX
+
+ From somewhere unknown
+
+ --XXX
+ Content-Type: text/plain
+
+ foo
+
+ --XXX--
+
+ From somewhere unknowable
+ """))
+ g.flatten(msg)
+ self.assertEqual(len([1 for x in s.getvalue().split('\n')
+ if x.startswith('>From ')]), 2)
# Test the basic MIMEAudio class
@@ -2262,6 +2285,12 @@
eq(time.localtime(t)[:6], timetup[:6])
eq(int(time.strftime('%Y', timetup[:9])), 2003)
+ def test_mktime_tz(self):
+ self.assertEqual(Utils.mktime_tz((1970, 1, 1, 0, 0, 0,
+ -1, -1, -1, 0)), 0)
+ self.assertEqual(Utils.mktime_tz((1970, 1, 1, 0, 0, 0,
+ -1, -1, -1, 1234)), -1234)
+
def test_parsedate_y2k(self):
"""Test for parsing a date with a two-digit year.
diff --git a/lib-python/2.7/email/test/test_email_renamed.py b/lib-python/2.7/email/test/test_email_renamed.py
--- a/lib-python/2.7/email/test/test_email_renamed.py
+++ b/lib-python/2.7/email/test/test_email_renamed.py
@@ -994,6 +994,38 @@
eq(msg.get_payload(), '+vv8/f7/')
eq(msg.get_payload(decode=True), bytes)
+ def test_binary_body_with_encode_7or8bit(self):
+ # Issue 17171.
+ bytesdata = b'\xfa\xfb\xfc\xfd\xfe\xff'
+ msg = MIMEApplication(bytesdata, _encoder=encoders.encode_7or8bit)
+ # Treated as a string, this will be invalid code points.
+ self.assertEqual(msg.get_payload(), bytesdata)
+ self.assertEqual(msg.get_payload(decode=True), bytesdata)
+ self.assertEqual(msg['Content-Transfer-Encoding'], '8bit')
+ s = StringIO()
+ g = Generator(s)
+ g.flatten(msg)
+ wireform = s.getvalue()
+ msg2 = email.message_from_string(wireform)
+ self.assertEqual(msg.get_payload(), bytesdata)
+ self.assertEqual(msg2.get_payload(decode=True), bytesdata)
+ self.assertEqual(msg2['Content-Transfer-Encoding'], '8bit')
+
+ def test_binary_body_with_encode_noop(self):
+ # Issue 16564: This does not produce an RFC valid message, since to be
+ # valid it should have a CTE of binary. But the below works, and is
+ # documented as working this way.
+ bytesdata = b'\xfa\xfb\xfc\xfd\xfe\xff'
+ msg = MIMEApplication(bytesdata, _encoder=encoders.encode_noop)
+ self.assertEqual(msg.get_payload(), bytesdata)
+ self.assertEqual(msg.get_payload(decode=True), bytesdata)
+ s = StringIO()
+ g = Generator(s)
+ g.flatten(msg)
+ wireform = s.getvalue()
+ msg2 = email.message_from_string(wireform)
+ self.assertEqual(msg.get_payload(), bytesdata)
+ self.assertEqual(msg2.get_payload(decode=True), bytesdata)
# Test the basic MIMEText class
diff --git a/lib-python/2.7/email/utils.py b/lib-python/2.7/email/utils.py
--- a/lib-python/2.7/email/utils.py
+++ b/lib-python/2.7/email/utils.py
@@ -63,7 +63,7 @@
"""Decodes a base64 string.
This function is equivalent to base64.decodestring and it's retained only
- for backward compatibility. It used to remove the last \n of the decoded
+ for backward compatibility. It used to remove the last \\n of the decoded
string, if it had any (see issue 7143).
"""
if not s:
@@ -73,7 +73,7 @@
def fix_eols(s):
- """Replace all line-ending characters with \r\n."""
+ """Replace all line-ending characters with \\r\\n."""
# Fix newlines with no preceding carriage return
s = re.sub(r'(?<!\r)\n', CRLF, s)
# Fix carriage returns with no following newline
diff --git a/lib-python/2.7/ftplib.py b/lib-python/2.7/ftplib.py
--- a/lib-python/2.7/ftplib.py
+++ b/lib-python/2.7/ftplib.py
@@ -273,21 +273,24 @@
def makeport(self):
'''Create a new socket and send a PORT command for it.'''
- msg = "getaddrinfo returns an empty list"
+ err = None
sock = None
for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
af, socktype, proto, canonname, sa = res
try:
sock = socket.socket(af, socktype, proto)
sock.bind(sa)
- except socket.error, msg:
+ except socket.error, err:
if sock:
sock.close()
sock = None
continue
break
- if not sock:
- raise socket.error, msg
+ if sock is None:
+ if err is not None:
+ raise err
+ else:
+ raise socket.error("getaddrinfo returns an empty list")
sock.listen(1)
port = sock.getsockname()[1] # Get proper port
host = self.sock.getsockname()[0] # Get proper host
diff --git a/lib-python/2.7/glob.py b/lib-python/2.7/glob.py
--- a/lib-python/2.7/glob.py
+++ b/lib-python/2.7/glob.py
@@ -5,12 +5,23 @@
import re
import fnmatch
+try:
+ _unicode = unicode
+except NameError:
+ # If Python is built without Unicode support, the unicode type
+ # will not exist. Fake one.
+ class _unicode(object):
+ pass
+
__all__ = ["glob", "iglob"]
def glob(pathname):
"""Return a list of paths matching a pathname pattern.
- The pattern may contain simple shell-style wildcards a la fnmatch.
+ The pattern may contain simple shell-style wildcards a la
+ fnmatch. However, unlike fnmatch, filenames starting with a
+ dot are special cases that are not matched by '*' and '?'
+ patterns.
"""
return list(iglob(pathname))
@@ -18,7 +29,10 @@
def iglob(pathname):
"""Return an iterator which yields the paths matching a pathname pattern.
- The pattern may contain simple shell-style wildcards a la fnmatch.
+ The pattern may contain simple shell-style wildcards a la
+ fnmatch. However, unlike fnmatch, filenames starting with a
+ dot are special cases that are not matched by '*' and '?'
+ patterns.
"""
if not has_magic(pathname):
@@ -30,7 +44,10 @@
for name in glob1(os.curdir, basename):
yield name
return
- if has_magic(dirname):
+ # `os.path.split()` returns the argument itself as a dirname if it is a
+ # drive or UNC path. Prevent an infinite recursion if a drive or UNC path
+ # contains magic characters (i.e. r'\\?\C:').
+ if dirname != pathname and has_magic(dirname):
dirs = iglob(dirname)
else:
dirs = [dirname]
@@ -49,7 +66,7 @@
def glob1(dirname, pattern):
if not dirname:
dirname = os.curdir
- if isinstance(pattern, unicode) and not isinstance(dirname, unicode):
+ if isinstance(pattern, _unicode) and not isinstance(dirname, unicode):
dirname = unicode(dirname, sys.getfilesystemencoding() or
sys.getdefaultencoding())
try:
diff --git a/lib-python/2.7/gzip.py b/lib-python/2.7/gzip.py
--- a/lib-python/2.7/gzip.py
+++ b/lib-python/2.7/gzip.py
@@ -21,9 +21,6 @@
# or unsigned.
output.write(struct.pack("<L", value))
-def read32(input):
- return struct.unpack("<I", input.read(4))[0]
-
def open(filename, mode="rb", compresslevel=9):
"""Shorthand for GzipFile(filename, mode, compresslevel).
@@ -66,9 +63,10 @@
Be aware that only the 'rb', 'ab', and 'wb' values should be used
for cross-platform portability.
- The compresslevel argument is an integer from 1 to 9 controlling the
+ The compresslevel argument is an integer from 0 to 9 controlling the
level of compression; 1 is fastest and produces the least compression,
- and 9 is slowest and produces the most compression. The default is 9.
+ and 9 is slowest and produces the most compression. 0 is no compression
+ at all. The default is 9.
The mtime argument is an optional numeric timestamp to be written
to the stream when compressing. All gzip compressed streams
@@ -81,6 +79,10 @@
"""
+ # Make sure we don't inadvertently enable universal newlines on the
+ # underlying file object - in read mode, this causes data corruption.
+ if mode:
+ mode = mode.replace('U', '')
# guarantee the file is opened in binary mode on platforms
# that care about that sort of thing
if mode and 'b' not in mode:
@@ -179,24 +181,28 @@
self.crc = zlib.crc32("") & 0xffffffffL
self.size = 0
+ def _read_exact(self, n):
+ data = self.fileobj.read(n)
+ while len(data) < n:
+ b = self.fileobj.read(n - len(data))
+ if not b:
+ raise EOFError("Compressed file ended before the "
+ "end-of-stream marker was reached")
+ data += b
+ return data
+
def _read_gzip_header(self):
magic = self.fileobj.read(2)
if magic != '\037\213':
raise IOError, 'Not a gzipped file'
- method = ord( self.fileobj.read(1) )
+
+ method, flag, self.mtime = struct.unpack("<BBIxx", self._read_exact(8))
if method != 8:
raise IOError, 'Unknown compression method'
- flag = ord( self.fileobj.read(1) )
- self.mtime = read32(self.fileobj)
- # extraflag = self.fileobj.read(1)
- # os = self.fileobj.read(1)
- self.fileobj.read(2)
if flag & FEXTRA:
# Read & discard the extra field, if present
- xlen = ord(self.fileobj.read(1))
- xlen = xlen + 256*ord(self.fileobj.read(1))
- self.fileobj.read(xlen)
+ self._read_exact(struct.unpack("<H", self._read_exact(2)))
if flag & FNAME:
# Read and discard a null-terminated string containing the filename
while True:
@@ -210,7 +216,7 @@
if not s or s=='\000':
break
if flag & FHCRC:
- self.fileobj.read(2) # Read & discard the 16-bit header CRC
+ self._read_exact(2) # Read & discard the 16-bit header CRC
def write(self,data):
self._check_closed()
@@ -244,20 +250,16 @@
readsize = 1024
if size < 0: # get the whole thing
- try:
- while True:
- self._read(readsize)
- readsize = min(self.max_read_chunk, readsize * 2)
- except EOFError:
- size = self.extrasize
+ while self._read(readsize):
+ readsize = min(self.max_read_chunk, readsize * 2)
+ size = self.extrasize
else: # just get some more of it
- try:
- while size > self.extrasize:
- self._read(readsize)
- readsize = min(self.max_read_chunk, readsize * 2)
- except EOFError:
- if size > self.extrasize:
- size = self.extrasize
+ while size > self.extrasize:
+ if not self._read(readsize):
+ if size > self.extrasize:
+ size = self.extrasize
+ break
+ readsize = min(self.max_read_chunk, readsize * 2)
offset = self.offset - self.extrastart
chunk = self.extrabuf[offset: offset + size]
@@ -272,7 +274,7 @@
def _read(self, size=1024):
if self.fileobj is None:
- raise EOFError, "Reached EOF"
+ return False
if self._new_member:
# If the _new_member flag is set, we have to
@@ -283,7 +285,7 @@
pos = self.fileobj.tell() # Save current position
self.fileobj.seek(0, 2) # Seek to end of file
if pos == self.fileobj.tell():
- raise EOFError, "Reached EOF"
+ return False
else:
self.fileobj.seek( pos ) # Return to original position
@@ -300,9 +302,10 @@
if buf == "":
uncompress = self.decompress.flush()
+ self.fileobj.seek(-len(self.decompress.unused_data), 1)
self._read_eof()
self._add_read_data( uncompress )
- raise EOFError, 'Reached EOF'
+ return False
uncompress = self.decompress.decompress(buf)
self._add_read_data( uncompress )
@@ -312,13 +315,14 @@
# so seek back to the start of the unused data, finish up
# this member, and read a new gzip header.
# (The number of bytes to seek back is the length of the unused
- # data, minus 8 because _read_eof() will rewind a further 8 bytes)
- self.fileobj.seek( -len(self.decompress.unused_data)+8, 1)
+ # data)
+ self.fileobj.seek(-len(self.decompress.unused_data), 1)
# Check the CRC and file size, and set the flag so we read
# a new member on the next call
self._read_eof()
self._new_member = True
+ return True
def _add_read_data(self, data):
self.crc = zlib.crc32(data, self.crc) & 0xffffffffL
@@ -329,14 +333,11 @@
self.size = self.size + len(data)
def _read_eof(self):
- # We've read to the end of the file, so we have to rewind in order
- # to reread the 8 bytes containing the CRC and the file size.
+ # We've read to the end of the file.
# We check the that the computed CRC and size of the
# uncompressed data matches the stored values. Note that the size
# stored is the true file size mod 2**32.
- self.fileobj.seek(-8, 1)
- crc32 = read32(self.fileobj)
- isize = read32(self.fileobj) # may exceed 2GB
+ crc32, isize = struct.unpack("<II", self._read_exact(8))
if crc32 != self.crc:
raise IOError("CRC check failed %s != %s" % (hex(crc32),
hex(self.crc)))
@@ -417,7 +418,7 @@
if offset < self.offset:
raise IOError('Negative seek in write mode')
count = offset - self.offset
- for i in range(count // 1024):
+ for i in xrange(count // 1024):
self.write(1024 * '\0')
self.write((count % 1024) * '\0')
elif self.mode == READ:
@@ -425,7 +426,7 @@
# for negative seek, rewind and do positive seek
self.rewind()
count = offset - self.offset
- for i in range(count // 1024):
+ for i in xrange(count // 1024):
self.read(1024)
self.read(count % 1024)
diff --git a/lib-python/2.7/hashlib.py b/lib-python/2.7/hashlib.py
--- a/lib-python/2.7/hashlib.py
+++ b/lib-python/2.7/hashlib.py
@@ -88,7 +88,7 @@
except ImportError:
pass # no extension module, this hash is unsupported.
- raise ValueError('unsupported hash type %s' % name)
+ raise ValueError('unsupported hash type ' + name)
def __get_openssl_constructor(name):
diff --git a/lib-python/2.7/heapq.py b/lib-python/2.7/heapq.py
--- a/lib-python/2.7/heapq.py
+++ b/lib-python/2.7/heapq.py
@@ -129,9 +129,8 @@
__all__ = ['heappush', 'heappop', 'heapify', 'heapreplace', 'merge',
'nlargest', 'nsmallest', 'heappushpop']
-from itertools import islice, repeat, count, imap, izip, tee, chain
+from itertools import islice, count, imap, izip, tee, chain
from operator import itemgetter
-import bisect
def cmp_lt(x, y):
# Use __lt__ if available; otherwise, try __le__.
@@ -188,6 +187,19 @@
for i in reversed(xrange(n//2)):
_siftup(x, i)
+def _heappushpop_max(heap, item):
+ """Maxheap version of a heappush followed by a heappop."""
+ if heap and cmp_lt(item, heap[0]):
+ item, heap[0] = heap[0], item
+ _siftup_max(heap, 0)
+ return item
+
+def _heapify_max(x):
+ """Transform list into a maxheap, in-place, in O(len(x)) time."""
+ n = len(x)
+ for i in reversed(range(n//2)):
+ _siftup_max(x, i)
+
def nlargest(n, iterable):
"""Find the n largest elements in a dataset.
@@ -213,30 +225,16 @@
"""
if n < 0:
return []
- if hasattr(iterable, '__len__') and n * 10 <= len(iterable):
- # For smaller values of n, the bisect method is faster than a minheap.
- # It is also memory efficient, consuming only n elements of space.
- it = iter(iterable)
- result = sorted(islice(it, 0, n))
- if not result:
- return result
- insort = bisect.insort
- pop = result.pop
- los = result[-1] # los --> Largest of the nsmallest
- for elem in it:
- if cmp_lt(elem, los):
- insort(result, elem)
- pop()
- los = result[-1]
+ it = iter(iterable)
+ result = list(islice(it, n))
+ if not result:
return result
- # An alternative approach manifests the whole iterable in memory but
- # saves comparisons by heapifying all at once. Also, saves time
- # over bisect.insort() which has O(n) data movement time for every
- # insertion. Finding the n smallest of an m length iterable requires
- # O(m) + O(n log m) comparisons.
- h = list(iterable)
- heapify(h)
- return map(heappop, repeat(h, min(n, len(h))))
+ _heapify_max(result)
+ _heappushpop = _heappushpop_max
+ for elem in it:
+ _heappushpop(result, elem)
+ result.sort()
+ return result
# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos
# is the index of a leaf with a possibly out-of-order value. Restore the
@@ -314,6 +312,42 @@
heap[pos] = newitem
_siftdown(heap, startpos, pos)
+def _siftdown_max(heap, startpos, pos):
+ 'Maxheap variant of _siftdown'
+ newitem = heap[pos]
+ # Follow the path to the root, moving parents down until finding a place
+ # newitem fits.
+ while pos > startpos:
+ parentpos = (pos - 1) >> 1
+ parent = heap[parentpos]
+ if cmp_lt(parent, newitem):
+ heap[pos] = parent
+ pos = parentpos
+ continue
+ break
+ heap[pos] = newitem
+
+def _siftup_max(heap, pos):
+ 'Maxheap variant of _siftup'
+ endpos = len(heap)
+ startpos = pos
+ newitem = heap[pos]
+ # Bubble up the larger child until hitting a leaf.
+ childpos = 2*pos + 1 # leftmost child position
+ while childpos < endpos:
+ # Set childpos to index of larger child.
+ rightpos = childpos + 1
+ if rightpos < endpos and not cmp_lt(heap[rightpos], heap[childpos]):
+ childpos = rightpos
+ # Move the larger child up.
+ heap[pos] = heap[childpos]
+ pos = childpos
+ childpos = 2*pos + 1
+ # The leaf at pos is empty now. Put newitem there, and bubble it up
+ # to its final resting place (by sifting its parents down).
+ heap[pos] = newitem
+ _siftdown_max(heap, startpos, pos)
+
# If available, use C implementation
try:
from _heapq import *
diff --git a/lib-python/2.7/httplib.py b/lib-python/2.7/httplib.py
--- a/lib-python/2.7/httplib.py
+++ b/lib-python/2.7/httplib.py
@@ -362,7 +362,9 @@
def _read_status(self):
# Initialize with Simple-Response defaults
- line = self.fp.readline()
+ line = self.fp.readline(_MAXLINE + 1)
+ if len(line) > _MAXLINE:
+ raise LineTooLong("header line")
if self.debuglevel > 0:
print "reply:", repr(line)
if not line:
@@ -545,7 +547,11 @@
if self.length is None:
s = self.fp.read()
else:
- s = self._safe_read(self.length)
+ try:
+ s = self._safe_read(self.length)
+ except IncompleteRead:
+ self.close()
+ raise
self.length = 0
self.close() # we read everything
return s
@@ -559,10 +565,15 @@
# connection, and the user is reading more bytes than will be provided
# (for example, reading in 1k chunks)
s = self.fp.read(amt)
+ if not s:
+ # Ideally, we would raise IncompleteRead if the content-length
+ # wasn't satisfied, but it might break compatibility.
+ self.close()
if self.length is not None:
self.length -= len(s)
if not self.length:
self.close()
+
return s
def _read_chunked(self, amt):
@@ -748,7 +759,11 @@
line = response.fp.readline(_MAXLINE + 1)
if len(line) > _MAXLINE:
raise LineTooLong("header line")
- if line == '\r\n': break
+ if not line:
+ # for sites which EOF without sending trailer
+ break
+ if line == '\r\n':
+ break
def connect(self):
@@ -985,7 +1000,7 @@
self.putrequest(method, url, **skips)
- if body and ('content-length' not in header_names):
+ if body is not None and 'content-length' not in header_names:
self._set_content_length(body)
for hdr, value in headers.iteritems():
self.putheader(hdr, value)
@@ -1058,7 +1073,7 @@
if port == 0:
port = None
- # Note that we may pass an empty string as the host; this will throw
+ # Note that we may pass an empty string as the host; this will raise
# an error when we attempt to connect. Presumably, the client code
# will call connect before then, with a proper host.
self._setup(self._connection_class(host, port, strict))
diff --git a/lib-python/2.7/idlelib/CallTips.py b/lib-python/2.7/idlelib/CallTips.py
--- a/lib-python/2.7/idlelib/CallTips.py
+++ b/lib-python/2.7/idlelib/CallTips.py
@@ -71,16 +71,16 @@
if not sur_paren:
return
hp.set_index(sur_paren[0])
- name = hp.get_expression()
- if not name or (not evalfuncs and name.find('(') != -1):
+ expression = hp.get_expression()
+ if not expression or (not evalfuncs and expression.find('(') != -1):
return
- arg_text = self.fetch_tip(name)
+ arg_text = self.fetch_tip(expression)
if not arg_text:
return
self.calltip = self._make_calltip_window()
self.calltip.showtip(arg_text, sur_paren[0], sur_paren[1])
- def fetch_tip(self, name):
+ def fetch_tip(self, expression):
"""Return the argument list and docstring of a function or class
If there is a Python subprocess, get the calltip there. Otherwise,
@@ -96,23 +96,27 @@
"""
try:
rpcclt = self.editwin.flist.pyshell.interp.rpcclt
- except:
+ except AttributeError:
rpcclt = None
if rpcclt:
return rpcclt.remotecall("exec", "get_the_calltip",
- (name,), {})
+ (expression,), {})
else:
- entity = self.get_entity(name)
+ entity = self.get_entity(expression)
return get_arg_text(entity)
- def get_entity(self, name):
- "Lookup name in a namespace spanning sys.modules and __main.dict__"
- if name:
+ def get_entity(self, expression):
+ """Return the object corresponding to expression evaluated
+ in a namespace spanning sys.modules and __main.dict__.
+ """
+ if expression:
namespace = sys.modules.copy()
namespace.update(__main__.__dict__)
try:
- return eval(name, namespace)
- except (NameError, AttributeError):
+ return eval(expression, namespace)
+ except BaseException:
+ # An uncaught exception closes idle, and eval can raise any
+ # exception, especially if user classes are involved.
return None
def _find_constructor(class_ob):
@@ -127,9 +131,10 @@
return None
def get_arg_text(ob):
- """Get a string describing the arguments for the given object"""
+ """Get a string describing the arguments for the given object,
+ only if it is callable."""
arg_text = ""
- if ob is not None:
+ if ob is not None and hasattr(ob, '__call__'):
arg_offset = 0
if type(ob) in (types.ClassType, types.TypeType):
# Look for the highest __init__ in the class chain.
diff --git a/lib-python/2.7/idlelib/ColorDelegator.py b/lib-python/2.7/idlelib/ColorDelegator.py
--- a/lib-python/2.7/idlelib/ColorDelegator.py
+++ b/lib-python/2.7/idlelib/ColorDelegator.py
@@ -20,10 +20,11 @@
# 1st 'file' colorized normal, 2nd as builtin, 3rd as string
builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b"
comment = any("COMMENT", [r"#[^\n]*"])
- sqstring = r"(\b[rRuU])?'[^'\\\n]*(\\.[^'\\\n]*)*'?"
- dqstring = r'(\b[rRuU])?"[^"\\\n]*(\\.[^"\\\n]*)*"?'
- sq3string = r"(\b[rRuU])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
- dq3string = r'(\b[rRuU])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
+ stringprefix = r"(\br|u|ur|R|U|UR|Ur|uR|b|B|br|Br|bR|BR)?"
+ sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?"
+ dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?'
+ sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
+ dq3string = stringprefix + r'"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
return kw + "|" + builtin + "|" + comment + "|" + string +\
"|" + any("SYNC", [r"\n"])
diff --git a/lib-python/2.7/idlelib/EditorWindow.py b/lib-python/2.7/idlelib/EditorWindow.py
--- a/lib-python/2.7/idlelib/EditorWindow.py
+++ b/lib-python/2.7/idlelib/EditorWindow.py
@@ -172,13 +172,13 @@
'recent-files.lst')
self.text_frame = text_frame = Frame(top)
self.vbar = vbar = Scrollbar(text_frame, name='vbar')
- self.width = idleConf.GetOption('main','EditorWindow','width')
+ self.width = idleConf.GetOption('main','EditorWindow','width', type='int')
text_options = {
'name': 'text',
'padx': 5,
'wrap': 'none',
'width': self.width,
- 'height': idleConf.GetOption('main', 'EditorWindow', 'height')}
+ 'height': idleConf.GetOption('main', 'EditorWindow', 'height', type='int')}
if TkVersion >= 8.5:
# Starting with tk 8.5 we have to set the new tabstyle option
# to 'wordprocessor' to achieve the same display of tabs as in
@@ -255,7 +255,8 @@
if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'):
fontWeight='bold'
text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'),
- idleConf.GetOption('main', 'EditorWindow', 'font-size'),
+ idleConf.GetOption('main', 'EditorWindow',
+ 'font-size', type='int'),
fontWeight))
text_frame.pack(side=LEFT, fill=BOTH, expand=1)
text.pack(side=TOP, fill=BOTH, expand=1)
@@ -470,7 +471,6 @@
rmenu = None
def right_menu_event(self, event):
- self.text.tag_remove("sel", "1.0", "end")
self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
if not self.rmenu:
self.make_rmenu()
@@ -479,23 +479,52 @@
iswin = sys.platform[:3] == 'win'
if iswin:
self.text.config(cursor="arrow")
+
+ for label, eventname, verify_state in self.rmenu_specs:
+ if verify_state is None:
+ continue
+ state = getattr(self, verify_state)()
+ rmenu.entryconfigure(label, state=state)
+
rmenu.tk_popup(event.x_root, event.y_root)
if iswin:
self.text.config(cursor="ibeam")
rmenu_specs = [
- # ("Label", "<<virtual-event>>"), ...
- ("Close", "<<close-window>>"), # Example
+ # ("Label", "<<virtual-event>>", "statefuncname"), ...
+ ("Close", "<<close-window>>", None), # Example
]
def make_rmenu(self):
rmenu = Menu(self.text, tearoff=0)
- for label, eventname in self.rmenu_specs:
- def command(text=self.text, eventname=eventname):
- text.event_generate(eventname)
- rmenu.add_command(label=label, command=command)
+ for label, eventname, _ in self.rmenu_specs:
+ if label is not None:
+ def command(text=self.text, eventname=eventname):
+ text.event_generate(eventname)
+ rmenu.add_command(label=label, command=command)
+ else:
+ rmenu.add_separator()
self.rmenu = rmenu
+ def rmenu_check_cut(self):
+ return self.rmenu_check_copy()
+
+ def rmenu_check_copy(self):
+ try:
+ indx = self.text.index('sel.first')
+ except TclError:
+ return 'disabled'
+ else:
+ return 'normal' if indx else 'disabled'
+
+ def rmenu_check_paste(self):
+ try:
+ self.text.tk.call('tk::GetSelection', self.text, 'CLIPBOARD')
+ except TclError:
+ return 'disabled'
+ else:
+ return 'normal'
+
def about_dialog(self, event=None):
aboutDialog.AboutDialog(self.top,'About IDLE')
@@ -735,7 +764,8 @@
if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
fontWeight='bold'
self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
- idleConf.GetOption('main','EditorWindow','font-size'),
+ idleConf.GetOption('main','EditorWindow','font-size',
+ type='int'),
fontWeight))
def RemoveKeybindings(self):
@@ -856,7 +886,7 @@
# for each edit window instance, construct the recent files menu
for instance in self.top.instance_dict.keys():
menu = instance.recent_files_menu
- menu.delete(1, END) # clear, and rebuild:
+ menu.delete(0, END) # clear, and rebuild:
for i, file_name in enumerate(rf_list):
file_name = file_name.rstrip() # zap \n
# make unicode string to display non-ASCII chars correctly
@@ -1581,7 +1611,7 @@
try:
try:
_tokenize.tokenize(self.readline, self.tokeneater)
- except _tokenize.TokenError:
+ except (_tokenize.TokenError, SyntaxError):
# since we cut off the tokenizer early, we can trigger
# spurious errors
pass
diff --git a/lib-python/2.7/idlelib/FormatParagraph.py b/lib-python/2.7/idlelib/FormatParagraph.py
--- a/lib-python/2.7/idlelib/FormatParagraph.py
+++ b/lib-python/2.7/idlelib/FormatParagraph.py
@@ -32,7 +32,8 @@
self.editwin = None
def format_paragraph_event(self, event):
- maxformatwidth = int(idleConf.GetOption('main','FormatParagraph','paragraph'))
+ maxformatwidth = int(idleConf.GetOption('main','FormatParagraph',
+ 'paragraph', type='int'))
text = self.editwin.text
first, last = self.editwin.get_selection_indices()
if first and last:
diff --git a/lib-python/2.7/idlelib/HyperParser.py b/lib-python/2.7/idlelib/HyperParser.py
--- a/lib-python/2.7/idlelib/HyperParser.py
+++ b/lib-python/2.7/idlelib/HyperParser.py
@@ -232,6 +232,11 @@
pass
else:
# We can't continue after other types of brackets
+ if rawtext[pos] in "'\"":
+ # Scan a string prefix
+ while pos > 0 and rawtext[pos - 1] in "rRbBuU":
+ pos -= 1
+ last_identifier_pos = pos
break
else:
diff --git a/lib-python/2.7/idlelib/IOBinding.py b/lib-python/2.7/idlelib/IOBinding.py
--- a/lib-python/2.7/idlelib/IOBinding.py
+++ b/lib-python/2.7/idlelib/IOBinding.py
@@ -7,6 +7,7 @@
import os
import types
+import pipes
import sys
import codecs
import tempfile
@@ -196,29 +197,33 @@
self.filename_change_hook()
def open(self, event=None, editFile=None):
- if self.editwin.flist:
+ flist = self.editwin.flist
+ # Save in case parent window is closed (ie, during askopenfile()).
+ if flist:
if not editFile:
filename = self.askopenfile()
else:
filename=editFile
if filename:
- # If the current window has no filename and hasn't been
- # modified, we replace its contents (no loss). Otherwise
- # we open a new window. But we won't replace the
- # shell window (which has an interp(reter) attribute), which
- # gets set to "not modified" at every new prompt.
- try:
- interp = self.editwin.interp
- except AttributeError:
- interp = None
- if not self.filename and self.get_saved() and not interp:
- self.editwin.flist.open(filename, self.loadfile)
+ # If editFile is valid and already open, flist.open will
+ # shift focus to its existing window.
+ # If the current window exists and is a fresh unnamed,
+ # unmodified editor window (not an interpreter shell),
+ # pass self.loadfile to flist.open so it will load the file
+ # in the current window (if the file is not already open)
+ # instead of a new window.
+ if (self.editwin and
+ not getattr(self.editwin, 'interp', None) and
+ not self.filename and
+ self.get_saved()):
+ flist.open(filename, self.loadfile)
else:
- self.editwin.flist.open(filename)
+ flist.open(filename)
else:
- self.text.focus_set()
+ if self.text:
+ self.text.focus_set()
return "break"
- #
+
# Code for use outside IDLE:
if self.get_saved():
reply = self.maybesave()
@@ -499,7 +504,7 @@
else: #no printing for this platform
printPlatform = False
if printPlatform: #we can try to print for this platform
- command = command % filename
+ command = command % pipes.quote(filename)
pipe = os.popen(command, "r")
# things can get ugly on NT if there is no printer available.
output = pipe.read().strip()
diff --git a/lib-python/2.7/idlelib/NEWS.txt b/lib-python/2.7/idlelib/NEWS.txt
--- a/lib-python/2.7/idlelib/NEWS.txt
+++ b/lib-python/2.7/idlelib/NEWS.txt
@@ -1,5 +1,38 @@
+What's New in IDLE 2.7.4?
+=========================
+
+- Issue #15318: Prevent writing to sys.stdin.
+
+- Issue #13532, #15319: Check that arguments to sys.stdout.write are strings.
+
+- Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE.
+
+- Issue10365: File open dialog now works instead of crashing even when
+ parent window is closed while dialog is open.
+
+- Issue 14876: use user-selected font for highlight configuration.
+
+- Issue #14018: Update checks for unstable system Tcl/Tk versions on OS X
+ to include versions shipped with OS X 10.7 and 10.8 in addition to 10.6.
+
+- Issue #15853: Prevent IDLE crash on OS X when opening Preferences menu
+ with certain versions of Tk 8.5. Initial patch by Kevin Walzer.
+
+
+What's New in IDLE 2.7.3?
+=========================
+
+- Issue #14409: IDLE now properly executes commands in the Shell window
+ when it cannot read the normal config files on startup and
+ has to use the built-in default key bindings.
+ There was previously a bug in one of the defaults.
+
+- Issue #3573: IDLE hangs when passing invalid command line args
+ (directory(ies) instead of file(s)).
+
+
What's New in IDLE 2.7.2?
-=======================
+=========================
*Release date: 29-May-2011*
diff --git a/lib-python/2.7/idlelib/OutputWindow.py b/lib-python/2.7/idlelib/OutputWindow.py
--- a/lib-python/2.7/idlelib/OutputWindow.py
+++ b/lib-python/2.7/idlelib/OutputWindow.py
@@ -57,7 +57,11 @@
# Our own right-button menu
rmenu_specs = [
- ("Go to file/line", "<<goto-file-line>>"),
+ ("Cut", "<<cut>>", "rmenu_check_cut"),
+ ("Copy", "<<copy>>", "rmenu_check_copy"),
+ ("Paste", "<<paste>>", "rmenu_check_paste"),
+ (None, None, None),
+ ("Go to file/line", "<<goto-file-line>>", None),
]
file_line_pats = [
diff --git a/lib-python/2.7/idlelib/PyShell.py b/lib-python/2.7/idlelib/PyShell.py
--- a/lib-python/2.7/idlelib/PyShell.py
+++ b/lib-python/2.7/idlelib/PyShell.py
@@ -11,6 +11,7 @@
import threading
import traceback
import types
+import io
import linecache
from code import InteractiveInterpreter
@@ -121,8 +122,13 @@
old_hook()
self.io.set_filename_change_hook(filename_changed_hook)
- rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
- ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
+ rmenu_specs = [
+ ("Cut", "<<cut>>", "rmenu_check_cut"),
+ ("Copy", "<<copy>>", "rmenu_check_copy"),
+ ("Paste", "<<paste>>", "rmenu_check_paste"),
+ ("Set Breakpoint", "<<set-breakpoint-here>>", None),
+ ("Clear Breakpoint", "<<clear-breakpoint-here>>", None)
+ ]
def set_breakpoint(self, lineno):
text = self.text
@@ -251,8 +257,8 @@
def ranges_to_linenumbers(self, ranges):
lines = []
for index in range(0, len(ranges), 2):
- lineno = int(float(ranges[index]))
- end = int(float(ranges[index+1]))
+ lineno = int(float(ranges[index].string))
+ end = int(float(ranges[index+1].string))
while lineno < end:
lines.append(lineno)
lineno += 1
@@ -313,6 +319,11 @@
"console": idleConf.GetHighlight(theme, "console"),
})
+ def removecolors(self):
+ # Don't remove shell color tags before "iomark"
+ for tag in self.tagdefs:
+ self.tag_remove(tag, "iomark", "end")
+
class ModifiedUndoDelegator(UndoDelegator):
"Extend base class: forbid insert/delete before the I/O mark"
@@ -417,7 +428,8 @@
except socket.timeout, err:
self.display_no_subprocess_error()
return None
- self.rpcclt.register("stdin", self.tkconsole)
+ self.rpcclt.register("console", self.tkconsole)
+ self.rpcclt.register("stdin", self.tkconsole.stdin)
self.rpcclt.register("stdout", self.tkconsole.stdout)
self.rpcclt.register("stderr", self.tkconsole.stderr)
self.rpcclt.register("flist", self.tkconsole.flist)
@@ -870,13 +882,14 @@
self.save_stderr = sys.stderr
self.save_stdin = sys.stdin
from idlelib import IOBinding
- self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
- self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
- self.console = PseudoFile(self, "console", IOBinding.encoding)
+ self.stdin = PseudoInputFile(self, "stdin", IOBinding.encoding)
+ self.stdout = PseudoOutputFile(self, "stdout", IOBinding.encoding)
+ self.stderr = PseudoOutputFile(self, "stderr", IOBinding.encoding)
+ self.console = PseudoOutputFile(self, "console", IOBinding.encoding)
if not use_subprocess:
sys.stdout = self.stdout
sys.stderr = self.stderr
- sys.stdin = self
+ sys.stdin = self.stdin
#
self.history = self.History(self.text)
#
@@ -1251,28 +1264,98 @@
if not use_subprocess:
raise KeyboardInterrupt
-class PseudoFile(object):
+ def rmenu_check_cut(self):
+ try:
+ if self.text.compare('sel.first', '<', 'iomark'):
+ return 'disabled'
+ except TclError: # no selection, so the index 'sel.first' doesn't exist
+ return 'disabled'
+ return super(PyShell, self).rmenu_check_cut()
+
+ def rmenu_check_paste(self):
+ if self.text.compare('insert', '<', 'iomark'):
+ return 'disabled'
+ return super(PyShell, self).rmenu_check_paste()
+
+class PseudoFile(io.TextIOBase):
def __init__(self, shell, tags, encoding=None):
self.shell = shell
self.tags = tags
self.softspace = 0
- self.encoding = encoding
+ self._encoding = encoding
- def write(self, s):
- self.shell.write(s, self.tags)
+ @property
+ def encoding(self):
+ return self._encoding
- def writelines(self, lines):
- for line in lines:
- self.write(line)
-
- def flush(self):
- pass
+ @property
+ def name(self):
+ return '<%s>' % self.tags
def isatty(self):
return True
+class PseudoOutputFile(PseudoFile):
+
+ def writable(self):
+ return True
+
+ def write(self, s):
+ if self.closed:
+ raise ValueError("write to closed file")
+ if not isinstance(s, (basestring, bytearray)):
+ raise TypeError('must be string, not ' + type(s).__name__)
+ return self.shell.write(s, self.tags)
+
+
+class PseudoInputFile(PseudoFile):
+
+ def __init__(self, shell, tags, encoding=None):
+ PseudoFile.__init__(self, shell, tags, encoding)
+ self._line_buffer = ''
+
+ def readable(self):
+ return True
+
+ def read(self, size=-1):
+ if self.closed:
+ raise ValueError("read from closed file")
+ if size is None:
+ size = -1
+ elif not isinstance(size, int):
+ raise TypeError('must be int, not ' + type(size).__name__)
+ result = self._line_buffer
+ self._line_buffer = ''
+ if size < 0:
+ while True:
+ line = self.shell.readline()
+ if not line: break
+ result += line
+ else:
+ while len(result) < size:
+ line = self.shell.readline()
+ if not line: break
+ result += line
+ self._line_buffer = result[size:]
+ result = result[:size]
+ return result
+
+ def readline(self, size=-1):
+ if self.closed:
+ raise ValueError("read from closed file")
+ if size is None:
+ size = -1
+ elif not isinstance(size, int):
+ raise TypeError('must be int, not ' + type(size).__name__)
+ line = self._line_buffer or self.shell.readline()
+ if size < 0:
+ size = len(line)
+ self._line_buffer = line[size:]
+ return line[:size]
+
+
usage_msg = """\
USAGE: idle [-deins] [-t title] [file]*
@@ -1412,8 +1495,10 @@
if enable_edit:
if not (cmd or script):
- for filename in args:
- flist.open(filename)
+ for filename in args[:]:
+ if flist.open(filename) is None:
+ # filename is a directory actually, disconsider it
+ args.remove(filename)
if not args:
flist.new()
if enable_shell:
@@ -1456,7 +1541,8 @@
if tkversionwarning:
shell.interp.runcommand(''.join(("print('", tkversionwarning, "')")))
- root.mainloop()
+ while flist.inversedict: # keep IDLE running while files are open.
+ root.mainloop()
root.destroy()
if __name__ == "__main__":
diff --git a/lib-python/2.7/idlelib/ReplaceDialog.py b/lib-python/2.7/idlelib/ReplaceDialog.py
--- a/lib-python/2.7/idlelib/ReplaceDialog.py
+++ b/lib-python/2.7/idlelib/ReplaceDialog.py
@@ -2,6 +2,8 @@
from idlelib import SearchEngine
from idlelib.SearchDialogBase import SearchDialogBase
+import re
+
def replace(text):
root = text._root()
@@ -11,6 +13,7 @@
dialog = engine._replacedialog
dialog.open(text)
+
class ReplaceDialog(SearchDialogBase):
title = "Replace Dialog"
@@ -55,8 +58,22 @@
def default_command(self, event=None):
if self.do_find(self.ok):
- self.do_replace()
- self.do_find(0)
+ if self.do_replace(): # Only find next match if replace succeeded.
+ # A bad re can cause a it to fail.
+ self.do_find(0)
+
+ def _replace_expand(self, m, repl):
+ """ Helper function for expanding a regular expression
+ in the replace field, if needed. """
+ if self.engine.isre():
+ try:
+ new = m.expand(repl)
+ except re.error:
+ self.engine.report_error(repl, 'Invalid Replace Expression')
+ new = None
+ else:
+ new = repl
+ return new
def replace_all(self, event=None):
prog = self.engine.getprog()
@@ -86,7 +103,9 @@
line, m = res
chars = text.get("%d.0" % line, "%d.0" % (line+1))
orig = m.group()
- new = m.expand(repl)
+ new = self._replace_expand(m, repl)
+ if new is None:
+ break
i, j = m.span()
first = "%d.%d" % (line, i)
last = "%d.%d" % (line, j)
@@ -103,7 +122,6 @@
text.undo_block_stop()
if first and last:
self.show_hit(first, last)
- self.close()
def do_find(self, ok=0):
if not self.engine.getprog():
@@ -138,7 +156,9 @@
m = prog.match(chars, col)
if not prog:
return False
- new = m.expand(self.replvar.get())
+ new = self._replace_expand(m, self.replvar.get())
+ if new is None:
+ return False
text.mark_set("insert", first)
text.undo_block_start()
if m.group():
diff --git a/lib-python/2.7/idlelib/config-extensions.def b/lib-python/2.7/idlelib/config-extensions.def
--- a/lib-python/2.7/idlelib/config-extensions.def
+++ b/lib-python/2.7/idlelib/config-extensions.def
@@ -46,6 +46,8 @@
[ScriptBinding]
enable=1
+enable_shell=0
+enable_editor=1
[ScriptBinding_cfgBindings]
run-module=<Key-F5>
check-module=<Alt-Key-x>
diff --git a/lib-python/2.7/idlelib/configDialog.py b/lib-python/2.7/idlelib/configDialog.py
--- a/lib-python/2.7/idlelib/configDialog.py
+++ b/lib-python/2.7/idlelib/configDialog.py
@@ -183,7 +183,7 @@
text=' Highlighting Theme ')
#frameCustom
self.textHighlightSample=Text(frameCustom,relief=SOLID,borderwidth=1,
- font=('courier',12,''),cursor='hand2',width=21,height=10,
+ font=('courier',12,''),cursor='hand2',width=21,height=11,
takefocus=FALSE,highlightthickness=0,wrap=NONE)
text=self.textHighlightSample
text.bind('<Double-Button-1>',lambda e: 'break')
@@ -832,8 +832,9 @@
fontWeight=tkFont.BOLD
else:
fontWeight=tkFont.NORMAL
- self.editFont.config(size=self.fontSize.get(),
- weight=fontWeight,family=fontName)
+ newFont = (fontName, self.fontSize.get(), fontWeight)
+ self.labelFontSample.config(font=newFont)
+ self.textHighlightSample.configure(font=newFont)
def SetHighlightTarget(self):
if self.highlightTarget.get()=='Cursor': #bg not possible
@@ -946,7 +947,7 @@
self.listFontName.select_anchor(currentFontIndex)
##font size dropdown
fontSize=idleConf.GetOption('main','EditorWindow','font-size',
- default='10')
+ type='int', default='10')
self.optMenuFontSize.SetMenu(('7','8','9','10','11','12','13','14',
'16','18','20','22'),fontSize )
##fontWeight
@@ -1032,10 +1033,13 @@
self.autoSave.set(idleConf.GetOption('main', 'General', 'autosave',
default=0, type='bool'))
#initial window size
- self.winWidth.set(idleConf.GetOption('main','EditorWindow','width'))
- self.winHeight.set(idleConf.GetOption('main','EditorWindow','height'))
+ self.winWidth.set(idleConf.GetOption('main','EditorWindow','width',
+ type='int'))
+ self.winHeight.set(idleConf.GetOption('main','EditorWindow','height',
+ type='int'))
#initial paragraph reformat size
- self.paraWidth.set(idleConf.GetOption('main','FormatParagraph','paragraph'))
+ self.paraWidth.set(idleConf.GetOption('main','FormatParagraph','paragraph',
+ type='int'))
# default source encoding
self.encoding.set(idleConf.GetOption('main', 'EditorWindow',
'encoding', default='none'))
diff --git a/lib-python/2.7/idlelib/configHandler.py b/lib-python/2.7/idlelib/configHandler.py
--- a/lib-python/2.7/idlelib/configHandler.py
+++ b/lib-python/2.7/idlelib/configHandler.py
@@ -237,24 +237,39 @@
printed to stderr.
"""
- if self.userCfg[configType].has_option(section,option):
- return self.userCfg[configType].Get(section, option,
- type=type, raw=raw)
- elif self.defaultCfg[configType].has_option(section,option):
- return self.defaultCfg[configType].Get(section, option,
- type=type, raw=raw)
- else: #returning default, print warning
- if warn_on_default:
- warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
- ' problem retrieving configuration option %r\n'
- ' from section %r.\n'
- ' returning default value: %r\n' %
- (option, section, default))
- try:
- sys.stderr.write(warning)
- except IOError:
- pass
- return default
+ try:
+ if self.userCfg[configType].has_option(section,option):
+ return self.userCfg[configType].Get(section, option,
+ type=type, raw=raw)
+ except ValueError:
+ warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
+ ' invalid %r value for configuration option %r\n'
+ ' from section %r: %r\n' %
+ (type, option, section,
+ self.userCfg[configType].Get(section, option,
+ raw=raw)))
+ try:
+ sys.stderr.write(warning)
+ except IOError:
+ pass
+ try:
+ if self.defaultCfg[configType].has_option(section,option):
+ return self.defaultCfg[configType].Get(section, option,
+ type=type, raw=raw)
+ except ValueError:
+ pass
+ #returning default, print warning
+ if warn_on_default:
+ warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
+ ' problem retrieving configuration option %r\n'
+ ' from section %r.\n'
+ ' returning default value: %r\n' %
+ (option, section, default))
+ try:
+ sys.stderr.write(warning)
+ except IOError:
+ pass
+ return default
def SetOption(self, configType, section, option, value):
"""In user's config file, set section's option to value.
@@ -595,7 +610,7 @@
'<<replace>>': ['<Control-h>'],
'<<goto-line>>': ['<Alt-g>'],
'<<smart-backspace>>': ['<Key-BackSpace>'],
- '<<newline-and-indent>>': ['<Key-Return> <Key-KP_Enter>'],
+ '<<newline-and-indent>>': ['<Key-Return>', '<Key-KP_Enter>'],
'<<smart-indent>>': ['<Key-Tab>'],
'<<indent-region>>': ['<Control-Key-bracketright>'],
'<<dedent-region>>': ['<Control-Key-bracketleft>'],
diff --git a/lib-python/2.7/idlelib/help.txt b/lib-python/2.7/idlelib/help.txt
--- a/lib-python/2.7/idlelib/help.txt
+++ b/lib-python/2.7/idlelib/help.txt
@@ -80,7 +80,7 @@
Debug Menu (only in Shell window):
Go to File/Line -- look around the insert point for a filename
- and linenumber, open the file, and show the line
+ and line number, open the file, and show the line
Debugger (toggle) -- Run commands in the shell under the debugger
Stack Viewer -- Show the stack traceback of the last exception
Auto-open Stack Viewer (toggle) -- Open stack viewer on traceback
@@ -92,7 +92,7 @@
Startup Preferences may be set, and Additional Help
Sources can be specified.
- On MacOS X this menu is not present, use
+ On OS X this menu is not present, use
menu 'IDLE -> Preferences...' instead.
---
Code Context -- Open a pane at the top of the edit window which
@@ -120,6 +120,24 @@
---
(Additional Help Sources may be added here)
+Edit context menu (Right-click / Control-click on OS X in Edit window):
+
+ Cut -- Copy a selection into system-wide clipboard,
+ then delete the selection
+ Copy -- Copy selection into system-wide clipboard
+ Paste -- Insert system-wide clipboard into window
+ Set Breakpoint -- Sets a breakpoint (when debugger open)
+ Clear Breakpoint -- Clears the breakpoint on that line
+
+Shell context menu (Right-click / Control-click on OS X in Shell window):
+
+ Cut -- Copy a selection into system-wide clipboard,
+ then delete the selection
+ Copy -- Copy selection into system-wide clipboard
+ Paste -- Insert system-wide clipboard into window
+ ---
+ Go to file/line -- Same as in Debug menu
+
** TIPS **
==========
@@ -222,7 +240,7 @@
Alt-p retrieves previous command matching what you have typed.
Alt-n retrieves next.
- (These are Control-p, Control-n on the Mac)
+ (These are Control-p, Control-n on OS X)
Return while cursor is on a previous command retrieves that command.
Expand word is also useful to reduce typing.
diff --git a/lib-python/2.7/idlelib/idlever.py b/lib-python/2.7/idlelib/idlever.py
--- a/lib-python/2.7/idlelib/idlever.py
+++ b/lib-python/2.7/idlelib/idlever.py
@@ -1,1 +1,1 @@
-IDLE_VERSION = "2.7.3rc2"
+IDLE_VERSION = "2.7.3"
diff --git a/lib-python/2.7/idlelib/macosxSupport.py b/lib-python/2.7/idlelib/macosxSupport.py
--- a/lib-python/2.7/idlelib/macosxSupport.py
+++ b/lib-python/2.7/idlelib/macosxSupport.py
@@ -37,17 +37,21 @@
def tkVersionWarning(root):
"""
Returns a string warning message if the Tk version in use appears to
- be one known to cause problems with IDLE. The Apple Cocoa-based Tk 8.5
- that was shipped with Mac OS X 10.6.
+ be one known to cause problems with IDLE.
+ 1. Apple Cocoa-based Tk 8.5.7 shipped with Mac OS X 10.6 is unusable.
+ 2. Apple Cocoa-based Tk 8.5.9 in OS X 10.7 and 10.8 is better but
+ can still crash unexpectedly.
"""
if (runningAsOSXApp() and
- ('AppKit' in root.tk.call('winfo', 'server', '.')) and
- (root.tk.call('info', 'patchlevel') == '8.5.7') ):
- return (r"WARNING: The version of Tcl/Tk (8.5.7) in use may"
+ ('AppKit' in root.tk.call('winfo', 'server', '.')) ):
+ patchlevel = root.tk.call('info', 'patchlevel')
+ if patchlevel not in ('8.5.7', '8.5.9'):
+ return False
+ return (r"WARNING: The version of Tcl/Tk ({0}) in use may"
r" be unstable.\n"
r"Visit http://www.python.org/download/mac/tcltk/"
- r" for current information.")
+ r" for current information.".format(patchlevel))
else:
return False
diff --git a/lib-python/2.7/idlelib/run.py b/lib-python/2.7/idlelib/run.py
--- a/lib-python/2.7/idlelib/run.py
+++ b/lib-python/2.7/idlelib/run.py
@@ -1,4 +1,5 @@
import sys
+import io
import linecache
import time
import socket
@@ -14,6 +15,8 @@
from idlelib import RemoteObjectBrowser
from idlelib import StackViewer
from idlelib import rpc
+from idlelib import PyShell
+from idlelib import IOBinding
import __main__
@@ -248,19 +251,19 @@
quitting = True
thread.interrupt_main()
-
class MyHandler(rpc.RPCHandler):
def handle(self):
"""Override base method"""
executive = Executive(self)
self.register("exec", executive)
- sys.stdin = self.console = self.get_remote_proxy("stdin")
- sys.stdout = self.get_remote_proxy("stdout")
- sys.stderr = self.get_remote_proxy("stderr")
- from idlelib import IOBinding
- sys.stdin.encoding = sys.stdout.encoding = \
- sys.stderr.encoding = IOBinding.encoding
+ self.console = self.get_remote_proxy("console")
+ sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
+ IOBinding.encoding)
+ sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
+ IOBinding.encoding)
+ sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
+ IOBinding.encoding)
self.interp = self.get_remote_proxy("interp")
rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
@@ -298,11 +301,14 @@
exec code in self.locals
finally:
interruptable = False
+ except SystemExit:
+ # Scripts that raise SystemExit should just
+ # return to the interactive prompt
+ pass
except:
self.usr_exc_info = sys.exc_info()
if quitting:
exit()
- # even print a user code SystemExit exception, continue
print_exception()
jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
if jit:
diff --git a/lib-python/2.7/io.py b/lib-python/2.7/io.py
--- a/lib-python/2.7/io.py
+++ b/lib-python/2.7/io.py
@@ -4,7 +4,7 @@
At the top of the I/O hierarchy is the abstract base class IOBase. It
defines the basic interface to a stream. Note, however, that there is no
separation between reading and writing to streams; implementations are
-allowed to throw an IOError if they do not support a given operation.
+allowed to raise an IOError if they do not support a given operation.
Extending IOBase is RawIOBase which deals simply with the reading and
writing of raw bytes to a stream. FileIO subclasses RawIOBase to provide
@@ -34,15 +34,6 @@
"""
# New I/O library conforming to PEP 3116.
-# XXX edge cases when switching between reading/writing
-# XXX need to support 1 meaning line-buffered
-# XXX whenever an argument is None, use the default value
-# XXX read/write ops should check readable/writable
-# XXX buffered readinto should work with arbitrary buffer objects
-# XXX use incremental encoder for text output, at least for UTF-16 and UTF-8-SIG
-# XXX check writable, readable and seekable in appropriate places
-
-
__author__ = ("Guido van Rossum <guido at python.org>, "
"Mike Verdone <mike.verdone at gmail.com>, "
"Mark Russell <mark.russell at zen.co.uk>, "
diff --git a/lib-python/2.7/json/__init__.py b/lib-python/2.7/json/__init__.py
--- a/lib-python/2.7/json/__init__.py
+++ b/lib-python/2.7/json/__init__.py
@@ -37,8 +37,8 @@
Pretty printing::
>>> import json
- >>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)
- >>> print '\n'.join([l.rstrip() for l in s.splitlines()])
+ >>> print json.dumps({'4': 5, '6': 7}, sort_keys=True,
+ ... indent=4, separators=(',', ': '))
{
"4": 5,
"6": 7
@@ -95,7 +95,7 @@
"json": "obj"
}
$ echo '{ 1.2:3.4}' | python -m json.tool
- Expecting property name: line 1 column 2 (char 2)
+ Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
"""
__version__ = '2.0.9'
__all__ = [
@@ -121,7 +121,7 @@
def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
- encoding='utf-8', default=None, **kw):
+ encoding='utf-8', default=None, sort_keys=False, **kw):
"""Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
``.write()``-supporting file-like object).
@@ -129,11 +129,14 @@
(``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
will be skipped instead of raising a ``TypeError``.
- If ``ensure_ascii`` is false, then the some chunks written to ``fp``
- may be ``unicode`` instances, subject to normal Python ``str`` to
- ``unicode`` coercion rules. Unless ``fp.write()`` explicitly
- understands ``unicode`` (as in ``codecs.getwriter()``) this is likely
- to cause an error.
+ If ``ensure_ascii`` is true (the default), all non-ASCII characters in the
+ output are escaped with ``\uXXXX`` sequences, and the result is a ``str``
+ instance consisting of ASCII characters only. If ``ensure_ascii`` is
+ ``False``, some chunks written to ``fp`` may be ``unicode`` instances.
+ This usually happens because the input contains unicode strings or the
+ ``encoding`` parameter is used. Unless ``fp.write()`` explicitly
+ understands ``unicode`` (as in ``codecs.getwriter``) this is likely to
+ cause an error.
If ``check_circular`` is false, then the circular reference check
for container types will be skipped and a circular reference will
@@ -147,7 +150,9 @@
If ``indent`` is a non-negative integer, then JSON array elements and
object members will be pretty-printed with that indent level. An indent
level of 0 will only insert newlines. ``None`` is the most compact
- representation.
+ representation. Since the default item separator is ``', '``, the
+ output might include trailing whitespace when ``indent`` is specified.
+ You can use ``separators=(',', ': ')`` to avoid this.
If ``separators`` is an ``(item_separator, dict_separator)`` tuple
then it will be used instead of the default ``(', ', ': ')`` separators.
@@ -158,6 +163,9 @@
``default(obj)`` is a function that should return a serializable version
of obj or raise TypeError. The default simply raises TypeError.
+ If *sort_keys* is ``True`` (default: ``False``), then the output of
+ dictionaries will be sorted by key.
+
To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
``.default()`` method to serialize additional types), specify it with
the ``cls`` kwarg; otherwise ``JSONEncoder`` is used.
@@ -167,7 +175,7 @@
if (not skipkeys and ensure_ascii and
check_circular and allow_nan and
cls is None and indent is None and separators is None and
- encoding == 'utf-8' and default is None and not kw):
+ encoding == 'utf-8' and default is None and not sort_keys and not kw):
iterable = _default_encoder.iterencode(obj)
else:
if cls is None:
@@ -175,7 +183,7 @@
iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
check_circular=check_circular, allow_nan=allow_nan, indent=indent,
separators=separators, encoding=encoding,
- default=default, **kw).iterencode(obj)
+ default=default, sort_keys=sort_keys, **kw).iterencode(obj)
# could accelerate with writelines in some versions of Python, at
# a debuggability cost
for chunk in iterable:
@@ -184,16 +192,15 @@
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
- encoding='utf-8', default=None, **kw):
+ encoding='utf-8', default=None, sort_keys=False, **kw):
"""Serialize ``obj`` to a JSON formatted ``str``.
If ``skipkeys`` is false then ``dict`` keys that are not basic types
(``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
will be skipped instead of raising a ``TypeError``.
- If ``ensure_ascii`` is false, then the return value will be a
- ``unicode`` instance subject to normal Python ``str`` to ``unicode``
- coercion rules instead of being escaped to an ASCII ``str``.
+ If ``ensure_ascii`` is false, all non-ASCII characters are not escaped, and
+ the return value may be a ``unicode`` instance. See ``dump`` for details.
If ``check_circular`` is false, then the circular reference check
for container types will be skipped and a circular reference will
@@ -207,7 +214,9 @@
If ``indent`` is a non-negative integer, then JSON array elements and
object members will be pretty-printed with that indent level. An indent
level of 0 will only insert newlines. ``None`` is the most compact
- representation.
+ representation. Since the default item separator is ``', '``, the
+ output might include trailing whitespace when ``indent`` is specified.
+ You can use ``separators=(',', ': ')`` to avoid this.
If ``separators`` is an ``(item_separator, dict_separator)`` tuple
then it will be used instead of the default ``(', ', ': ')`` separators.
@@ -218,6 +227,9 @@
``default(obj)`` is a function that should return a serializable version
of obj or raise TypeError. The default simply raises TypeError.
+ If *sort_keys* is ``True`` (default: ``False``), then the output of
+ dictionaries will be sorted by key.
+
To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
``.default()`` method to serialize additional types), specify it with
the ``cls`` kwarg; otherwise ``JSONEncoder`` is used.
@@ -227,7 +239,7 @@
if (not skipkeys and ensure_ascii and
check_circular and allow_nan and
cls is None and indent is None and separators is None and
- encoding == 'utf-8' and default is None and not kw):
+ encoding == 'utf-8' and default is None and not sort_keys and not kw):
return _default_encoder.encode(obj)
if cls is None:
cls = JSONEncoder
@@ -235,7 +247,7 @@
skipkeys=skipkeys, ensure_ascii=ensure_ascii,
check_circular=check_circular, allow_nan=allow_nan, indent=indent,
separators=separators, encoding=encoding, default=default,
- **kw).encode(obj)
+ sort_keys=sort_keys, **kw).encode(obj)
_default_decoder = JSONDecoder(encoding=None, object_hook=None,
diff --git a/lib-python/2.7/json/decoder.py b/lib-python/2.7/json/decoder.py
--- a/lib-python/2.7/json/decoder.py
+++ b/lib-python/2.7/json/decoder.py
@@ -27,7 +27,7 @@
def linecol(doc, pos):
lineno = doc.count('\n', 0, pos) + 1
if lineno == 1:
- colno = pos
+ colno = pos + 1
else:
colno = pos - doc.rindex('\n', 0, pos)
return lineno, colno
@@ -169,7 +169,8 @@
pairs = object_hook(pairs)
return pairs, end + 1
elif nextchar != '"':
- raise ValueError(errmsg("Expecting property name", s, end))
+ raise ValueError(errmsg(
+ "Expecting property name enclosed in double quotes", s, end))
end += 1
while True:
key, end = scanstring(s, end, encoding, strict)
@@ -179,8 +180,7 @@
if s[end:end + 1] != ':':
end = _w(s, end).end()
if s[end:end + 1] != ':':
- raise ValueError(errmsg("Expecting : delimiter", s, end))
-
+ raise ValueError(errmsg("Expecting ':' delimiter", s, end))
end += 1
try:
@@ -209,7 +209,7 @@
if nextchar == '}':
break
elif nextchar != ',':
- raise ValueError(errmsg("Expecting , delimiter", s, end - 1))
+ raise ValueError(errmsg("Expecting ',' delimiter", s, end - 1))
try:
nextchar = s[end]
@@ -224,8 +224,8 @@
end += 1
if nextchar != '"':
- raise ValueError(errmsg("Expecting property name", s, end - 1))
-
+ raise ValueError(errmsg(
+ "Expecting property name enclosed in double quotes", s, end - 1))
if object_pairs_hook is not None:
result = object_pairs_hook(pairs)
return result, end
@@ -259,8 +259,7 @@
if nextchar == ']':
break
elif nextchar != ',':
- raise ValueError(errmsg("Expecting , delimiter", s, end))
-
+ raise ValueError(errmsg("Expecting ',' delimiter", s, end))
try:
if s[end] in _ws:
end += 1
diff --git a/lib-python/2.7/json/encoder.py b/lib-python/2.7/json/encoder.py
--- a/lib-python/2.7/json/encoder.py
+++ b/lib-python/2.7/json/encoder.py
@@ -27,8 +27,7 @@
ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
#ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
-# Assume this produces an infinity on all machines (probably not guaranteed)
-INFINITY = float('1e66666')
+INFINITY = float('inf')
FLOAT_REPR = repr
def encode_basestring(s):
@@ -108,9 +107,12 @@
encoding of keys that are not str, int, long, float or None. If
skipkeys is True, such items are simply skipped.
- If ensure_ascii is true, the output is guaranteed to be str
- objects with all incoming unicode characters escaped. If
- ensure_ascii is false, the output will be unicode object.
+ If *ensure_ascii* is true (the default), all non-ASCII
+ characters in the output are escaped with \uXXXX sequences,
+ and the results are str instances consisting of ASCII
+ characters only. If ensure_ascii is False, a result may be a
+ unicode instance. This usually happens if the input contains
+ unicode strings or the *encoding* parameter is used.
If check_circular is true, then lists, dicts, and custom encoded
objects will be checked for circular references during encoding to
@@ -129,7 +131,10 @@
If indent is a non-negative integer, then JSON array
elements and object members will be pretty-printed with that
indent level. An indent level of 0 will only insert newlines.
- None is the most compact representation.
+ None is the most compact representation. Since the default
+ item separator is ', ', the output might include trailing
+ whitespace when indent is specified. You can use
+ separators=(',', ': ') to avoid this.
If specified, separators should be a (item_separator, key_separator)
tuple. The default is (', ', ': '). To get the most compact JSON
diff --git a/lib-python/2.7/json/tests/test_decode.py b/lib-python/2.7/json/tests/test_decode.py
--- a/lib-python/2.7/json/tests/test_decode.py
+++ b/lib-python/2.7/json/tests/test_decode.py
@@ -45,6 +45,15 @@
object_hook=lambda x: None),
OrderedDict(p))
+ def test_extra_data(self):
+ s = '[1, 2, 3]5'
+ msg = 'Extra data'
+ self.assertRaisesRegexp(ValueError, msg, self.loads, s)
+
+ def test_invalid_escape(self):
+ s = '["abc\\y"]'
+ msg = 'escape'
+ self.assertRaisesRegexp(ValueError, msg, self.loads, s)
class TestPyDecode(TestDecode, PyTest): pass
class TestCDecode(TestDecode, CTest): pass
diff --git a/lib-python/2.7/json/tests/test_dump.py b/lib-python/2.7/json/tests/test_dump.py
--- a/lib-python/2.7/json/tests/test_dump.py
+++ b/lib-python/2.7/json/tests/test_dump.py
@@ -19,5 +19,14 @@
{2: 3.0, 4.0: 5L, False: 1, 6L: True}, sort_keys=True),
'{"false": 1, "2": 3.0, "4.0": 5, "6": true}')
+ # Issue 16228: Crash on encoding resized list
+ def test_encode_mutated(self):
+ a = [object()] * 10
+ def crasher(obj):
+ del a[-1]
+ self.assertEqual(self.dumps(a, default=crasher),
+ '[null, null, null, null, null]')
+
+
class TestPyDump(TestDump, PyTest): pass
class TestCDump(TestDump, CTest): pass
diff --git a/lib-python/2.7/json/tests/test_fail.py b/lib-python/2.7/json/tests/test_fail.py
--- a/lib-python/2.7/json/tests/test_fail.py
+++ b/lib-python/2.7/json/tests/test_fail.py
@@ -1,13 +1,13 @@
from json.tests import PyTest, CTest
-# Fri Dec 30 18:57:26 2005
+# 2007-10-05
JSONDOCS = [
# http://json.org/JSON_checker/test/fail1.json
'"A JSON payload should be an object or array, not a string."',
# http://json.org/JSON_checker/test/fail2.json
'["Unclosed array"',
# http://json.org/JSON_checker/test/fail3.json
- '{unquoted_key: "keys must be quoted}',
+ '{unquoted_key: "keys must be quoted"}',
# http://json.org/JSON_checker/test/fail4.json
'["extra comma",]',
# http://json.org/JSON_checker/test/fail5.json
@@ -33,7 +33,7 @@
# http://json.org/JSON_checker/test/fail15.json
'["Illegal backslash escape: \\x15"]',
# http://json.org/JSON_checker/test/fail16.json
- '["Illegal backslash escape: \\\'"]',
+ '[\\naked]',
# http://json.org/JSON_checker/test/fail17.json
'["Illegal backslash escape: \\017"]',
# http://json.org/JSON_checker/test/fail18.json
@@ -50,6 +50,24 @@
'["Bad value", truth]',
# http://json.org/JSON_checker/test/fail24.json
"['single quote']",
+ # http://json.org/JSON_checker/test/fail25.json
+ '["\ttab\tcharacter\tin\tstring\t"]',
+ # http://json.org/JSON_checker/test/fail26.json
+ '["tab\\ character\\ in\\ string\\ "]',
+ # http://json.org/JSON_checker/test/fail27.json
+ '["line\nbreak"]',
+ # http://json.org/JSON_checker/test/fail28.json
+ '["line\\\nbreak"]',
+ # http://json.org/JSON_checker/test/fail29.json
+ '[0e]',
+ # http://json.org/JSON_checker/test/fail30.json
+ '[0e+]',
+ # http://json.org/JSON_checker/test/fail31.json
+ '[0e+-1]',
+ # http://json.org/JSON_checker/test/fail32.json
+ '{"Comma instead if closing brace": true,',
+ # http://json.org/JSON_checker/test/fail33.json
+ '["mismatch"}',
# http://code.google.com/p/simplejson/issues/detail?id=3
u'["A\u001FZ control characters in string"]',
]
diff --git a/lib-python/2.7/json/tests/test_float.py b/lib-python/2.7/json/tests/test_float.py
--- a/lib-python/2.7/json/tests/test_float.py
+++ b/lib-python/2.7/json/tests/test_float.py
@@ -17,6 +17,21 @@
self.assertEqual(self.loads(self.dumps(num)), num)
self.assertEqual(self.loads(unicode(self.dumps(num))), num)
+ def test_out_of_range(self):
+ self.assertEqual(self.loads('[23456789012E666]'), [float('inf')])
+ self.assertEqual(self.loads('[-23456789012E666]'), [float('-inf')])
+
+ def test_allow_nan(self):
+ for val in (float('inf'), float('-inf'), float('nan')):
+ out = self.dumps([val])
+ if val == val: # inf
+ self.assertEqual(self.loads(out), [val])
+ else: # nan
+ res = self.loads(out)
+ self.assertEqual(len(res), 1)
+ self.assertNotEqual(res[0], res[0])
+ self.assertRaises(ValueError, self.dumps, [val], allow_nan=False)
+
class TestPyFloat(TestFloat, PyTest): pass
class TestCFloat(TestFloat, CTest): pass
diff --git a/lib-python/2.7/json/tests/test_pass1.py b/lib-python/2.7/json/tests/test_pass1.py
--- a/lib-python/2.7/json/tests/test_pass1.py
+++ b/lib-python/2.7/json/tests/test_pass1.py
@@ -17,7 +17,7 @@
"real": -9876.543210,
"e": 0.123456789e-12,
"E": 1.234567890E+34,
- "": 23456789012E666,
+ "": 23456789012E66,
"zero": 0,
"one": 1,
"space": " ",
@@ -28,6 +28,7 @@
"alpha": "abcdefghijklmnopqrstuvwyz",
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
"digit": "0123456789",
+ "0123456789": "digit",
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
"true": true,
@@ -43,8 +44,7 @@
,
-4 , 5 , 6 ,7 ],
- "compact": [1,2,3,4,5,6,7],
+4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
"quotes": "" \u0022 %22 0x22 034 "",
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
@@ -55,9 +55,11 @@
99.44
,
-1066
-
-
+1066,
+1e1,
+0.1e1,
+1e-1,
+1e00,2e+00,2e-00
,"rosebud"]
'''
@@ -67,12 +69,6 @@
res = self.loads(JSON)
out = self.dumps(res)
self.assertEqual(res, self.loads(out))
- try:
- self.dumps(res, allow_nan=False)
- except ValueError:
- pass
- else:
- self.fail("23456789012E666 should be out of range")
class TestPyPass1(TestPass1, PyTest): pass
diff --git a/lib-python/2.7/json/tool.py b/lib-python/2.7/json/tool.py
--- a/lib-python/2.7/json/tool.py
+++ b/lib-python/2.7/json/tool.py
@@ -7,7 +7,7 @@
"json": "obj"
}
$ echo '{ 1.2:3.4}' | python -m json.tool
- Expecting property name: line 1 column 2 (char 2)
+ Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
"""
import sys
@@ -25,12 +25,15 @@
outfile = open(sys.argv[2], 'wb')
else:
raise SystemExit(sys.argv[0] + " [infile [outfile]]")
- try:
- obj = json.load(infile)
- except ValueError, e:
- raise SystemExit(e)
- json.dump(obj, outfile, sort_keys=True, indent=4)
- outfile.write('\n')
+ with infile:
+ try:
+ obj = json.load(infile)
+ except ValueError, e:
+ raise SystemExit(e)
+ with outfile:
+ json.dump(obj, outfile, sort_keys=True,
+ indent=4, separators=(',', ': '))
+ outfile.write('\n')
if __name__ == '__main__':
diff --git a/lib-python/2.7/lib-tk/Tkinter.py b/lib-python/2.7/lib-tk/Tkinter.py
--- a/lib-python/2.7/lib-tk/Tkinter.py
+++ b/lib-python/2.7/lib-tk/Tkinter.py
@@ -41,6 +41,7 @@
TclError = _tkinter.TclError
from types import *
from Tkconstants import *
+import re
wantobjects = 1
@@ -58,6 +59,37 @@
except AttributeError: _tkinter.deletefilehandler = None
+_magic_re = re.compile(r'([\\{}])')
+_space_re = re.compile(r'([\s])')
+
+def _join(value):
+ """Internal function."""
+ return ' '.join(map(_stringify, value))
+
+def _stringify(value):
+ """Internal function."""
+ if isinstance(value, (list, tuple)):
+ if len(value) == 1:
+ value = _stringify(value[0])
+ if value[0] == '{':
+ value = '{%s}' % value
+ else:
+ value = '{%s}' % _join(value)
+ else:
+ if isinstance(value, basestring):
+ value = unicode(value)
+ else:
+ value = str(value)
+ if not value:
+ value = '{}'
+ elif _magic_re.search(value):
+ # add '\' before special characters and spaces
+ value = _magic_re.sub(r'\\\1', value)
+ value = _space_re.sub(r'\\\1', value)
+ elif value[0] == '"' or _space_re.search(value):
+ value = '{%s}' % value
+ return value
+
def _flatten(tuple):
"""Internal function."""
res = ()
@@ -154,8 +186,12 @@
"""Internal function."""
pass
-def _exit(code='0'):
- """Internal function. Calling it will throw the exception SystemExit."""
+def _exit(code=0):
+ """Internal function. Calling it will raise the exception SystemExit."""
+ try:
+ code = int(code)
+ except ValueError:
+ pass
raise SystemExit, code
_varnum = 0
@@ -534,12 +570,19 @@
The type keyword specifies the form in which the data is
to be returned and should be an atom name such as STRING
- or FILE_NAME. Type defaults to STRING.
+ or FILE_NAME. Type defaults to STRING, except on X11, where the default
+ is to try UTF8_STRING and fall back to STRING.
This command is equivalent to:
selection_get(CLIPBOARD)
"""
+ if 'type' not in kw and self._windowingsystem == 'x11':
+ try:
+ kw['type'] = 'UTF8_STRING'
+ return self.tk.call(('clipboard', 'get') + self._options(kw))
+ except TclError:
+ del kw['type']
return self.tk.call(('clipboard', 'get') + self._options(kw))
def clipboard_clear(self, **kw):
@@ -621,8 +664,16 @@
A keyword parameter selection specifies the name of
the selection and defaults to PRIMARY. A keyword
parameter displayof specifies a widget on the display
- to use."""
+ to use. A keyword parameter type specifies the form of data to be
+ fetched, defaulting to STRING except on X11, where UTF8_STRING is tried
+ before STRING."""
if 'displayof' not in kw: kw['displayof'] = self._w
+ if 'type' not in kw and self._windowingsystem == 'x11':
+ try:
+ kw['type'] = 'UTF8_STRING'
+ return self.tk.call(('selection', 'get') + self._options(kw))
+ except TclError:
+ del kw['type']
return self.tk.call(('selection', 'get') + self._options(kw))
def selection_handle(self, command, **kw):
"""Specify a function COMMAND to call if the X
@@ -1037,6 +1088,15 @@
if displayof is None:
return ('-displayof', self._w)
return ()
+ @property
+ def _windowingsystem(self):
+ """Internal function."""
+ try:
+ return self._root()._windowingsystem_cached
+ except AttributeError:
+ ws = self._root()._windowingsystem_cached = \
+ self.tk.call('tk', 'windowingsystem')
+ return ws
def _options(self, cnf, kw = None):
"""Internal function."""
if kw:
@@ -1058,7 +1118,7 @@
nv.append('%d' % item)
else:
# format it to proper Tcl code if it contains space
- nv.append(('{%s}' if ' ' in item else '%s') % item)
+ nv.append(_stringify(item))
else:
v = ' '.join(nv)
res = res + ('-'+k, v)
@@ -1685,7 +1745,9 @@
self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
if useTk:
self._loadtk()
- self.readprofile(baseName, className)
+ if not sys.flags.ignore_environment:
+ # Issue #16248: Honor the -E flag to avoid code injection.
+ self.readprofile(baseName, className)
def loadtk(self):
if not self._tkloaded:
self.tk.loadtk()
diff --git a/lib-python/2.7/lib-tk/test/test_ttk/test_functions.py b/lib-python/2.7/lib-tk/test/test_ttk/test_functions.py
--- a/lib-python/2.7/lib-tk/test/test_ttk/test_functions.py
+++ b/lib-python/2.7/lib-tk/test/test_ttk/test_functions.py
@@ -50,13 +50,17 @@
ttk._format_optdict({'test': {'left': 'as is'}}),
{'-test': {'left': 'as is'}})
- # check script formatting and untouched value(s)
+ # check script formatting
check_against(
ttk._format_optdict(
- {'test': [1, -1, '', '2m', 0], 'nochange1': 3,
- 'nochange2': 'abc def'}, script=True),
- {'-test': '{1 -1 {} 2m 0}', '-nochange1': 3,
- '-nochange2': 'abc def' })
+ {'test': [1, -1, '', '2m', 0], 'test2': 3,
+ 'test3': '', 'test4': 'abc def',
+ 'test5': '"abc"', 'test6': '{}',
+ 'test7': '} -spam {'}, script=True),
+ {'-test': '{1 -1 {} 2m 0}', '-test2': '3',
+ '-test3': '{}', '-test4': '{abc def}',
+ '-test5': '{"abc"}', '-test6': r'\{\}',
+ '-test7': r'\}\ -spam\ \{'})
opts = {u'αβγ': True, u'á': False}
orig_opts = opts.copy()
@@ -70,6 +74,32 @@
ttk._format_optdict(
{'option': ('one two', 'three')}),
{'-option': '{one two} three'})
+ check_against(
+ ttk._format_optdict(
+ {'option': ('one\ttwo', 'three')}),
+ {'-option': '{one\ttwo} three'})
+
+ # passing empty strings inside a tuple/list
+ check_against(
+ ttk._format_optdict(
+ {'option': ('', 'one')}),
+ {'-option': '{} one'})
+
+ # passing values with braces inside a tuple/list
+ check_against(
+ ttk._format_optdict(
+ {'option': ('one} {two', 'three')}),
+ {'-option': r'one\}\ \{two three'})
+
+ # passing quoted strings inside a tuple/list
+ check_against(
+ ttk._format_optdict(
+ {'option': ('"one"', 'two')}),
+ {'-option': '{"one"} two'})
+ check_against(
+ ttk._format_optdict(
+ {'option': ('{one}', 'two')}),
+ {'-option': r'\{one\} two'})
# ignore an option
amount_opts = len(ttk._format_optdict(opts, ignore=(u'á'))) // 2
diff --git a/lib-python/2.7/lib-tk/test/test_ttk/test_widgets.py b/lib-python/2.7/lib-tk/test/test_ttk/test_widgets.py
--- a/lib-python/2.7/lib-tk/test/test_ttk/test_widgets.py
+++ b/lib-python/2.7/lib-tk/test/test_ttk/test_widgets.py
@@ -188,6 +188,14 @@
self.combo.configure(values=[1, '', 2])
self.assertEqual(self.combo['values'], ('1', '', '2'))
+ # testing values with spaces
+ self.combo['values'] = ['a b', 'a\tb', 'a\nb']
+ self.assertEqual(self.combo['values'], ('a b', 'a\tb', 'a\nb'))
+
+ # testing values with special characters
+ self.combo['values'] = [r'a\tb', '"a"', '} {']
+ self.assertEqual(self.combo['values'], (r'a\tb', '"a"', '} {'))
+
# out of range
self.assertRaises(Tkinter.TclError, self.combo.current,
len(self.combo['values']))
diff --git a/lib-python/2.7/lib-tk/tkSimpleDialog.py b/lib-python/2.7/lib-tk/tkSimpleDialog.py
--- a/lib-python/2.7/lib-tk/tkSimpleDialog.py
+++ b/lib-python/2.7/lib-tk/tkSimpleDialog.py
@@ -200,7 +200,7 @@
self.entry = Entry(master, name="entry")
self.entry.grid(row=1, padx=5, sticky=W+E)
- if self.initialvalue:
+ if self.initialvalue is not None:
self.entry.insert(0, self.initialvalue)
self.entry.select_range(0, END)
diff --git a/lib-python/2.7/lib-tk/ttk.py b/lib-python/2.7/lib-tk/ttk.py
--- a/lib-python/2.7/lib-tk/ttk.py
+++ b/lib-python/2.7/lib-tk/ttk.py
@@ -26,8 +26,7 @@
"tclobjs_to_py", "setup_master"]
import Tkinter
-
-_flatten = Tkinter._flatten
+from Tkinter import _flatten, _join, _stringify
# Verify if Tk is new enough to not need the Tile package
_REQUIRE_TILE = True if Tkinter.TkVersion < 8.5 else False
@@ -47,39 +46,56 @@
master.tk.eval('package require tile') # TclError may be raised here
master._tile_loaded = True
+def _format_optvalue(value, script=False):
+ """Internal function."""
+ if script:
+ # if caller passes a Tcl script to tk.call, all the values need to
+ # be grouped into words (arguments to a command in Tcl dialect)
+ value = _stringify(value)
+ elif isinstance(value, (list, tuple)):
+ value = _join(value)
+ return value
+
def _format_optdict(optdict, script=False, ignore=None):
"""Formats optdict to a tuple to pass it to tk.call.
E.g. (script=False):
{'foreground': 'blue', 'padding': [1, 2, 3, 4]} returns:
('-foreground', 'blue', '-padding', '1 2 3 4')"""
- format = "%s" if not script else "{%s}"
opts = []
for opt, value in optdict.iteritems():
- if ignore and opt in ignore:
- continue
+ if not ignore or opt not in ignore:
+ opts.append("-%s" % opt)
+ if value is not None:
+ opts.append(_format_optvalue(value, script))
- if isinstance(value, (list, tuple)):
- v = []
- for val in value:
- if isinstance(val, basestring):
- v.append(unicode(val) if val else '{}')
- else:
- v.append(str(val))
+ return _flatten(opts)
- # format v according to the script option, but also check for
- # space in any value in v in order to group them correctly
- value = format % ' '.join(
- ('{%s}' if ' ' in val else '%s') % val for val in v)
-
- if script and value == '':
- value = '{}' # empty string in Python is equivalent to {} in Tcl
-
- opts.append(("-%s" % opt, value))
-
- # Remember: _flatten skips over None
- return _flatten(opts)
+def _mapdict_values(items):
+ # each value in mapdict is expected to be a sequence, where each item
+ # is another sequence containing a state (or several) and a value
+ # E.g. (script=False):
+ # [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]
+ # returns:
+ # ['active selected', 'grey', 'focus', [1, 2, 3, 4]]
+ opt_val = []
+ for item in items:
+ state = item[:-1]
+ val = item[-1]
+ # hacks for bakward compatibility
+ state[0] # raise IndexError if empty
+ if len(state) == 1:
+ # if it is empty (something that evaluates to False), then
+ # format it to Tcl code to denote the "normal" state
+ state = state[0] or ''
+ else:
+ # group multiple states
+ state = ' '.join(state) # raise TypeError if not str
+ opt_val.append(state)
+ if val is not None:
+ opt_val.append(val)
+ return opt_val
def _format_mapdict(mapdict, script=False):
"""Formats mapdict to pass it to tk.call.
@@ -90,32 +106,11 @@
returns:
('-expand', '{active selected} grey focus {1, 2, 3, 4}')"""
- # if caller passes a Tcl script to tk.call, all the values need to
- # be grouped into words (arguments to a command in Tcl dialect)
- format = "%s" if not script else "{%s}"
opts = []
for opt, value in mapdict.iteritems():
-
- opt_val = []
- # each value in mapdict is expected to be a sequence, where each item
- # is another sequence containing a state (or several) and a value
- for statespec in value:
- state, val = statespec[:-1], statespec[-1]
-
- if len(state) > 1: # group multiple states
- state = "{%s}" % ' '.join(state)
- else: # single state
- # if it is empty (something that evaluates to False), then
- # format it to Tcl code to denote the "normal" state
- state = state[0] or '{}'
-
- if isinstance(val, (list, tuple)): # val needs to be grouped
- val = "{%s}" % ' '.join(map(str, val))
-
- opt_val.append("%s %s" % (state, val))
-
- opts.append(("-%s" % opt, format % ' '.join(opt_val)))
+ opts.extend(("-%s" % opt,
+ _format_optvalue(_mapdict_values(value), script)))
return _flatten(opts)
@@ -129,7 +124,7 @@
iname = args[0]
# next args, if any, are statespec/value pairs which is almost
# a mapdict, but we just need the value
- imagespec = _format_mapdict({None: args[1:]})[1]
+ imagespec = _join(_mapdict_values(args[1:]))
spec = "%s %s" % (iname, imagespec)
else:
@@ -138,7 +133,7 @@
# themed styles on Windows XP and Vista.
# Availability: Tk 8.6, Windows XP and Vista.
class_name, part_id = args[:2]
- statemap = _format_mapdict({None: args[2:]})[1]
+ statemap = _join(_mapdict_values(args[2:]))
spec = "%s %s %s" % (class_name, part_id, statemap)
opts = _format_optdict(kw, script)
@@ -148,11 +143,11 @@
# otherwise it will clone {} (empty element)
spec = args[0] # theme name
if len(args) > 1: # elementfrom specified
- opts = (args[1], )
+ opts = (_format_optvalue(args[1], script),)
if script:
spec = '{%s}' % spec
- opts = ' '.join(map(str, opts))
+ opts = ' '.join(opts)
return spec, opts
@@ -189,7 +184,7 @@
for layout_elem in layout:
elem, opts = layout_elem
opts = opts or {}
- fopts = ' '.join(map(str, _format_optdict(opts, True, "children")))
+ fopts = ' '.join(_format_optdict(opts, True, ("children",)))
head = "%s%s%s" % (' ' * indent, elem, (" %s" % fopts) if fopts else '')
if "children" in opts:
@@ -215,11 +210,11 @@
for name, opts in settings.iteritems():
# will format specific keys according to Tcl code
if opts.get('configure'): # format 'configure'
- s = ' '.join(map(unicode, _format_optdict(opts['configure'], True)))
+ s = ' '.join(_format_optdict(opts['configure'], True))
script.append("ttk::style configure %s %s;" % (name, s))
if opts.get('map'): # format 'map'
- s = ' '.join(map(unicode, _format_mapdict(opts['map'], True)))
+ s = ' '.join(_format_mapdict(opts['map'], True))
script.append("ttk::style map %s %s;" % (name, s))
if 'layout' in opts: # format 'layout' which may be empty
@@ -706,30 +701,9 @@
exportselection, justify, height, postcommand, state,
textvariable, values, width
"""
- # The "values" option may need special formatting, so leave to
- # _format_optdict the responsibility to format it
- if "values" in kw:
- kw["values"] = _format_optdict({'v': kw["values"]})[1]
-
Entry.__init__(self, master, "ttk::combobox", **kw)
- def __setitem__(self, item, value):
- if item == "values":
- value = _format_optdict({item: value})[1]
-
- Entry.__setitem__(self, item, value)
-
-
- def configure(self, cnf=None, **kw):
- """Custom Combobox configure, created to properly format the values
- option."""
- if "values" in kw:
- kw["values"] = _format_optdict({'v': kw["values"]})[1]
-
- return Entry.configure(self, cnf, **kw)
-
-
def current(self, newindex=None):
"""If newindex is supplied, sets the combobox value to the
element at position newindex in the list of values. Otherwise,
@@ -1253,7 +1227,7 @@
def exists(self, item):
- """Returns True if the specified item is present in the three,
+ """Returns True if the specified item is present in the tree,
False otherwise."""
return bool(self.tk.call(self._w, "exists", item))
diff --git a/lib-python/2.7/lib2to3/fixer_util.py b/lib-python/2.7/lib2to3/fixer_util.py
--- a/lib-python/2.7/lib2to3/fixer_util.py
+++ b/lib-python/2.7/lib2to3/fixer_util.py
@@ -165,7 +165,7 @@
consuming_calls = set(["sorted", "list", "set", "any", "all", "tuple", "sum",
- "min", "max"])
+ "min", "max", "enumerate"])
def attr_chain(obj, attr):
"""Follow an attribute chain.
@@ -192,14 +192,14 @@
p1 = """
power<
( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' |
- 'any' | 'all' | (any* trailer< '.' 'join' >) )
+ 'any' | 'all' | 'enumerate' | (any* trailer< '.' 'join' >) )
trailer< '(' node=any ')' >
any*
>
"""
p2 = """
power<
- 'sorted'
+ ( 'sorted' | 'enumerate' )
trailer< '(' arglist<node=any any*> ')' >
any*
>
@@ -207,14 +207,14 @@
pats_built = False
def in_special_context(node):
""" Returns true if node is in an environment where all that is required
- of it is being itterable (ie, it doesn't matter if it returns a list
- or an itterator).
+ of it is being iterable (ie, it doesn't matter if it returns a list
+ or an iterator).
See test_map_nochange in test_fixers.py for some examples and tests.
"""
global p0, p1, p2, pats_built
if not pats_built:
+ p0 = patcomp.compile_pattern(p0)
p1 = patcomp.compile_pattern(p1)
- p0 = patcomp.compile_pattern(p0)
p2 = patcomp.compile_pattern(p2)
pats_built = True
patterns = [p0, p1, p2]
@@ -274,9 +274,9 @@
"""Find the top level namespace."""
# Scamper up to the top level namespace
while node.type != syms.file_input:
- assert node.parent, "Tree is insane! root found before "\
- "file_input node was found."
node = node.parent
+ if not node:
+ raise ValueError("root found before file_input node was found.")
return node
def does_tree_import(package, name, node):
diff --git a/lib-python/2.7/lib2to3/pgen2/driver.py b/lib-python/2.7/lib2to3/pgen2/driver.py
--- a/lib-python/2.7/lib2to3/pgen2/driver.py
+++ b/lib-python/2.7/lib2to3/pgen2/driver.py
@@ -138,3 +138,20 @@
if not os.path.exists(b):
return True
return os.path.getmtime(a) >= os.path.getmtime(b)
+
+
+def main(*args):
+ """Main program, when run as a script: produce grammar pickle files.
+
+ Calls load_grammar for each argument, a path to a grammar text file.
+ """
+ if not args:
+ args = sys.argv[1:]
+ logging.basicConfig(level=logging.INFO, stream=sys.stdout,
+ format='%(message)s')
+ for gt in args:
+ load_grammar(gt, save=True, force=True)
+ return True
+
+if __name__ == "__main__":
+ sys.exit(int(not main()))
diff --git a/lib-python/2.7/lib2to3/refactor.py b/lib-python/2.7/lib2to3/refactor.py
--- a/lib-python/2.7/lib2to3/refactor.py
+++ b/lib-python/2.7/lib2to3/refactor.py
@@ -445,7 +445,7 @@
try:
find_root(node)
- except AssertionError:
+ except ValueError:
# this node has been cut off from a
# previous transformation ; skip
continue
diff --git a/lib-python/2.7/lib2to3/tests/test_fixers.py b/lib-python/2.7/lib2to3/tests/test_fixers.py
--- a/lib-python/2.7/lib2to3/tests/test_fixers.py
+++ b/lib-python/2.7/lib2to3/tests/test_fixers.py
@@ -2981,6 +2981,10 @@
self.unchanged(a)
a = """sorted(filter(f, 'abc'), key=blah)[0]"""
self.unchanged(a)
+ a = """enumerate(filter(f, 'abc'))"""
+ self.unchanged(a)
+ a = """enumerate(filter(f, 'abc'), start=1)"""
+ self.unchanged(a)
a = """for i in filter(f, 'abc'): pass"""
self.unchanged(a)
a = """[x for x in filter(f, 'abc')]"""
@@ -3089,6 +3093,10 @@
self.unchanged(a)
a = """sorted(map(f, 'abc'), key=blah)[0]"""
self.unchanged(a)
+ a = """enumerate(map(f, 'abc'))"""
+ self.unchanged(a)
+ a = """enumerate(map(f, 'abc'), start=1)"""
+ self.unchanged(a)
a = """for i in map(f, 'abc'): pass"""
self.unchanged(a)
a = """[x for x in map(f, 'abc')]"""
@@ -3152,6 +3160,10 @@
self.unchanged(a)
a = """sorted(zip(a, b), key=blah)[0]"""
self.unchanged(a)
+ a = """enumerate(zip(a, b))"""
+ self.unchanged(a)
+ a = """enumerate(zip(a, b), start=1)"""
+ self.unchanged(a)
a = """for i in zip(a, b): pass"""
self.unchanged(a)
a = """[x for x in zip(a, b)]"""
diff --git a/lib-python/2.7/locale.py b/lib-python/2.7/locale.py
--- a/lib-python/2.7/locale.py
+++ b/lib-python/2.7/locale.py
@@ -18,6 +18,14 @@
import operator
import functools
+try:
+ _unicode = unicode
+except NameError:
+ # If Python is built without Unicode support, the unicode type
+ # will not exist. Fake one.
+ class _unicode(object):
+ pass
+
# Try importing the _locale module.
#
# If this fails, fall back on a basic 'C' locale emulation.
@@ -353,7 +361,7 @@
"""
# Normalize the locale name and extract the encoding
- if isinstance(localename, unicode):
+ if isinstance(localename, _unicode):
localename = localename.encode('ascii')
fullname = localename.translate(_ascii_lower_map)
if ':' in fullname:
diff --git a/lib-python/2.7/logging/__init__.py b/lib-python/2.7/logging/__init__.py
--- a/lib-python/2.7/logging/__init__.py
+++ b/lib-python/2.7/logging/__init__.py
@@ -180,7 +180,7 @@
_releaseLock()
def _checkLevel(level):
- if isinstance(level, int):
+ if isinstance(level, (int, long)):
rv = level
elif str(level) == level:
if level not in _levelNames:
@@ -624,7 +624,8 @@
# This function can be called during module teardown, when globals are
# set to None. If _acquireLock is None, assume this is the case and do
# nothing.
- if _acquireLock is not None:
+ if (_acquireLock is not None and _handlerList is not None and
+ _releaseLock is not None):
_acquireLock()
try:
if wr in _handlerList:
@@ -1173,11 +1174,12 @@
if self.isEnabledFor(ERROR):
self._log(ERROR, msg, args, **kwargs)
- def exception(self, msg, *args):
+ def exception(self, msg, *args, **kwargs):
"""
Convenience method for logging an ERROR with exception information.
"""
- self.error(msg, exc_info=1, *args)
+ kwargs['exc_info'] = 1
+ self.error(msg, *args, **kwargs)
def critical(self, msg, *args, **kwargs):
"""
@@ -1250,7 +1252,7 @@
all the handlers of this logger to handle the record.
"""
if _srcfile:
- #IronPython doesn't track Python frames, so findCaller throws an
+ #IronPython doesn't track Python frames, so findCaller raises an
#exception on some versions of IronPython. We trap it here so that
#IronPython can use logging.
try:
@@ -1582,12 +1584,13 @@
basicConfig()
root.error(msg, *args, **kwargs)
-def exception(msg, *args):
+def exception(msg, *args, **kwargs):
"""
Log a message with severity 'ERROR' on the root logger,
with exception information.
"""
- error(msg, exc_info=1, *args)
+ kwargs['exc_info'] = 1
+ error(msg, *args, **kwargs)
def warning(msg, *args, **kwargs):
"""
diff --git a/lib-python/2.7/logging/handlers.py b/lib-python/2.7/logging/handlers.py
--- a/lib-python/2.7/logging/handlers.py
+++ b/lib-python/2.7/logging/handlers.py
@@ -23,7 +23,7 @@
To use, simply 'import logging.handlers' and log away!
"""
-import logging, socket, os, cPickle, struct, time, re
+import errno, logging, socket, os, cPickle, struct, time, re
from stat import ST_DEV, ST_INO, ST_MTIME
try:
@@ -139,7 +139,6 @@
os.remove(dfn)
os.rename(self.baseFilename, dfn)
#print "%s -> %s" % (self.baseFilename, dfn)
- self.mode = 'w'
self.stream = self._open()
def shouldRollover(self, record):
@@ -354,7 +353,6 @@
for s in self.getFilesToDelete():
os.remove(s)
#print "%s -> %s" % (self.baseFilename, dfn)
- self.mode = 'w'
self.stream = self._open()
newRolloverAt = self.computeRollover(currentTime)
while newRolloverAt <= currentTime:
@@ -392,11 +390,13 @@
"""
def __init__(self, filename, mode='a', encoding=None, delay=0):
logging.FileHandler.__init__(self, filename, mode, encoding, delay)
- if not os.path.exists(self.baseFilename):
- self.dev, self.ino = -1, -1
- else:
- stat = os.stat(self.baseFilename)
- self.dev, self.ino = stat[ST_DEV], stat[ST_INO]
+ self.dev, self.ino = -1, -1
+ self._statstream()
+
+ def _statstream(self):
+ if self.stream:
+ sres = os.fstat(self.stream.fileno())
+ self.dev, self.ino = sres[ST_DEV], sres[ST_INO]
def emit(self, record):
"""
@@ -406,19 +406,27 @@
has, close the old stream and reopen the file to get the
current stream.
"""
- if not os.path.exists(self.baseFilename):
- stat = None
- changed = 1
- else:
- stat = os.stat(self.baseFilename)
- changed = (stat[ST_DEV] != self.dev) or (stat[ST_INO] != self.ino)
- if changed and self.stream is not None:
- self.stream.flush()
- self.stream.close()
- self.stream = self._open()
- if stat is None:
- stat = os.stat(self.baseFilename)
- self.dev, self.ino = stat[ST_DEV], stat[ST_INO]
+ # Reduce the chance of race conditions by stat'ing by path only
+ # once and then fstat'ing our new fd if we opened a new log stream.
+ # See issue #14632: Thanks to John Mulligan for the problem report
+ # and patch.
+ try:
+ # stat the file by path, checking for existence
+ sres = os.stat(self.baseFilename)
+ except OSError as err:
+ if err.errno == errno.ENOENT:
+ sres = None
+ else:
+ raise
+ # compare file system stat with that of our stream file handle
+ if not sres or sres[ST_DEV] != self.dev or sres[ST_INO] != self.ino:
+ if self.stream is not None:
+ # we have an open file handle, clean it up
+ self.stream.flush()
+ self.stream.close()
+ # open a new file handle and get new stat info from that fd
+ self.stream = self._open()
+ self._statstream()
logging.FileHandler.emit(self, record)
class SocketHandler(logging.Handler):
@@ -528,9 +536,16 @@
"""
ei = record.exc_info
if ei:
- dummy = self.format(record) # just to get traceback text into record.exc_text
+ # just to get traceback text into record.exc_text ...
+ dummy = self.format(record)
record.exc_info = None # to avoid Unpickleable error
- s = cPickle.dumps(record.__dict__, 1)
+ # See issue #14436: If msg or args are objects, they may not be
+ # available on the receiving end. So we convert the msg % args
+ # to a string, save it as msg and zap the args.
+ d = dict(record.__dict__)
+ d['msg'] = record.getMessage()
+ d['args'] = None
+ s = cPickle.dumps(d, 1)
if ei:
record.exc_info = ei # for next handler
slen = struct.pack(">L", len(s))
@@ -747,14 +762,12 @@
self.formatter = None
def _connect_unixsocket(self, address):
- self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
- # syslog may require either DGRAM or STREAM sockets
+ self.socket = socket.socket(socket.AF_UNIX, self.socktype)
try:
self.socket.connect(address)
except socket.error:
self.socket.close()
- self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- self.socket.connect(address)
+ raise
# curious: when talking to the unix-domain '/dev/log' socket, a
# zero-terminator seems to be required. this string is placed
@@ -814,8 +827,6 @@
# Message is a string. Convert to bytes as required by RFC 5424
if type(msg) is unicode:
msg = msg.encode('utf-8')
- if codecs:
- msg = codecs.BOM_UTF8 + msg
msg = prio + msg
try:
if self.unixsocket:
@@ -868,6 +879,7 @@
self.toaddrs = toaddrs
self.subject = subject
self.secure = secure
+ self._timeout = 5.0
def getSubject(self, record):
"""
@@ -890,7 +902,7 @@
port = self.mailport
if not port:
port = smtplib.SMTP_PORT
- smtp = smtplib.SMTP(self.mailhost, port)
+ smtp = smtplib.SMTP(self.mailhost, port, timeout=self._timeout)
msg = self.format(record)
msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
self.fromaddr,
diff --git a/lib-python/2.7/mailbox.py b/lib-python/2.7/mailbox.py
--- a/lib-python/2.7/mailbox.py
+++ b/lib-python/2.7/mailbox.py
@@ -197,6 +197,9 @@
"""Flush and close the mailbox."""
raise NotImplementedError('Method must be implemented by subclass')
+ # Whether each message must end in a newline
+ _append_newline = False
+
def _dump_message(self, message, target, mangle_from_=False):
# Most files are opened in binary mode to allow predictable seeking.
# To get native line endings on disk, the user-friendly \n line endings
@@ -207,13 +210,21 @@
gen = email.generator.Generator(buffer, mangle_from_, 0)
gen.flatten(message)
buffer.seek(0)
- target.write(buffer.read().replace('\n', os.linesep))
+ data = buffer.read().replace('\n', os.linesep)
+ target.write(data)
+ if self._append_newline and not data.endswith(os.linesep):
+ # Make sure the message ends with a newline
+ target.write(os.linesep)
elif isinstance(message, str):
if mangle_from_:
message = message.replace('\nFrom ', '\n>From ')
message = message.replace('\n', os.linesep)
target.write(message)
+ if self._append_newline and not message.endswith(os.linesep):
+ # Make sure the message ends with a newline
+ target.write(os.linesep)
elif hasattr(message, 'read'):
+ lastline = None
while True:
line = message.readline()
if line == '':
@@ -222,6 +233,10 @@
line = '>From ' + line[5:]
line = line.replace('\n', os.linesep)
target.write(line)
+ lastline = line
+ if self._append_newline and lastline and not lastline.endswith(os.linesep):
+ # Make sure the message ends with a newline
+ target.write(os.linesep)
else:
raise TypeError('Invalid message type: %s' % type(message))
@@ -561,16 +576,19 @@
self._file = f
self._toc = None
self._next_key = 0
- self._pending = False # No changes require rewriting the file.
+ self._pending = False # No changes require rewriting the file.
+ self._pending_sync = False # No need to sync the file
self._locked = False
- self._file_length = None # Used to record mailbox size
+ self._file_length = None # Used to record mailbox size
def add(self, message):
"""Add message and return assigned key."""
self._lookup()
self._toc[self._next_key] = self._append_message(message)
self._next_key += 1
- self._pending = True
+ # _append_message appends the message to the mailbox file. We
+ # don't need a full rewrite + rename, sync is enough.
+ self._pending_sync = True
return self._next_key - 1
def remove(self, key):
@@ -616,6 +634,11 @@
def flush(self):
"""Write any pending changes to disk."""
if not self._pending:
+ if self._pending_sync:
+ # Messages have only been added, so syncing the file
+ # is enough.
+ _sync_flush(self._file)
+ self._pending_sync = False
return
# In order to be writing anything out at all, self._toc must
@@ -649,6 +672,7 @@
new_file.write(buffer)
new_toc[key] = (new_start, new_file.tell())
self._post_message_hook(new_file)
+ self._file_length = new_file.tell()
except:
new_file.close()
os.remove(new_file.name)
@@ -656,6 +680,9 @@
_sync_close(new_file)
# self._file is about to get replaced, so no need to sync.
self._file.close()
+ # Make sure the new file's mode is the same as the old file's
+ mode = os.stat(self._path).st_mode
+ os.chmod(new_file.name, mode)
try:
os.rename(new_file.name, self._path)
except OSError, e:
@@ -668,6 +695,7 @@
self._file = open(self._path, 'rb+')
self._toc = new_toc
self._pending = False
+ self._pending_sync = False
if self._locked:
_lock_file(self._file, dotlock=False)
@@ -704,6 +732,12 @@
"""Append message to mailbox and return (start, stop) offsets."""
self._file.seek(0, 2)
before = self._file.tell()
+ if len(self._toc) == 0 and not self._pending:
+ # This is the first message, and the _pre_mailbox_hook
+ # hasn't yet been called. If self._pending is True,
+ # messages have been removed, so _pre_mailbox_hook must
+ # have been called already.
+ self._pre_mailbox_hook(self._file)
try:
self._pre_message_hook(self._file)
offsets = self._install_message(message)
@@ -778,30 +812,48 @@
_mangle_from_ = True
+ # All messages must end in a newline character, and
+ # _post_message_hooks outputs an empty line between messages.
+ _append_newline = True
+
def __init__(self, path, factory=None, create=True):
"""Initialize an mbox mailbox."""
self._message_factory = mboxMessage
_mboxMMDF.__init__(self, path, factory, create)
- def _pre_message_hook(self, f):
- """Called before writing each message to file f."""
- if f.tell() != 0:
- f.write(os.linesep)
+ def _post_message_hook(self, f):
+ """Called after writing each message to file f."""
+ f.write(os.linesep)
def _generate_toc(self):
"""Generate key-to-(start, stop) table of contents."""
starts, stops = [], []
+ last_was_empty = False
self._file.seek(0)
while True:
line_pos = self._file.tell()
line = self._file.readline()
if line.startswith('From '):
if len(stops) < len(starts):
+ if last_was_empty:
+ stops.append(line_pos - len(os.linesep))
+ else:
+ # The last line before the "From " line wasn't
+ # blank, but we consider it a start of a
+ # message anyway.
+ stops.append(line_pos)
+ starts.append(line_pos)
+ last_was_empty = False
+ elif not line:
+ if last_was_empty:
stops.append(line_pos - len(os.linesep))
- starts.append(line_pos)
- elif line == '':
- stops.append(line_pos)
+ else:
+ stops.append(line_pos)
break
+ elif line == os.linesep:
+ last_was_empty = True
+ else:
+ last_was_empty = False
self._toc = dict(enumerate(zip(starts, stops)))
self._next_key = len(self._toc)
self._file_length = self._file.tell()
@@ -1367,9 +1419,9 @@
line = message.readline()
self._file.write(line.replace('\n', os.linesep))
if line == '\n' or line == '':
- self._file.write('*** EOOH ***' + os.linesep)
if first_pass:
first_pass = False
+ self._file.write('*** EOOH ***' + os.linesep)
message.seek(original_pos)
else:
break
diff --git a/lib-python/2.7/mimetypes.py b/lib-python/2.7/mimetypes.py
--- a/lib-python/2.7/mimetypes.py
+++ b/lib-python/2.7/mimetypes.py
@@ -432,11 +432,12 @@
'.hdf' : 'application/x-hdf',
'.htm' : 'text/html',
'.html' : 'text/html',
+ '.ico' : 'image/vnd.microsoft.icon',
'.ief' : 'image/ief',
'.jpe' : 'image/jpeg',
'.jpeg' : 'image/jpeg',
'.jpg' : 'image/jpeg',
- '.js' : 'application/x-javascript',
+ '.js' : 'application/javascript',
'.ksh' : 'text/plain',
'.latex' : 'application/x-latex',
'.m1v' : 'video/mpeg',
diff --git a/lib-python/2.7/multiprocessing/connection.py b/lib-python/2.7/multiprocessing/connection.py
--- a/lib-python/2.7/multiprocessing/connection.py
+++ b/lib-python/2.7/multiprocessing/connection.py
@@ -186,6 +186,8 @@
'''
if duplex:
s1, s2 = socket.socketpair()
+ s1.setblocking(True)
+ s2.setblocking(True)
c1 = _multiprocessing.Connection(os.dup(s1.fileno()))
c2 = _multiprocessing.Connection(os.dup(s2.fileno()))
s1.close()
@@ -198,7 +200,6 @@
return c1, c2
else:
-
from _multiprocessing import win32
def Pipe(duplex=True):
@@ -251,6 +252,7 @@
self._socket = socket.socket(getattr(socket, family))
try:
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self._socket.setblocking(True)
self._socket.bind(address)
self._socket.listen(backlog)
self._address = self._socket.getsockname()
@@ -269,6 +271,7 @@
def accept(self):
s, self._last_accepted = self._socket.accept()
+ s.setblocking(True)
fd = duplicate(s.fileno())
conn = _multiprocessing.Connection(fd)
s.close()
@@ -286,6 +289,7 @@
'''
family = address_type(address)
s = socket.socket( getattr(socket, family) )
+ s.setblocking(True)
t = _init_timeout()
while 1:
@@ -348,7 +352,10 @@
try:
win32.ConnectNamedPipe(handle, win32.NULL)
except WindowsError, e:
- if e.args[0] != win32.ERROR_PIPE_CONNECTED:
+ # ERROR_NO_DATA can occur if a client has already connected,
+ # written data and then disconnected -- see Issue 14725.
+ if e.args[0] not in (win32.ERROR_PIPE_CONNECTED,
+ win32.ERROR_NO_DATA):
raise
return _multiprocessing.PipeConnection(handle)
diff --git a/lib-python/2.7/multiprocessing/dummy/__init__.py b/lib-python/2.7/multiprocessing/dummy/__init__.py
--- a/lib-python/2.7/multiprocessing/dummy/__init__.py
+++ b/lib-python/2.7/multiprocessing/dummy/__init__.py
@@ -70,7 +70,8 @@
def start(self):
assert self._parent is current_process()
self._start_called = True
- self._parent._children[self] = None
+ if hasattr(self._parent, '_children'):
+ self._parent._children[self] = None
threading.Thread.start(self)
@property
diff --git a/lib-python/2.7/multiprocessing/forking.py b/lib-python/2.7/multiprocessing/forking.py
--- a/lib-python/2.7/multiprocessing/forking.py
+++ b/lib-python/2.7/multiprocessing/forking.py
@@ -35,6 +35,7 @@
import os
import sys
import signal
+import errno
from multiprocessing import util, process
@@ -129,12 +130,17 @@
def poll(self, flag=os.WNOHANG):
if self.returncode is None:
- try:
- pid, sts = os.waitpid(self.pid, flag)
- except os.error:
- # Child process not yet created. See #1731717
- # e.errno == errno.ECHILD == 10
- return None
+ while True:
+ try:
+ pid, sts = os.waitpid(self.pid, flag)
+ except os.error as e:
+ if e.errno == errno.EINTR:
+ continue
+ # Child process not yet created. See #1731717
+ # e.errno == errno.ECHILD == 10
+ return None
+ else:
+ break
if pid == self.pid:
if os.WIFSIGNALED(sts):
self.returncode = -os.WTERMSIG(sts)
@@ -336,7 +342,7 @@
'''
Returns prefix of command line used for spawning a child process
'''
- if process.current_process()._identity==() and is_forking(sys.argv):
+ if getattr(process.current_process(), '_inheriting', False):
raise RuntimeError('''
Attempt to start a new process before the current process
has finished its bootstrapping phase.
diff --git a/lib-python/2.7/multiprocessing/pool.py b/lib-python/2.7/multiprocessing/pool.py
--- a/lib-python/2.7/multiprocessing/pool.py
+++ b/lib-python/2.7/multiprocessing/pool.py
@@ -68,6 +68,23 @@
# Code run by worker processes
#
+class MaybeEncodingError(Exception):
+ """Wraps possible unpickleable errors, so they can be
+ safely sent through the socket."""
+
+ def __init__(self, exc, value):
+ self.exc = repr(exc)
+ self.value = repr(value)
+ super(MaybeEncodingError, self).__init__(self.exc, self.value)
+
+ def __str__(self):
+ return "Error sending result: '%s'. Reason: '%s'" % (self.value,
+ self.exc)
+
+ def __repr__(self):
+ return "<MaybeEncodingError: %s>" % str(self)
+
+
def worker(inqueue, outqueue, initializer=None, initargs=(), maxtasks=None):
assert maxtasks is None or (type(maxtasks) == int and maxtasks > 0)
put = outqueue.put
@@ -96,7 +113,13 @@
result = (True, func(*args, **kwds))
except Exception, e:
result = (False, e)
- put((job, i, result))
+ try:
+ put((job, i, result))
+ except Exception as e:
+ wrapped = MaybeEncodingError(e, result[1])
+ debug("Possible encoding error while sending result: %s" % (
+ wrapped))
+ put((job, i, (False, wrapped)))
completed += 1
debug('worker exiting after %d tasks' % completed)
@@ -466,7 +489,8 @@
# We must wait for the worker handler to exit before terminating
# workers because we don't want workers to be restarted behind our back.
debug('joining worker handler')
- worker_handler.join()
+ if threading.current_thread() is not worker_handler:
+ worker_handler.join(1e100)
# Terminate workers which haven't already finished.
if pool and hasattr(pool[0], 'terminate'):
@@ -476,10 +500,12 @@
p.terminate()
debug('joining task handler')
- task_handler.join(1e100)
+ if threading.current_thread() is not task_handler:
+ task_handler.join(1e100)
debug('joining result handler')
- result_handler.join(1e100)
+ if threading.current_thread() is not result_handler:
+ result_handler.join(1e100)
if pool and hasattr(pool[0], 'terminate'):
debug('joining pool workers')
@@ -553,6 +579,7 @@
if chunksize <= 0:
self._number_left = 0
self._ready = True
+ del cache[self._job]
else:
self._number_left = length//chunksize + bool(length % chunksize)
diff --git a/lib-python/2.7/multiprocessing/process.py b/lib-python/2.7/multiprocessing/process.py
--- a/lib-python/2.7/multiprocessing/process.py
+++ b/lib-python/2.7/multiprocessing/process.py
@@ -262,12 +262,12 @@
except SystemExit, e:
if not e.args:
exitcode = 1
- elif type(e.args[0]) is int:
+ elif isinstance(e.args[0], int):
exitcode = e.args[0]
else:
- sys.stderr.write(e.args[0] + '\n')
+ sys.stderr.write(str(e.args[0]) + '\n')
sys.stderr.flush()
- exitcode = 1
+ exitcode = 0 if isinstance(e.args[0], str) else 1
except:
exitcode = 1
import traceback
diff --git a/lib-python/2.7/multiprocessing/util.py b/lib-python/2.7/multiprocessing/util.py
--- a/lib-python/2.7/multiprocessing/util.py
+++ b/lib-python/2.7/multiprocessing/util.py
@@ -247,6 +247,12 @@
Finalizers with highest priority are called first; finalizers with
the same priority will be called in reverse order of creation.
'''
+ if _finalizer_registry is None:
+ # This function may be called after this module's globals are
+ # destroyed. See the _exit_function function in this module for more
+ # notes.
+ return
+
if minpriority is None:
f = lambda p : p[0][0] is not None
else:
@@ -278,21 +284,38 @@
_exiting = False
-def _exit_function():
+def _exit_function(info=info, debug=debug, _run_finalizers=_run_finalizers,
+ active_children=active_children,
+ current_process=current_process):
+ # NB: we hold on to references to functions in the arglist due to the
+ # situation described below, where this function is called after this
+ # module's globals are destroyed.
+
global _exiting
info('process shutting down')
debug('running all "atexit" finalizers with priority >= 0')
_run_finalizers(0)
- for p in active_children():
- if p._daemonic:
- info('calling terminate() for daemon %s', p.name)
- p._popen.terminate()
+ if current_process() is not None:
+ # NB: we check if the current process is None here because if
+ # it's None, any call to ``active_children()`` will throw an
+ # AttributeError (active_children winds up trying to get
+ # attributes from util._current_process). This happens in a
+ # variety of shutdown circumstances that are not well-understood
+ # because module-scope variables are not apparently supposed to
+ # be destroyed until after this function is called. However,
+ # they are indeed destroyed before this function is called. See
+ # issues 9775 and 15881. Also related: 4106, 9205, and 9207.
- for p in active_children():
- info('calling join() for process %s', p.name)
- p.join()
+ for p in active_children():
+ if p._daemonic:
+ info('calling terminate() for daemon %s', p.name)
+ p._popen.terminate()
+
+ for p in active_children():
+ info('calling join() for process %s', p.name)
+ p.join()
debug('running the remaining "atexit" finalizers')
_run_finalizers()
diff --git a/lib-python/2.7/plat-generic/regen b/lib-python/2.7/plat-generic/regen
--- a/lib-python/2.7/plat-generic/regen
+++ b/lib-python/2.7/plat-generic/regen
@@ -1,3 +1,3 @@
#! /bin/sh
set -v
-python$EXE ../../Tools/scripts/h2py.py -i '(u_long)' /usr/include/netinet/in.h
+eval $PYTHON_FOR_BUILD ../../Tools/scripts/h2py.py -i "'(u_long)'" /usr/include/netinet/in.h
diff --git a/lib-python/2.7/platform.py b/lib-python/2.7/platform.py
--- a/lib-python/2.7/platform.py
+++ b/lib-python/2.7/platform.py
@@ -673,8 +673,13 @@
release = '7'
else:
release = '2008ServerR2'
+ elif min == 2:
+ if product_type == VER_NT_WORKSTATION:
+ release = '8'
+ else:
+ release = '2012Server'
else:
- release = 'post2008Server'
+ release = 'post2012Server'
else:
if not release:
@@ -1020,16 +1025,38 @@
case the command should fail.
"""
+
+ # We do the import here to avoid a bootstrap issue.
+ # See c73b90b6dadd changeset.
+ #
+ # [..]
+ # ranlib libpython2.7.a
+ # gcc -o python \
+ # Modules/python.o \
+ # libpython2.7.a -lsocket -lnsl -ldl -lm
+ # Traceback (most recent call last):
+ # File "./setup.py", line 8, in <module>
+ # from platform import machine as platform_machine
+ # File "[..]/build/Lib/platform.py", line 116, in <module>
+ # import sys,string,os,re,subprocess
+ # File "[..]/build/Lib/subprocess.py", line 429, in <module>
+ # import select
+ # ImportError: No module named select
+
+ import subprocess
+
if sys.platform in ('dos','win32','win16','os2'):
# XXX Others too ?
return default
- target = _follow_symlinks(target).replace('"', '\\"')
+ target = _follow_symlinks(target)
try:
- f = os.popen('file "%s" 2> %s' % (target, DEV_NULL))
+ proc = subprocess.Popen(['file', target],
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+
except (AttributeError,os.error):
return default
- output = string.strip(f.read())
- rc = f.close()
+ output = proc.communicate()[0]
+ rc = proc.wait()
if not output or rc:
return default
else:
diff --git a/lib-python/2.7/posixpath.py b/lib-python/2.7/posixpath.py
--- a/lib-python/2.7/posixpath.py
+++ b/lib-python/2.7/posixpath.py
@@ -17,6 +17,14 @@
import warnings
from genericpath import *
+try:
+ _unicode = unicode
+except NameError:
+ # If Python is built without Unicode support, the unicode type
+ # will not exist. Fake one.
+ class _unicode(object):
+ pass
+
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
"basename","dirname","commonprefix","getsize","getmtime",
"getatime","getctime","islink","exists","lexists","isdir","isfile",
@@ -60,7 +68,8 @@
def join(a, *p):
"""Join two or more pathname components, inserting '/' as needed.
If any component is an absolute path, all previous path components
- will be discarded."""
+ will be discarded. An empty last part will result in a path that
+ ends with a separator."""
path = a
for b in p:
if b.startswith('/'):
@@ -267,8 +276,8 @@
except KeyError:
return path
userhome = pwent.pw_dir
- userhome = userhome.rstrip('/') or userhome
- return userhome + path[i:]
+ userhome = userhome.rstrip('/')
+ return (userhome + path[i:]) or '/'
# Expand paths containing shell variable substitutions.
@@ -312,7 +321,7 @@
def normpath(path):
"""Normalize path, eliminating double slashes, etc."""
# Preserve unicode (if path is unicode)
- slash, dot = (u'/', u'.') if isinstance(path, unicode) else ('/', '.')
+ slash, dot = (u'/', u'.') if isinstance(path, _unicode) else ('/', '.')
if path == '':
return dot
initial_slashes = path.startswith('/')
@@ -341,7 +350,7 @@
def abspath(path):
"""Return an absolute path."""
if not isabs(path):
- if isinstance(path, unicode):
+ if isinstance(path, _unicode):
cwd = os.getcwdu()
else:
cwd = os.getcwd()
@@ -355,46 +364,53 @@
def realpath(filename):
"""Return the canonical path of the specified filename, eliminating any
symbolic links encountered in the path."""
- if isabs(filename):
- bits = ['/'] + filename.split('/')[1:]
- else:
- bits = [''] + filename.split('/')
+ path, ok = _joinrealpath('', filename, {})
+ return abspath(path)
- for i in range(2, len(bits)+1):
- component = join(*bits[0:i])
- # Resolve symbolic links.
- if islink(component):
- resolved = _resolve_link(component)
- if resolved is None:
- # Infinite loop -- return original component + rest of the path
- return abspath(join(*([component] + bits[i:])))
+# Join two paths, normalizing ang eliminating any symbolic links
+# encountered in the second path.
+def _joinrealpath(path, rest, seen):
+ if isabs(rest):
+ rest = rest[1:]
+ path = sep
+
+ while rest:
+ name, _, rest = rest.partition(sep)
+ if not name or name == curdir:
+ # current dir
+ continue
+ if name == pardir:
+ # parent dir
+ if path:
+ path, name = split(path)
+ if name == pardir:
+ path = join(path, pardir, pardir)
else:
- newpath = join(*([resolved] + bits[i:]))
- return realpath(newpath)
+ path = pardir
+ continue
+ newpath = join(path, name)
+ if not islink(newpath):
+ path = newpath
+ continue
+ # Resolve the symbolic link
+ if newpath in seen:
+ # Already seen this path
+ path = seen[newpath]
+ if path is not None:
+ # use cached value
+ continue
+ # The symlink is not resolved, so we must have a symlink loop.
+ # Return already resolved part + rest of the path unchanged.
+ return join(newpath, rest), False
+ seen[newpath] = None # not resolved symlink
+ path, ok = _joinrealpath(path, os.readlink(newpath), seen)
+ if not ok:
+ return join(path, rest), False
+ seen[newpath] = path # resolved symlink
- return abspath(filename)
+ return path, True
-def _resolve_link(path):
- """Internal helper function. Takes a path and follows symlinks
- until we either arrive at something that isn't a symlink, or
- encounter a path we've seen before (meaning that there's a loop).
- """
- paths_seen = set()
- while islink(path):
- if path in paths_seen:
- # Already seen this path, so we must have a symlink loop
- return None
- paths_seen.add(path)
- # Resolve where the link points to
- resolved = os.readlink(path)
- if not isabs(resolved):
- dir = dirname(path)
- path = normpath(join(dir, resolved))
- else:
- path = normpath(resolved)
- return path
-
supports_unicode_filenames = (sys.platform == 'darwin')
def relpath(path, start=curdir):
diff --git a/lib-python/2.7/pstats.py b/lib-python/2.7/pstats.py
--- a/lib-python/2.7/pstats.py
+++ b/lib-python/2.7/pstats.py
@@ -120,8 +120,8 @@
self.stats = arg.stats
arg.stats = {}
if not self.stats:
- raise TypeError, "Cannot create or construct a %r object from '%r''" % (
- self.__class__, arg)
+ raise TypeError("Cannot create or construct a %r object from %r"
+ % (self.__class__, arg))
return
def get_top_level_stats(self):
@@ -172,15 +172,19 @@
# along with some printable description
sort_arg_dict_default = {
"calls" : (((1,-1), ), "call count"),
+ "ncalls" : (((1,-1), ), "call count"),
+ "cumtime" : (((3,-1), ), "cumulative time"),
"cumulative": (((3,-1), ), "cumulative time"),
"file" : (((4, 1), ), "file name"),
+ "filename" : (((4, 1), ), "file name"),
"line" : (((5, 1), ), "line number"),
"module" : (((4, 1), ), "file name"),
"name" : (((6, 1), ), "function name"),
"nfl" : (((6, 1),(4, 1),(5, 1),), "name/file/line"),
- "pcalls" : (((0,-1), ), "call count"),
+ "pcalls" : (((0,-1), ), "primitive call count"),
"stdname" : (((7, 1), ), "standard name"),
"time" : (((2,-1), ), "internal time"),
+ "tottime" : (((2,-1), ), "internal time"),
}
def get_sort_arg_defs(self):
diff --git a/lib-python/2.7/py_compile.py b/lib-python/2.7/py_compile.py
--- a/lib-python/2.7/py_compile.py
+++ b/lib-python/2.7/py_compile.py
@@ -112,7 +112,7 @@
try:
codeobject = __builtin__.compile(codestring, dfile or file,'exec')
except Exception,err:
- py_exc = PyCompileError(err.__class__,err.args,dfile or file)
+ py_exc = PyCompileError(err.__class__, err, dfile or file)
if doraise:
raise py_exc
else:
diff --git a/lib-python/2.7/pyclbr.py b/lib-python/2.7/pyclbr.py
--- a/lib-python/2.7/pyclbr.py
+++ b/lib-python/2.7/pyclbr.py
@@ -128,6 +128,8 @@
parent = _readmodule(package, path, inpackage)
if inpackage is not None:
package = "%s.%s" % (inpackage, package)
+ if not '__path__' in parent:
+ raise ImportError('No package named {}'.format(package))
return _readmodule(submodule, parent['__path__'], package)
# Search the path for the module
diff --git a/lib-python/2.7/pydoc.py b/lib-python/2.7/pydoc.py
--- a/lib-python/2.7/pydoc.py
+++ b/lib-python/2.7/pydoc.py
@@ -1498,7 +1498,8 @@
raise ImportError, 'no Python documentation found for %r' % thing
return object, thing
else:
- return thing, getattr(thing, '__name__', None)
+ name = getattr(thing, '__name__', None)
+ return thing, name if isinstance(name, str) else None
def render_doc(thing, title='Python Library Documentation: %s', forceload=0):
"""Render text documentation, given an object or a path to an object."""
@@ -1799,7 +1800,7 @@
Welcome to Python %s! This is the online help utility.
If this is your first time using Python, you should definitely check out
-the tutorial on the Internet at http://docs.python.org/tutorial/.
+the tutorial on the Internet at http://docs.python.org/%s/tutorial/.
Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules. To quit this help utility and
@@ -1809,7 +1810,7 @@
"keywords", or "topics". Each module also comes with a one-line summary
of what it does; to list the modules whose summaries contain a given word
such as "spam", type "modules spam".
-''' % sys.version[:3])
+''' % tuple([sys.version[:3]]*2))
def list(self, items, columns=4, width=80):
items = items[:]
diff --git a/lib-python/2.7/random.py b/lib-python/2.7/random.py
--- a/lib-python/2.7/random.py
+++ b/lib-python/2.7/random.py
@@ -457,27 +457,25 @@
if kappa <= 1e-6:
return TWOPI * random()
- a = 1.0 + _sqrt(1.0 + 4.0 * kappa * kappa)
- b = (a - _sqrt(2.0 * a))/(2.0 * kappa)
- r = (1.0 + b * b)/(2.0 * b)
+ s = 0.5 / kappa
+ r = s + _sqrt(1.0 + s * s)
while 1:
u1 = random()
+ z = _cos(_pi * u1)
- z = _cos(_pi * u1)
- f = (1.0 + r * z)/(r + z)
- c = kappa * (r - f)
-
+ d = z / (r + z)
u2 = random()
-
- if u2 < c * (2.0 - c) or u2 <= c * _exp(1.0 - c):
+ if u2 < 1.0 - d * d or u2 <= (1.0 - d) * _exp(d):
break
+ q = 1.0 / r
+ f = (q + z) / (1.0 + q * z)
u3 = random()
if u3 > 0.5:
- theta = (mu % TWOPI) + _acos(f)
+ theta = (mu + _acos(f)) % TWOPI
else:
- theta = (mu % TWOPI) - _acos(f)
+ theta = (mu - _acos(f)) % TWOPI
return theta
diff --git a/lib-python/2.7/rfc822.py b/lib-python/2.7/rfc822.py
--- a/lib-python/2.7/rfc822.py
+++ b/lib-python/2.7/rfc822.py
@@ -212,7 +212,7 @@
You may override this method if your application wants to bend the
rules, e.g. to strip trailing whitespace, or to recognize MH template
separators ('--------'). For convenience (e.g. for code reading from
- sockets) a line consisting of \r\n also matches.
+ sockets) a line consisting of \\r\\n also matches.
"""
return line in _blanklines
diff --git a/lib-python/2.7/rlcompleter.py b/lib-python/2.7/rlcompleter.py
--- a/lib-python/2.7/rlcompleter.py
+++ b/lib-python/2.7/rlcompleter.py
@@ -1,13 +1,11 @@
-"""Word completion for GNU readline 2.0.
+"""Word completion for GNU readline.
-This requires the latest extension to the readline module. The completer
-completes keywords, built-ins and globals in a selectable namespace (which
-defaults to __main__); when completing NAME.NAME..., it evaluates (!) the
-expression up to the last dot and completes its attributes.
+The completer completes keywords, built-ins and globals in a selectable
+namespace (which defaults to __main__); when completing NAME.NAME..., it
+evaluates (!) the expression up to the last dot and completes its attributes.
-It's very cool to do "import sys" type "sys.", hit the
-completion key (twice), and see the list of names defined by the
-sys module!
+It's very cool to do "import sys" type "sys.", hit the completion key (twice),
+and see the list of names defined by the sys module!
Tip: to use the tab key as the completion key, call
@@ -15,18 +13,16 @@
Notes:
-- Exceptions raised by the completer function are *ignored* (and
-generally cause the completion to fail). This is a feature -- since
-readline sets the tty device in raw (or cbreak) mode, printing a
-traceback wouldn't work well without some complicated hoopla to save,
-reset and restore the tty state.
+- Exceptions raised by the completer function are *ignored* (and generally cause
+ the completion to fail). This is a feature -- since readline sets the tty
+ device in raw (or cbreak) mode, printing a traceback wouldn't work well
+ without some complicated hoopla to save, reset and restore the tty state.
-- The evaluation of the NAME.NAME... form may cause arbitrary
-application defined code to be executed if an object with a
-__getattr__ hook is found. Since it is the responsibility of the
-application (or the user) to enable this feature, I consider this an
-acceptable risk. More complicated expressions (e.g. function calls or
-indexing operations) are *not* evaluated.
+- The evaluation of the NAME.NAME... form may cause arbitrary application
+ defined code to be executed if an object with a __getattr__ hook is found.
+ Since it is the responsibility of the application (or the user) to enable this
+ feature, I consider this an acceptable risk. More complicated expressions
+ (e.g. function calls or indexing operations) are *not* evaluated.
- GNU readline is also used by the built-in functions input() and
raw_input(), and thus these also benefit/suffer from the completer
@@ -35,7 +31,7 @@
its input.
- When the original stdin is not a tty device, GNU readline is never
-used, and this module (and the readline module) are silently inactive.
+ used, and this module (and the readline module) are silently inactive.
"""
diff --git a/lib-python/2.7/runpy.py b/lib-python/2.7/runpy.py
--- a/lib-python/2.7/runpy.py
+++ b/lib-python/2.7/runpy.py
@@ -200,7 +200,7 @@
pass
else:
# The following check looks a bit odd. The trick is that
- # NullImporter throws ImportError if the supplied path is a
+ # NullImporter raises ImportError if the supplied path is a
# *valid* directory entry (and hence able to be handled
# by the standard import machinery)
try:
diff --git a/lib-python/2.7/shutil.py b/lib-python/2.7/shutil.py
--- a/lib-python/2.7/shutil.py
+++ b/lib-python/2.7/shutil.py
@@ -102,8 +102,10 @@
try:
os.chflags(dst, st.st_flags)
except OSError, why:
- if (not hasattr(errno, 'EOPNOTSUPP') or
- why.errno != errno.EOPNOTSUPP):
+ for err in 'EOPNOTSUPP', 'ENOTSUP':
+ if hasattr(errno, err) and why.errno == getattr(errno, err):
+ break
+ else:
raise
def copy(src, dst):
@@ -201,7 +203,7 @@
# Copying file access times may fail on Windows
pass
else:
- errors.extend((src, dst, str(why)))
+ errors.append((src, dst, str(why)))
if errors:
raise Error, errors
diff --git a/lib-python/2.7/smtplib.py b/lib-python/2.7/smtplib.py
--- a/lib-python/2.7/smtplib.py
+++ b/lib-python/2.7/smtplib.py
@@ -818,13 +818,13 @@
try:
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.connect(host)
- except socket.error, msg:
+ except socket.error:
if self.debuglevel > 0:
print>>stderr, 'connect fail:', host
if self.sock:
self.sock.close()
self.sock = None
- raise socket.error, msg
+ raise
(code, msg) = self.getreply()
if self.debuglevel > 0:
print>>stderr, "connect:", msg
diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py
--- a/lib-python/2.7/socket.py
+++ b/lib-python/2.7/socket.py
@@ -319,8 +319,8 @@
self._wbuf.append(data)
self._wbuf_len += len(data)
if (self._wbufsize == 0 or
- self._wbufsize == 1 and '\n' in data or
- self._wbuf_len >= self._wbufsize):
+ (self._wbufsize == 1 and '\n' in data) or
+ (self._wbufsize > 1 and self._wbuf_len >= self._wbufsize)):
self.flush()
def writelines(self, list):
diff --git a/lib-python/2.7/sqlite3/dbapi2.py b/lib-python/2.7/sqlite3/dbapi2.py
--- a/lib-python/2.7/sqlite3/dbapi2.py
+++ b/lib-python/2.7/sqlite3/dbapi2.py
@@ -1,4 +1,4 @@
-#-*- coding: ISO-8859-1 -*-
+# -*- coding: iso-8859-1 -*-
# pysqlite2/dbapi2.py: the DB-API 2.0 interface
#
# Copyright (C) 2004-2005 Gerhard Häring <gh at ghaering.de>
@@ -68,7 +68,7 @@
timepart_full = timepart.split(".")
hours, minutes, seconds = map(int, timepart_full[0].split(":"))
if len(timepart_full) == 2:
- microseconds = int(timepart_full[1])
+ microseconds = int('{:0<6.6}'.format(timepart_full[1].decode()))
else:
microseconds = 0
diff --git a/lib-python/2.7/sqlite3/dump.py b/lib-python/2.7/sqlite3/dump.py
--- a/lib-python/2.7/sqlite3/dump.py
+++ b/lib-python/2.7/sqlite3/dump.py
@@ -25,9 +25,10 @@
FROM "sqlite_master"
WHERE "sql" NOT NULL AND
"type" == 'table'
+ ORDER BY "name"
"""
schema_res = cu.execute(q)
- for table_name, type, sql in sorted(schema_res.fetchall()):
+ for table_name, type, sql in schema_res.fetchall():
if table_name == 'sqlite_sequence':
yield('DELETE FROM "sqlite_sequence";')
elif table_name == 'sqlite_stat1':
@@ -42,7 +43,7 @@
# qtable,
# sql.replace("''")))
else:
- yield('{0};'.format(sql))
+ yield('%s;' % sql)
# Build the insert statement for each row of the current table
table_name_ident = table_name.replace('"', '""')
@@ -53,7 +54,7 @@
",".join("""'||quote("{0}")||'""".format(col.replace('"', '""')) for col in column_names))
query_res = cu.execute(q)
for row in query_res:
- yield("{0};".format(row[0]))
+ yield("%s;" % row[0])
# Now when the type is 'index', 'trigger', or 'view'
q = """
@@ -64,6 +65,6 @@
"""
schema_res = cu.execute(q)
for name, type, sql in schema_res.fetchall():
- yield('{0};'.format(sql))
+ yield('%s;' % sql)
yield('COMMIT;')
diff --git a/lib-python/2.7/sqlite3/test/dump.py b/lib-python/2.7/sqlite3/test/dump.py
--- a/lib-python/2.7/sqlite3/test/dump.py
+++ b/lib-python/2.7/sqlite3/test/dump.py
@@ -29,6 +29,8 @@
,
"INSERT INTO \"t1\" VALUES(2,'foo2',30,30);"
,
+ u"INSERT INTO \"t1\" VALUES(3,'f\xc3\xb6',40,10);"
+ ,
"CREATE TABLE t2(id integer, t2_i1 integer, " \
"t2_i2 integer, primary key (id)," \
"foreign key(t2_i1) references t1(t1_i1));"
@@ -49,6 +51,27 @@
[self.assertEqual(expected_sqls[i], actual_sqls[i])
for i in xrange(len(expected_sqls))]
+ def CheckUnorderableRow(self):
+ # iterdump() should be able to cope with unorderable row types (issue #15545)
+ class UnorderableRow:
+ def __init__(self, cursor, row):
+ self.row = row
+ def __getitem__(self, index):
+ return self.row[index]
+ self.cx.row_factory = UnorderableRow
+ CREATE_ALPHA = """CREATE TABLE "alpha" ("one");"""
+ CREATE_BETA = """CREATE TABLE "beta" ("two");"""
+ expected = [
+ "BEGIN TRANSACTION;",
+ CREATE_ALPHA,
+ CREATE_BETA,
+ "COMMIT;"
+ ]
+ self.cu.execute(CREATE_BETA)
+ self.cu.execute(CREATE_ALPHA)
+ got = list(self.cx.iterdump())
+ self.assertEqual(expected, got)
+
def suite():
return unittest.TestSuite(unittest.makeSuite(DumpTests, "Check"))
diff --git a/lib-python/2.7/sqlite3/test/hooks.py b/lib-python/2.7/sqlite3/test/hooks.py
--- a/lib-python/2.7/sqlite3/test/hooks.py
+++ b/lib-python/2.7/sqlite3/test/hooks.py
@@ -76,6 +76,25 @@
except sqlite.OperationalError, e:
self.assertEqual(e.args[0].lower(), "no such collation sequence: mycoll")
+ def CheckCollationReturnsLargeInteger(self):
+ def mycoll(x, y):
+ # reverse order
+ return -((x > y) - (x < y)) * 2**32
+ con = sqlite.connect(":memory:")
+ con.create_collation("mycoll", mycoll)
+ sql = """
+ select x from (
+ select 'a' as x
+ union
+ select 'b' as x
+ union
+ select 'c' as x
+ ) order by x collate mycoll
+ """
+ result = con.execute(sql).fetchall()
+ self.assertEqual(result, [('c',), ('b',), ('a',)],
+ msg="the expected order was not returned")
+
def CheckCollationRegisterTwice(self):
"""
Register two different collation functions under the same name.
diff --git a/lib-python/2.7/sqlite3/test/regression.py b/lib-python/2.7/sqlite3/test/regression.py
--- a/lib-python/2.7/sqlite3/test/regression.py
+++ b/lib-python/2.7/sqlite3/test/regression.py
@@ -1,4 +1,4 @@
-#-*- coding: ISO-8859-1 -*-
+#-*- coding: iso-8859-1 -*-
# pysqlite2/test/regression.py: pysqlite regression tests
#
# Copyright (C) 2006-2007 Gerhard Häring <gh at ghaering.de>
@@ -285,6 +285,32 @@
cur.executemany("insert into b (baz) values (?)",
((i,) for i in foo()))
+ def CheckConvertTimestampMicrosecondPadding(self):
+ """
+ http://bugs.python.org/issue14720
+
+ The microsecond parsing of convert_timestamp() should pad with zeros,
+ since the microsecond string "456" actually represents "456000".
+ """
+
+ con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
+ cur = con.cursor()
+ cur.execute("CREATE TABLE t (x TIMESTAMP)")
+
+ # Microseconds should be 456000
+ cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.456')")
+
+ # Microseconds should be truncated to 123456
+ cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.123456789')")
+
+ cur.execute("SELECT * FROM t")
+ values = [x[0] for x in cur.fetchall()]
+
+ self.assertEqual(values, [
+ datetime.datetime(2012, 4, 4, 15, 6, 0, 456000),
+ datetime.datetime(2012, 4, 4, 15, 6, 0, 123456),
+ ])
+
def suite():
regression_suite = unittest.makeSuite(RegressionTests, "Check")
diff --git a/lib-python/2.7/sqlite3/test/userfunctions.py b/lib-python/2.7/sqlite3/test/userfunctions.py
--- a/lib-python/2.7/sqlite3/test/userfunctions.py
+++ b/lib-python/2.7/sqlite3/test/userfunctions.py
@@ -374,14 +374,15 @@
val = cur.fetchone()[0]
self.assertEqual(val, 60)
-def authorizer_cb(action, arg1, arg2, dbname, source):
- if action != sqlite.SQLITE_SELECT:
- return sqlite.SQLITE_DENY
- if arg2 == 'c2' or arg1 == 't2':
- return sqlite.SQLITE_DENY
- return sqlite.SQLITE_OK
+class AuthorizerTests(unittest.TestCase):
+ @staticmethod
+ def authorizer_cb(action, arg1, arg2, dbname, source):
+ if action != sqlite.SQLITE_SELECT:
+ return sqlite.SQLITE_DENY
+ if arg2 == 'c2' or arg1 == 't2':
+ return sqlite.SQLITE_DENY
+ return sqlite.SQLITE_OK
-class AuthorizerTests(unittest.TestCase):
def setUp(self):
self.con = sqlite.connect(":memory:")
self.con.executescript("""
@@ -394,12 +395,12 @@
# For our security test:
self.con.execute("select c2 from t2")
- self.con.set_authorizer(authorizer_cb)
+ self.con.set_authorizer(self.authorizer_cb)
def tearDown(self):
pass
- def CheckTableAccess(self):
+ def test_table_access(self):
try:
self.con.execute("select * from t2")
except sqlite.DatabaseError, e:
@@ -408,7 +409,7 @@
return
self.fail("should have raised an exception due to missing privileges")
- def CheckColumnAccess(self):
+ def test_column_access(self):
try:
self.con.execute("select c2 from t1")
except sqlite.DatabaseError, e:
@@ -417,11 +418,46 @@
return
self.fail("should have raised an exception due to missing privileges")
+class AuthorizerRaiseExceptionTests(AuthorizerTests):
+ @staticmethod
+ def authorizer_cb(action, arg1, arg2, dbname, source):
+ if action != sqlite.SQLITE_SELECT:
+ raise ValueError
+ if arg2 == 'c2' or arg1 == 't2':
+ raise ValueError
+ return sqlite.SQLITE_OK
+
+class AuthorizerIllegalTypeTests(AuthorizerTests):
+ @staticmethod
+ def authorizer_cb(action, arg1, arg2, dbname, source):
+ if action != sqlite.SQLITE_SELECT:
+ return 0.0
+ if arg2 == 'c2' or arg1 == 't2':
+ return 0.0
+ return sqlite.SQLITE_OK
+
+class AuthorizerLargeIntegerTests(AuthorizerTests):
+ @staticmethod
+ def authorizer_cb(action, arg1, arg2, dbname, source):
+ if action != sqlite.SQLITE_SELECT:
+ return 2**32
+ if arg2 == 'c2' or arg1 == 't2':
+ return 2**32
+ return sqlite.SQLITE_OK
+
+
def suite():
function_suite = unittest.makeSuite(FunctionTests, "Check")
aggregate_suite = unittest.makeSuite(AggregateTests, "Check")
- authorizer_suite = unittest.makeSuite(AuthorizerTests, "Check")
- return unittest.TestSuite((function_suite, aggregate_suite, authorizer_suite))
+ authorizer_suite = unittest.makeSuite(AuthorizerTests)
+ return unittest.TestSuite((
+ function_suite,
+ aggregate_suite,
+ authorizer_suite,
+ unittest.makeSuite(AuthorizerRaiseExceptionTests),
+ unittest.makeSuite(AuthorizerIllegalTypeTests),
+ unittest.makeSuite(AuthorizerLargeIntegerTests),
+ ))
def test():
runner = unittest.TextTestRunner()
diff --git a/lib-python/2.7/sre_compile.py b/lib-python/2.7/sre_compile.py
--- a/lib-python/2.7/sre_compile.py
+++ b/lib-python/2.7/sre_compile.py
@@ -13,6 +13,7 @@
import _sre, sys
import sre_parse
from sre_constants import *
+from _sre import MAXREPEAT
assert _sre.MAGIC == MAGIC, "SRE module mismatch"
diff --git a/lib-python/2.7/sre_constants.py b/lib-python/2.7/sre_constants.py
--- a/lib-python/2.7/sre_constants.py
+++ b/lib-python/2.7/sre_constants.py
@@ -15,9 +15,7 @@
MAGIC = 20031017
-# max code word in this release
-
-MAXREPEAT = 65535
+from _sre import MAXREPEAT
# SRE standard exception (access as sre.error)
# should this really be here?
diff --git a/lib-python/2.7/sre_parse.py b/lib-python/2.7/sre_parse.py
--- a/lib-python/2.7/sre_parse.py
+++ b/lib-python/2.7/sre_parse.py
@@ -15,6 +15,7 @@
import sys
from sre_constants import *
+from _sre import MAXREPEAT
SPECIAL_CHARS = ".\\[{()*+?^$|"
REPEAT_CHARS = "*+?{"
@@ -228,7 +229,7 @@
if code:
return code
code = CATEGORIES.get(escape)
- if code:
+ if code and code[0] == IN:
return code
try:
c = escape[1:2]
@@ -498,10 +499,14 @@
continue
if lo:
min = int(lo)
+ if min >= MAXREPEAT:
+ raise OverflowError("the repetition number is too large")
if hi:
max = int(hi)
- if max < min:
- raise error, "bad repeat interval"
+ if max >= MAXREPEAT:
+ raise OverflowError("the repetition number is too large")
+ if max < min:
+ raise error("bad repeat interval")
else:
raise error, "not supported"
# figure out which item to repeat
@@ -541,6 +546,8 @@
break
name = name + char
group = 1
+ if not name:
+ raise error("missing group name")
if not isname(name):
raise error, "bad character in group name"
elif sourcematch("="):
@@ -553,6 +560,8 @@
if char == ")":
break
name = name + char
+ if not name:
+ raise error("missing group name")
if not isname(name):
raise error, "bad character in group name"
gid = state.groupdict.get(name)
@@ -605,6 +614,8 @@
break
condname = condname + char
group = 2
+ if not condname:
+ raise error("missing group name")
if isname(condname):
condgroup = state.groupdict.get(condname)
if condgroup is None:
@@ -723,7 +734,7 @@
break
name = name + char
if not name:
- raise error, "bad group name"
+ raise error, "missing group name"
try:
index = int(name)
if index < 0:
diff --git a/lib-python/2.7/ssl.py b/lib-python/2.7/ssl.py
--- a/lib-python/2.7/ssl.py
+++ b/lib-python/2.7/ssl.py
@@ -313,17 +313,19 @@
self.cert_reqs, self.ssl_version,
self.ca_certs, self.ciphers)
try:
- socket.connect(self, addr)
- if self.do_handshake_on_connect:
- self.do_handshake()
- except socket_error as e:
if return_errno:
- return e.errno
+ rc = socket.connect_ex(self, addr)
else:
- self._sslobj = None
- raise e
- self._connected = True
- return 0
+ rc = None
+ socket.connect(self, addr)
+ if not rc:
+ if self.do_handshake_on_connect:
+ self.do_handshake()
+ self._connected = True
+ return rc
+ except socket_error:
+ self._sslobj = None
+ raise
def connect(self, addr):
"""Connects to remote ADDR, and then wraps the connection in
diff --git a/lib-python/2.7/string.py b/lib-python/2.7/string.py
--- a/lib-python/2.7/string.py
+++ b/lib-python/2.7/string.py
@@ -601,12 +601,12 @@
def convert_field(self, value, conversion):
# do any conversion on the resulting object
- if conversion == 'r':
- return repr(value)
+ if conversion is None:
+ return value
elif conversion == 's':
return str(value)
- elif conversion is None:
- return value
+ elif conversion == 'r':
+ return repr(value)
raise ValueError("Unknown conversion specifier {0!s}".format(conversion))
diff --git a/lib-python/2.7/subprocess.py b/lib-python/2.7/subprocess.py
--- a/lib-python/2.7/subprocess.py
+++ b/lib-python/2.7/subprocess.py
@@ -671,12 +671,33 @@
c2pread, c2pwrite,
errread, errwrite) = self._get_handles(stdin, stdout, stderr)
- self._execute_child(args, executable, preexec_fn, close_fds,
- cwd, env, universal_newlines,
- startupinfo, creationflags, shell,
- p2cread, p2cwrite,
- c2pread, c2pwrite,
- errread, errwrite)
+ try:
+ self._execute_child(args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+ except Exception:
+ # Preserve original exception in case os.close raises.
+ exc_type, exc_value, exc_trace = sys.exc_info()
+
+ to_close = []
+ # Only close the pipes we created.
+ if stdin == PIPE:
+ to_close.extend((p2cread, p2cwrite))
+ if stdout == PIPE:
+ to_close.extend((c2pread, c2pwrite))
+ if stderr == PIPE:
+ to_close.extend((errread, errwrite))
+
+ for fd in to_close:
+ try:
+ os.close(fd)
+ except EnvironmentError:
+ pass
+
+ raise exc_type, exc_value, exc_trace
if mswindows:
if p2cwrite is not None:
@@ -1253,9 +1274,6 @@
if e.errno != errno.ECHILD:
raise
child_exception = pickle.loads(data)
- for fd in (p2cwrite, c2pread, errread):
- if fd is not None:
- os.close(fd)
raise child_exception
@@ -1274,7 +1292,7 @@
def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid,
- _WNOHANG=os.WNOHANG, _os_error=os.error):
+ _WNOHANG=os.WNOHANG, _os_error=os.error, _ECHILD=errno.ECHILD):
"""Check if child process has terminated. Returns returncode
attribute.
@@ -1287,16 +1305,23 @@
pid, sts = _waitpid(self.pid, _WNOHANG)
if pid == self.pid:
self._handle_exitstatus(sts)
- except _os_error:
+ except _os_error as e:
if _deadstate is not None:
self.returncode = _deadstate
+ if e.errno == _ECHILD:
+ # This happens if SIGCLD is set to be ignored or
+ # waiting for child processes has otherwise been
+ # disabled for our process. This child is dead, we
+ # can't get the status.
+ # http://bugs.python.org/issue15756
+ self.returncode = 0
return self.returncode
def wait(self):
"""Wait for child process to terminate. Returns returncode
attribute."""
- if self.returncode is None:
+ while self.returncode is None:
try:
pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0)
except OSError as e:
@@ -1305,8 +1330,12 @@
# This happens if SIGCLD is set to be ignored or waiting
# for child processes has otherwise been disabled for our
# process. This child is dead, we can't get the status.
+ pid = self.pid
sts = 0
- self._handle_exitstatus(sts)
+ # Check the pid and loop as waitpid has been known to return
+ # 0 even without WNOHANG in odd situations. issue14396.
+ if pid == self.pid:
+ self._handle_exitstatus(sts)
return self.returncode
diff --git a/lib-python/2.7/sysconfig.py b/lib-python/2.7/sysconfig.py
--- a/lib-python/2.7/sysconfig.py
+++ b/lib-python/2.7/sysconfig.py
@@ -116,6 +116,10 @@
if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower():
_PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
+# set for cross builds
+if "_PYTHON_PROJECT_BASE" in os.environ:
+ # the build directory for posix builds
+ _PROJECT_BASE = os.path.normpath(os.path.abspath("."))
def is_python_build():
for fn in ("Setup.dist", "Setup.local"):
if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)):
@@ -445,64 +449,11 @@
srcdir = os.path.join(base, _CONFIG_VARS['srcdir'])
_CONFIG_VARS['srcdir'] = os.path.normpath(srcdir)
+ # OS X platforms require special customization to handle
+ # multi-architecture, multi-os-version installers
if sys.platform == 'darwin':
- kernel_version = os.uname()[2] # Kernel version (8.4.3)
- major_version = int(kernel_version.split('.')[0])
-
- if major_version < 8:
- # On Mac OS X before 10.4, check if -arch and -isysroot
- # are in CFLAGS or LDFLAGS and remove them if they are.
- # This is needed when building extensions on a 10.3 system
- # using a universal build of python.
- for key in ('LDFLAGS', 'BASECFLAGS',
- # a number of derived variables. These need to be
- # patched up as well.
- 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
- flags = _CONFIG_VARS[key]
- flags = re.sub('-arch\s+\w+\s', ' ', flags)
- flags = re.sub('-isysroot [^ \t]*', ' ', flags)
- _CONFIG_VARS[key] = flags
- else:
- # Allow the user to override the architecture flags using
- # an environment variable.
- # NOTE: This name was introduced by Apple in OSX 10.5 and
- # is used by several scripting languages distributed with
- # that OS release.
- if 'ARCHFLAGS' in os.environ:
- arch = os.environ['ARCHFLAGS']
- for key in ('LDFLAGS', 'BASECFLAGS',
- # a number of derived variables. These need to be
- # patched up as well.
- 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
-
- flags = _CONFIG_VARS[key]
- flags = re.sub('-arch\s+\w+\s', ' ', flags)
- flags = flags + ' ' + arch
- _CONFIG_VARS[key] = flags
-
- # If we're on OSX 10.5 or later and the user tries to
- # compiles an extension using an SDK that is not present
- # on the current machine it is better to not use an SDK
- # than to fail.
- #
- # The major usecase for this is users using a Python.org
- # binary installer on OSX 10.6: that installer uses
- # the 10.4u SDK, but that SDK is not installed by default
- # when you install Xcode.
- #
- CFLAGS = _CONFIG_VARS.get('CFLAGS', '')
- m = re.search('-isysroot\s+(\S+)', CFLAGS)
- if m is not None:
- sdk = m.group(1)
- if not os.path.exists(sdk):
- for key in ('LDFLAGS', 'BASECFLAGS',
- # a number of derived variables. These need to be
- # patched up as well.
- 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
-
- flags = _CONFIG_VARS[key]
- flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
- _CONFIG_VARS[key] = flags
+ import _osx_support
+ _osx_support.customize_config_vars(_CONFIG_VARS)
if args:
vals = []
@@ -560,6 +511,10 @@
return 'win-ia64'
return sys.platform
+ # Set for cross builds explicitly
+ if "_PYTHON_HOST_PLATFORM" in os.environ:
+ return os.environ["_PYTHON_HOST_PLATFORM"]
+
if os.name != "posix" or not hasattr(os, 'uname'):
# XXX what about the architecture? NT is Intel or Alpha,
# Mac OS is M68k or PPC, etc.
@@ -600,91 +555,10 @@
if m:
release = m.group()
elif osname[:6] == "darwin":
- #
- # For our purposes, we'll assume that the system version from
- # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
- # to. This makes the compatibility story a bit more sane because the
- # machine is going to compile and link as if it were
- # MACOSX_DEPLOYMENT_TARGET.
- cfgvars = get_config_vars()
- macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
-
- if 1:
- # Always calculate the release of the running machine,
- # needed to determine if we can build fat binaries or not.
-
- macrelease = macver
- # Get the system version. Reading this plist is a documented
- # way to get the system version (see the documentation for
- # the Gestalt Manager)
- try:
- f = open('/System/Library/CoreServices/SystemVersion.plist')
- except IOError:
- # We're on a plain darwin box, fall back to the default
- # behaviour.
- pass
- else:
- try:
- m = re.search(
- r'<key>ProductUserVisibleVersion</key>\s*' +
- r'<string>(.*?)</string>', f.read())
- if m is not None:
- macrelease = '.'.join(m.group(1).split('.')[:2])
- # else: fall back to the default behaviour
- finally:
- f.close()
-
- if not macver:
- macver = macrelease
-
- if macver:
- release = macver
- osname = "macosx"
-
- if (macrelease + '.') >= '10.4.' and \
- '-arch' in get_config_vars().get('CFLAGS', '').strip():
- # The universal build will build fat binaries, but not on
- # systems before 10.4
- #
- # Try to detect 4-way universal builds, those have machine-type
- # 'universal' instead of 'fat'.
-
- machine = 'fat'
- cflags = get_config_vars().get('CFLAGS')
-
- archs = re.findall('-arch\s+(\S+)', cflags)
- archs = tuple(sorted(set(archs)))
-
- if len(archs) == 1:
- machine = archs[0]
- elif archs == ('i386', 'ppc'):
- machine = 'fat'
- elif archs == ('i386', 'x86_64'):
- machine = 'intel'
- elif archs == ('i386', 'ppc', 'x86_64'):
- machine = 'fat3'
- elif archs == ('ppc64', 'x86_64'):
- machine = 'fat64'
- elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
- machine = 'universal'
- else:
- raise ValueError(
- "Don't know machine value for archs=%r"%(archs,))
-
- elif machine == 'i386':
- # On OSX the machine type returned by uname is always the
- # 32-bit variant, even if the executable architecture is
- # the 64-bit variant
- if sys.maxint >= 2**32:
- machine = 'x86_64'
-
- elif machine in ('PowerPC', 'Power_Macintosh'):
- # Pick a sane name for the PPC architecture.
- # See 'i386' case
- if sys.maxint >= 2**32:
- machine = 'ppc64'
- else:
- machine = 'ppc'
+ import _osx_support
+ osname, release, machine = _osx_support.get_platform_osx(
+ get_config_vars(),
+ osname, release, machine)
return "%s-%s-%s" % (osname, release, machine)
diff --git a/lib-python/2.7/tarfile.py b/lib-python/2.7/tarfile.py
--- a/lib-python/2.7/tarfile.py
+++ b/lib-python/2.7/tarfile.py
@@ -1987,9 +1987,8 @@
# Append the tar header and data to the archive.
if tarinfo.isreg():
- f = bltn_open(name, "rb")
- self.addfile(tarinfo, f)
- f.close()
+ with bltn_open(name, "rb") as f:
+ self.addfile(tarinfo, f)
elif tarinfo.isdir():
self.addfile(tarinfo)
@@ -2197,10 +2196,11 @@
"""Make a file called targetpath.
"""
source = self.extractfile(tarinfo)
- target = bltn_open(targetpath, "wb")
- copyfileobj(source, target)
- source.close()
- target.close()
+ try:
+ with bltn_open(targetpath, "wb") as target:
+ copyfileobj(source, target)
+ finally:
+ source.close()
def makeunknown(self, tarinfo, targetpath):
"""Make a file from a TarInfo object with an unknown type
@@ -2397,7 +2397,7 @@
"""
if tarinfo.issym():
# Always search the entire archive.
- linkname = os.path.dirname(tarinfo.name) + "/" + tarinfo.linkname
+ linkname = "/".join(filter(None, (os.path.dirname(tarinfo.name), tarinfo.linkname)))
limit = None
else:
# Search the archive before the link, because a hard link is
diff --git a/lib-python/2.7/telnetlib.py b/lib-python/2.7/telnetlib.py
--- a/lib-python/2.7/telnetlib.py
+++ b/lib-python/2.7/telnetlib.py
@@ -34,6 +34,7 @@
# Imported modules
+import errno
import sys
import socket
import select
@@ -205,6 +206,7 @@
self.sb = 0 # flag for SB and SE sequence.
self.sbdataq = ''
self.option_callback = None
+ self._has_poll = hasattr(select, 'poll')
if host is not None:
self.open(host, port, timeout)
@@ -287,6 +289,61 @@
is closed and no cooked data is available.
"""
+ if self._has_poll:
+ return self._read_until_with_poll(match, timeout)
+ else:
+ return self._read_until_with_select(match, timeout)
+
+ def _read_until_with_poll(self, match, timeout):
+ """Read until a given string is encountered or until timeout.
+
+ This method uses select.poll() to implement the timeout.
+ """
+ n = len(match)
+ call_timeout = timeout
+ if timeout is not None:
+ from time import time
+ time_start = time()
+ self.process_rawq()
+ i = self.cookedq.find(match)
+ if i < 0:
+ poller = select.poll()
+ poll_in_or_priority_flags = select.POLLIN | select.POLLPRI
+ poller.register(self, poll_in_or_priority_flags)
+ while i < 0 and not self.eof:
+ try:
+ ready = poller.poll(call_timeout)
+ except select.error as e:
+ if e.errno == errno.EINTR:
+ if timeout is not None:
+ elapsed = time() - time_start
+ call_timeout = timeout-elapsed
+ continue
+ raise
+ for fd, mode in ready:
+ if mode & poll_in_or_priority_flags:
+ i = max(0, len(self.cookedq)-n)
+ self.fill_rawq()
+ self.process_rawq()
+ i = self.cookedq.find(match, i)
+ if timeout is not None:
+ elapsed = time() - time_start
+ if elapsed >= timeout:
+ break
+ call_timeout = timeout-elapsed
+ poller.unregister(self)
+ if i >= 0:
+ i = i + n
+ buf = self.cookedq[:i]
+ self.cookedq = self.cookedq[i:]
+ return buf
+ return self.read_very_lazy()
+
+ def _read_until_with_select(self, match, timeout=None):
+ """Read until a given string is encountered or until timeout.
+
+ The timeout is implemented using select.select().
+ """
n = len(match)
self.process_rawq()
i = self.cookedq.find(match)
@@ -589,6 +646,79 @@
results are undeterministic, and may depend on the I/O timing.
"""
+ if self._has_poll:
+ return self._expect_with_poll(list, timeout)
+ else:
+ return self._expect_with_select(list, timeout)
+
+ def _expect_with_poll(self, expect_list, timeout=None):
+ """Read until one from a list of a regular expressions matches.
+
+ This method uses select.poll() to implement the timeout.
+ """
+ re = None
+ expect_list = expect_list[:]
+ indices = range(len(expect_list))
+ for i in indices:
+ if not hasattr(expect_list[i], "search"):
+ if not re: import re
+ expect_list[i] = re.compile(expect_list[i])
+ call_timeout = timeout
+ if timeout is not None:
+ from time import time
+ time_start = time()
+ self.process_rawq()
+ m = None
+ for i in indices:
+ m = expect_list[i].search(self.cookedq)
+ if m:
+ e = m.end()
+ text = self.cookedq[:e]
+ self.cookedq = self.cookedq[e:]
+ break
+ if not m:
+ poller = select.poll()
+ poll_in_or_priority_flags = select.POLLIN | select.POLLPRI
+ poller.register(self, poll_in_or_priority_flags)
+ while not m and not self.eof:
+ try:
+ ready = poller.poll(call_timeout)
+ except select.error as e:
+ if e.errno == errno.EINTR:
+ if timeout is not None:
+ elapsed = time() - time_start
+ call_timeout = timeout-elapsed
+ continue
+ raise
+ for fd, mode in ready:
+ if mode & poll_in_or_priority_flags:
+ self.fill_rawq()
+ self.process_rawq()
+ for i in indices:
+ m = expect_list[i].search(self.cookedq)
+ if m:
+ e = m.end()
+ text = self.cookedq[:e]
+ self.cookedq = self.cookedq[e:]
+ break
+ if timeout is not None:
+ elapsed = time() - time_start
+ if elapsed >= timeout:
+ break
+ call_timeout = timeout-elapsed
+ poller.unregister(self)
+ if m:
+ return (i, m, text)
+ text = self.read_very_lazy()
+ if not text and self.eof:
+ raise EOFError
+ return (-1, None, text)
+
+ def _expect_with_select(self, list, timeout=None):
+ """Read until one from a list of a regular expressions matches.
+
+ The timeout is implemented using select.select().
+ """
re = None
list = list[:]
indices = range(len(list))
diff --git a/lib-python/2.7/tempfile.py b/lib-python/2.7/tempfile.py
--- a/lib-python/2.7/tempfile.py
+++ b/lib-python/2.7/tempfile.py
@@ -29,6 +29,7 @@
# Imports.
+import io as _io
import os as _os
import errno as _errno
from random import Random as _Random
@@ -193,15 +194,18 @@
name = namer.next()
filename = _os.path.join(dir, name)
try:
- fd = _os.open(filename, flags, 0600)
- fp = _os.fdopen(fd, 'w')
- fp.write('blat')
- fp.close()
- _os.unlink(filename)
- del fp, fd
+ fd = _os.open(filename, flags, 0o600)
+ try:
+ try:
+ with _io.open(fd, 'wb', closefd=False) as fp:
+ fp.write(b'blat')
+ finally:
+ _os.close(fd)
+ finally:
+ _os.unlink(filename)
return dir
- except (OSError, IOError), e:
- if e[0] != _errno.EEXIST:
+ except (OSError, IOError) as e:
+ if e.args[0] != _errno.EEXIST:
break # no point trying more names in this directory
pass
raise IOError, (_errno.ENOENT,
@@ -546,10 +550,6 @@
def closed(self):
return self._file.closed
- @property
- def encoding(self):
- return self._file.encoding
-
def fileno(self):
self.rollover()
return self._file.fileno()
@@ -562,15 +562,17 @@
@property
def mode(self):
- return self._file.mode
+ try:
+ return self._file.mode
+ except AttributeError:
+ return self._TemporaryFileArgs[0]
@property
def name(self):
- return self._file.name
-
- @property
- def newlines(self):
- return self._file.newlines
+ try:
+ return self._file.name
+ except AttributeError:
+ return None
def next(self):
return self._file.next
@@ -610,4 +612,7 @@
return rv
def xreadlines(self, *args):
- return self._file.xreadlines(*args)
+ try:
+ return self._file.xreadlines(*args)
+ except AttributeError:
+ return iter(self._file.readlines(*args))
diff --git a/lib-python/2.7/test/keycert.pem b/lib-python/2.7/test/keycert.pem
--- a/lib-python/2.7/test/keycert.pem
+++ b/lib-python/2.7/test/keycert.pem
@@ -1,32 +1,31 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L
-opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH
-fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB
-AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU
-D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA
-IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM
-oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0
-ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/
-loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j
-oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA
-z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq
-ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV
-q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU=
------END RSA PRIVATE KEY-----
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
+LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
+ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
+USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
+CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
+SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
+UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
+BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
+ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
+oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
+eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
+0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
+x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
+SPIXQuT8RMPDVNQ=
+-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
-MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD
-VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x
-IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT
-U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1
-NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl
-bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m
-dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj
-aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh
-m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8
-M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn
-fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC
-AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb
-08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx
-CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/
-iHkC6gGdBJhogs4=
+MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
+MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
+Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
+YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
+6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
+pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
+FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
+BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
+lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
+CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
-----END CERTIFICATE-----
diff --git a/lib-python/2.7/test/pickletester.py b/lib-python/2.7/test/pickletester.py
--- a/lib-python/2.7/test/pickletester.py
+++ b/lib-python/2.7/test/pickletester.py
@@ -6,7 +6,8 @@
import pickletools
import copy_reg
-from test.test_support import TestFailed, have_unicode, TESTFN
+from test.test_support import (TestFailed, have_unicode, TESTFN, _2G, _1M,
+ precisionbigmemtest)
# Tests that try a number of pickle protocols should have a
# for proto in protocols:
@@ -502,10 +503,10 @@
i = C()
i.attr = i
for proto in protocols:
- s = self.dumps(i, 2)
+ s = self.dumps(i, proto)
x = self.loads(s)
self.assertEqual(dir(x), dir(i))
- self.assertTrue(x.attr is x)
+ self.assertIs(x.attr, x)
def test_recursive_multi(self):
l = []
@@ -1280,3 +1281,31 @@
f.write(pickled2)
f.seek(0)
self.assertEqual(unpickler.load(), data2)
+
+class BigmemPickleTests(unittest.TestCase):
+
+ # Memory requirements: 1 byte per character for input strings, 1 byte
+ # for pickled data, 1 byte for unpickled strings, 1 byte for internal
+ # buffer and 1 byte of free space for resizing of internal buffer.
+
+ @precisionbigmemtest(size=_2G + 100*_1M, memuse=5)
+ def test_huge_strlist(self, size):
+ chunksize = 2**20
+ data = []
+ while size > chunksize:
+ data.append('x' * chunksize)
+ size -= chunksize
+ chunksize += 1
+ data.append('y' * size)
+
+ try:
+ for proto in protocols:
+ try:
+ pickled = self.dumps(data, proto)
+ res = self.loads(pickled)
+ self.assertEqual(res, data)
+ finally:
+ res = None
+ pickled = None
+ finally:
+ data = None
diff --git a/lib-python/2.7/test/regrtest.py b/lib-python/2.7/test/regrtest.py
--- a/lib-python/2.7/test/regrtest.py
+++ b/lib-python/2.7/test/regrtest.py
@@ -32,7 +32,7 @@
Selecting tests
--r/--random -- randomize test execution order (see below)
+-r/--randomize -- randomize test execution order (see below)
--randseed -- pass a random seed to reproduce a previous random run
-f/--fromfile -- read names of tests to run from a file (see below)
-x/--exclude -- arguments are tests to *exclude*
@@ -158,6 +158,7 @@
import os
import random
import re
+import shutil
import sys
import time
import traceback
@@ -258,7 +259,7 @@
try:
opts, args = getopt.getopt(sys.argv[1:], 'hvqxsSrf:lu:t:TD:NLR:FwWM:j:',
['help', 'verbose', 'verbose2', 'verbose3', 'quiet',
- 'exclude', 'single', 'slow', 'random', 'fromfile', 'findleaks',
+ 'exclude', 'single', 'slow', 'randomize', 'fromfile=', 'findleaks',
'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir',
'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=',
'multiprocess=', 'slaveargs=', 'forever', 'header'])
@@ -540,6 +541,8 @@
print stdout
if stderr:
print >>sys.stderr, stderr
+ sys.stdout.flush()
+ sys.stderr.flush()
if result[0] == INTERRUPTED:
assert result[1] == 'KeyboardInterrupt'
raise KeyboardInterrupt # What else?
@@ -941,7 +944,6 @@
return FAILED, test_time
def cleanup_test_droppings(testname, verbose):
- import shutil
import stat
import gc
diff --git a/lib-python/2.7/test/script_helper.py b/lib-python/2.7/test/script_helper.py
--- a/lib-python/2.7/test/script_helper.py
+++ b/lib-python/2.7/test/script_helper.py
@@ -10,7 +10,13 @@
import py_compile
import contextlib
import shutil
-import zipfile
+try:
+ import zipfile
+except ImportError:
+ # If Python is build without Unicode support, importing _io will
+ # fail, which, in turn, means that zipfile cannot be imported
+ # Most of this module can then still be used.
+ pass
from test.test_support import strip_python_stderr
diff --git a/lib-python/2.7/test/sha256.pem b/lib-python/2.7/test/sha256.pem
--- a/lib-python/2.7/test/sha256.pem
+++ b/lib-python/2.7/test/sha256.pem
@@ -1,129 +1,128 @@
# Certificate chain for https://sha256.tbs-internet.com
- 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=sha-256 production/CN=sha256.tbs-internet.com
- i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC
+ 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=Certificats TBS X509/CN=ecom.tbs-x509.com
+ i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA business
-----BEGIN CERTIFICATE-----
-MIIGXTCCBUWgAwIBAgIRAMmag+ygSAdxZsbyzYjhuW0wDQYJKoZIhvcNAQELBQAw
-gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl
+MIIGTjCCBTagAwIBAgIQOh3d9dNDPq1cSdJmEiMpqDANBgkqhkiG9w0BAQUFADCB
+yTELMAkGA1UEBhMCRlIxETAPBgNVBAgTCENhbHZhZG9zMQ0wCwYDVQQHEwRDYWVu
+MRUwEwYDVQQKEwxUQlMgSU5URVJORVQxSDBGBgNVBAsTP1Rlcm1zIGFuZCBDb25k
+aXRpb25zOiBodHRwOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0EvcmVwb3NpdG9y
+eTEYMBYGA1UECxMPVEJTIElOVEVSTkVUIENBMR0wGwYDVQQDExRUQlMgWDUwOSBD
+QSBidXNpbmVzczAeFw0xMTAxMjUwMDAwMDBaFw0xMzAyMDUyMzU5NTlaMIHHMQsw
+CQYDVQQGEwJGUjEOMAwGA1UEERMFMTQwMDAxETAPBgNVBAgTCENhbHZhZG9zMQ0w
+CwYDVQQHEwRDQUVOMRswGQYDVQQJExIyMiBydWUgZGUgQnJldGFnbmUxFTATBgNV
+BAoTDFRCUyBJTlRFUk5FVDEXMBUGA1UECxMOMDAwMiA0NDA0NDM4MTAxHTAbBgNV
+BAsTFENlcnRpZmljYXRzIFRCUyBYNTA5MRowGAYDVQQDExFlY29tLnRicy14NTA5
+LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKRrlHUnJ++1lpcg
+jtYco7cdmRe+EEfTmwPfCdfV3G1QfsTSvY6FfMpm/83pqHfT+4ANwr18wD9ZrAEN
+G16mf9VdCGK12+TP7DmqeZyGIqlFFoahQnmb8EarvE43/1UeQ2CV9XmzwZvpqeli
+LfXsFonawrY3H6ZnMwS64St61Z+9gdyuZ/RbsoZBbT5KUjDEG844QRU4OT1IGeEI
+eY5NM5RNIh6ZNhVtqeeCxMS7afONkHQrOco73RdSTRck/Hj96Ofl3MHNHryr+AMK
+DGFk1kLCZGpPdXtkxXvaDeQoiYDlil26CWc+YK6xyDPMdsWvoG14ZLyCpzMXA7/7
+4YAQRH0CAwEAAaOCAjAwggIsMB8GA1UdIwQYMBaAFBoJBMz5CY+7HqDO1KQUf0vV
+I1jNMB0GA1UdDgQWBBQgOU8HsWzbmD4WZP5Wtdw7jca2WDAOBgNVHQ8BAf8EBAMC
+BaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
+TAYDVR0gBEUwQzBBBgsrBgEEAYDlNwIBATAyMDAGCCsGAQUFBwIBFiRodHRwczov
+L3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL0NQUzEwdwYDVR0fBHAwbjA3oDWgM4Yx
+aHR0cDovL2NybC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQWJ1c2luZXNzLmNy
+bDAzoDGgL4YtaHR0cDovL2NybC50YnMteDUwOS5jb20vVEJTWDUwOUNBYnVzaW5l
+c3MuY3JsMIGwBggrBgEFBQcBAQSBozCBoDA9BggrBgEFBQcwAoYxaHR0cDovL2Ny
+dC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQWJ1c2luZXNzLmNydDA5BggrBgEF
+BQcwAoYtaHR0cDovL2NydC50YnMteDUwOS5jb20vVEJTWDUwOUNBYnVzaW5lc3Mu
+Y3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wMwYDVR0R
+BCwwKoIRZWNvbS50YnMteDUwOS5jb22CFXd3dy5lY29tLnRicy14NTA5LmNvbTAN
+BgkqhkiG9w0BAQUFAAOCAQEArT4NHfbY87bGAw8lPV4DmHlmuDuVp/y7ltO3Ynse
+3Rz8RxW2AzuO0Oy2F0Cu4yWKtMyEyMXyHqWtae7ElRbdTu5w5GwVBLJHClCzC8S9
+SpgMMQTx3Rgn8vjkHuU9VZQlulZyiPK7yunjc7c310S9FRZ7XxOwf8Nnx4WnB+No
+WrfApzhhQl31w+RyrNxZe58hCfDDHmevRvwLjQ785ZoQXJDj2j3qAD4aI2yB8lB5
+oaE1jlCJzC7Kmz/Y9jzfmv/zAs1LQTm9ktevv4BTUFaGjv9jxnQ1xnS862ZiouLW
+zZYIlYPf4F6JjXGiIQgQRglILUfq3ftJd9/ok9W9ZF8h8w==
+-----END CERTIFICATE-----
+ 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA business
+ i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
+-----BEGIN CERTIFICATE-----
+MIIFPzCCBCegAwIBAgIQDlBz/++iRSmLDeVRHT/hADANBgkqhkiG9w0BAQUFADBv
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
+ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
+eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDcwOTE4MTkyMlow
+gckxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl
bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u
ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv
-cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg
-Q0EgU0dDMB4XDTEwMDIxODAwMDAwMFoXDTEyMDIxOTIzNTk1OVowgcsxCzAJBgNV
-BAYTAkZSMQ4wDAYDVQQREwUxNDAwMDERMA8GA1UECBMIQ2FsdmFkb3MxDTALBgNV
-BAcTBENBRU4xGzAZBgNVBAkTEjIyIHJ1ZSBkZSBCcmV0YWduZTEVMBMGA1UEChMM
-VEJTIElOVEVSTkVUMRcwFQYDVQQLEw4wMDAyIDQ0MDQ0MzgxMDEbMBkGA1UECxMS
-c2hhLTI1NiBwcm9kdWN0aW9uMSAwHgYDVQQDExdzaGEyNTYudGJzLWludGVybmV0
-LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbuM8VT7f0nntwu
-N3F7v9KIBlhKNAxqCrziOXU5iqUt8HrQB3DtHbdmII+CpVUlwlmepsx6G+srEZ9a
-MIGAy0nxi5aLb7watkyIdPjJTMvTUBQ/+RPWzt5JtYbbY9BlJ+yci0dctP74f4NU
-ISLtlrEjUbf2gTohLrcE01TfmOF6PDEbB5PKDi38cB3NzKfizWfrOaJW6Q1C1qOJ
-y4/4jkUREX1UFUIxzx7v62VfjXSGlcjGpBX1fvtABQOSLeE0a6gciDZs1REqroFf
-5eXtqYphpTa14Z83ITXMfgg5Nze1VtMnzI9Qx4blYBw4dgQVEuIsYr7FDBOITDzc
-VEVXZx0CAwEAAaOCAj8wggI7MB8GA1UdIwQYMBaAFAdEdoWTKLx/bXjSCuv6TEvf
-2YIfMB0GA1UdDgQWBBSJKI/AYVI9RQNY0QPIqc8ej2QivTAOBgNVHQ8BAf8EBAMC
-BaAwDAYDVR0TAQH/BAIwADA0BgNVHSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIG
-CisGAQQBgjcKAwMGCWCGSAGG+EIEATBMBgNVHSAERTBDMEEGCysGAQQBgOU3AgQB
-MDIwMAYIKwYBBQUHAgEWJGh0dHBzOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0Ev
-Q1BTNDBtBgNVHR8EZjBkMDKgMKAuhixodHRwOi8vY3JsLnRicy1pbnRlcm5ldC5j
-b20vVEJTWDUwOUNBU0dDLmNybDAuoCygKoYoaHR0cDovL2NybC50YnMteDUwOS5j
-b20vVEJTWDUwOUNBU0dDLmNybDCBpgYIKwYBBQUHAQEEgZkwgZYwOAYIKwYBBQUH
-MAKGLGh0dHA6Ly9jcnQudGJzLWludGVybmV0LmNvbS9UQlNYNTA5Q0FTR0MuY3J0
-MDQGCCsGAQUFBzAChihodHRwOi8vY3J0LnRicy14NTA5LmNvbS9UQlNYNTA5Q0FT
-R0MuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wPwYD
-VR0RBDgwNoIXc2hhMjU2LnRicy1pbnRlcm5ldC5jb22CG3d3dy5zaGEyNTYudGJz
-LWludGVybmV0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAA5NL0D4QSqhErhlkdPmz
-XtiMvdGL+ZehM4coTRIpasM/Agt36Rc0NzCvnQwKE+wkngg1Gy2qe7Q0E/ziqBtB
-fZYzdVgu1zdiL4kTaf+wFKYAFGsFbyeEmXysy+CMwaNoF2vpSjCU1UD56bEnTX/W
-fxVZYxtBQUpnu2wOsm8cDZuZRv9XrYgAhGj9Tt6F0aVHSDGn59uwShG1+BVF/uju
-SCyPTTjL1oc7YElJUzR/x4mQJYvtQI8gDIDAGEOs7v3R/gKa5EMfbUQUI4C84UbI
-Yz09Jdnws/MkC/Hm1BZEqk89u7Hvfv+oHqEb0XaUo0TDfsxE0M1sMdnLb91QNQBm
-UQ==
------END CERTIFICATE-----
- 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC
- i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
------BEGIN CERTIFICATE-----
-MIIFVjCCBD6gAwIBAgIQXpDZ0ETJMV02WTx3GTnhhTANBgkqhkiG9w0BAQUFADBv
-MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
-ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
-eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDYyNDE5MDYzMFow
-gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl
-bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u
-ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv
-cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg
-Q0EgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgOkO3f7wzN6
-rOjg45tR5vjBfzK7qmV9IBxb/QW9EEXxG+E7FNhZqQLtwGBKoSsHTnQqV75wWMk0
-9tinWvftBkSpj5sTi/8cbzJfUvTSVYh3Qxv6AVVjMMH/ruLjE6y+4PoaPs8WoYAQ
-ts5R4Z1g8c/WnTepLst2x0/Wv7GmuoQi+gXvHU6YrBiu7XkeYhzc95QdviWSJRDk
-owhb5K43qhcvjRmBfO/paGlCliDGZp8mHwrI21mwobWpVjTxZRwYO3bd4+TGcI4G
-Ie5wmHwE8F7SK1tgSqbBacKjDa93j7txKkfz/Yd2n7TGqOXiHPsJpG655vrKtnXk
-9vs1zoDeJQIDAQABo4IBljCCAZIwHQYDVR0OBBYEFAdEdoWTKLx/bXjSCuv6TEvf
-2YIfMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMCAGA1UdJQQZ
-MBcGCisGAQQBgjcKAwMGCWCGSAGG+EIEATAYBgNVHSAEETAPMA0GCysGAQQBgOU3
-AgQBMHsGA1UdHwR0MHIwOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0Fk
-ZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMDagNKAyhjBodHRwOi8vY3JsLmNvbW9k
-by5uZXQvQWRkVHJ1c3RFeHRlcm5hbENBUm9vdC5jcmwwgYAGCCsGAQUFBwEBBHQw
-cjA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21vZG9jYS5jb20vQWRkVHJ1c3RV
-VE5TR0NDQS5jcnQwNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvLm5ldC9B
-ZGRUcnVzdFVUTlNHQ0NBLmNydDARBglghkgBhvhCAQEEBAMCAgQwDQYJKoZIhvcN
-AQEFBQADggEBAK2zEzs+jcIrVK9oDkdDZNvhuBYTdCfpxfFs+OAujW0bIfJAy232
-euVsnJm6u/+OrqKudD2tad2BbejLLXhMZViaCmK7D9nrXHx4te5EP8rL19SUVqLY
-1pTnv5dhNgEgvA7n5lIzDSYs7yRLsr7HJsYPr6SeYSuZizyX1SNz7ooJ32/F3X98
-RB0Mlc/E0OyOrkQ9/y5IrnpnaSora8CnUrV5XNOg+kyCz9edCyx4D5wXYcwZPVWz
-8aDqquESrezPyjtfi4WRO4s/VD3HLZvOxzMrWAVYCDG9FxaOhF0QGuuG1F7F3GKV
-v6prNyCl016kRl2j1UT+a7gLd8fA25A4C9E=
+cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEdMBsGA1UEAxMUVEJTIFg1MDkg
+Q0EgYnVzaW5lc3MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB1PAU
+qudCcz3tmyGcf+u6EkZqonKKHrV4gZYbvVkIRojmmlhfi/jwvpHvo8bqSt/9Rj5S
+jhCDW0pcbI+IPPtD1Jy+CHNSfnMqVDy6CKQ3p5maTzCMG6ZT+XjnvcND5v+FtaiB
+xk1iCX6uvt0jeUtdZvYbyytsSDE6c3Y5//wRxOF8tM1JxibwO3pyER26jbbN2gQz
+m/EkdGjLdJ4svPk23WDAvQ6G0/z2LcAaJB+XLfqRwfQpHQvfKa1uTi8PivC8qtip
+rmNQMMPMjxSK2azX8cKjjTDJiUKaCb4VHlJDWKEsCFRpgJAoAuX8f7Yfs1M4esGo
+sWb3PGspK3O22uIlAgMBAAGjggF6MIIBdjAdBgNVHQ4EFgQUGgkEzPkJj7seoM7U
+pBR/S9UjWM0wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwGAYD
+VR0gBBEwDzANBgsrBgEEAYDlNwIBATB7BgNVHR8EdDByMDigNqA0hjJodHRwOi8v
+Y3JsLmNvbW9kb2NhLmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDA2oDSg
+MoYwaHR0cDovL2NybC5jb21vZG8ubmV0L0FkZFRydXN0RXh0ZXJuYWxDQVJvb3Qu
+Y3JsMIGGBggrBgEFBQcBAQR6MHgwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29t
+b2RvY2EuY29tL0FkZFRydXN0VVROU2VydmVyQ0EuY3J0MDkGCCsGAQUFBzAChi1o
+dHRwOi8vY3J0LmNvbW9kby5uZXQvQWRkVHJ1c3RVVE5TZXJ2ZXJDQS5jcnQwEQYJ
+YIZIAYb4QgEBBAQDAgIEMA0GCSqGSIb3DQEBBQUAA4IBAQA7mqrMgk/MrE6QnbNA
+h4nRCn2ti4bg4w2C3lB6bSvRPnYwuNw9Jb8vuKkNFzRDxNJXqVDZdfFW5CVQJuyd
+nfAx83+wk+spzvFaE1KhFYfN9G9pQfXUfvDRoIcJgPEKUXL1wRiOG+IjU3VVI8pg
+IgqHkr7ylln5i5zCiFAPuIJmYUSFg/gxH5xkCNcjJqqrHrHatJr6Qrrke93joupw
+oU1njfAcZtYp6fbiK6u2b1pJqwkVBE8RsfLnPhRj+SFbpvjv8Od7o/ieJhFIYQNU
+k2jX2u8qZnAiNw93LZW9lpYjtuvMXq8QQppENNja5b53q7UwI+lU7ZGjZ7quuESp
+J6/5
-----END CERTIFICATE-----
2 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC
+ i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
-----BEGIN CERTIFICATE-----
-MIIEZjCCA06gAwIBAgIQUSYKkxzif5zDpV954HKugjANBgkqhkiG9w0BAQUFADCB
-kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+MIIETzCCAzegAwIBAgIQHM5EYpUZep1jUvnyI6m2mDANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
-IFNHQzAeFw0wNTA2MDcwODA5MTBaFw0xOTA2MjQxOTA2MzBaMG8xCzAJBgNVBAYT
-AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0
-ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
-IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39xoz5vIABC05
-4E5b7R+8bA/Ntfojts7emxEzl6QpTH2Tn71KvJPtAxrjj8/lbVBa1pcplFqAsEl6
-2y6V/bjKvzc4LR4+kUGtcFbH8E8/6DKedMrIkFTpxl8PeJ2aQDwOrGGqXhSPnoeh
-alDc15pOrwWzpnGUnHGzUGAKxxOdOAeGAqjpqGkmGJCrTLBPI6s6T4TY386f4Wlv
-u9dC12tE5Met7m1BX3JacQg3s3llpFmglDf3AC8NwpJy2tA4ctsUqEXEXSp9t7TW
-xO6szRNEt8kr3UMAJfphuWlqWCMRt6czj1Z1WfXNKddGtworZbbTQm8Vsrh7++/p
-XVPVNFonAgMBAAGjgdgwgdUwHwYDVR0jBBgwFoAUUzLRs89/+uDxoF2FTpLSnkUd
-tE8wHQYDVR0OBBYEFK29mHo0tCb3+sQmVO8DveAky1QaMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MBEGCWCGSAGG+EIBAQQEAwIBAjAgBgNVHSUEGTAX
-BgorBgEEAYI3CgMDBglghkgBhvhCBAEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov
-L2NybC51c2VydHJ1c3QuY29tL1VUTi1EQVRBQ29ycFNHQy5jcmwwDQYJKoZIhvcN
-AQEFBQADggEBAMbuUxdoFLJRIh6QWA2U/b3xcOWGLcM2MY9USEbnLQg3vGwKYOEO
-rVE04BKT6b64q7gmtOmWPSiPrmQH/uAB7MXjkesYoPF1ftsK5p+R26+udd8jkWjd
-FwBaS/9kbHDrARrQkNnHptZt9hPk/7XJ0h4qy7ElQyZ42TCbTg0evmnv3+r+LbPM
-+bDdtRTKkdSytaX7ARmjR3mfnYyVhzT4HziS2jamEfpr62vp3EV4FTkG101B5CHI
-3C+H0be/SGB1pWLLJN47YaApIKa+xWycxOkKaSLvkTr6Jq/RW0GnOuL4OAdCq8Fb
-+M5tug8EPzI0rNwEKNdwMBQmBsTkm5jVz3g=
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNMDUwNjA3MDgwOTEwWhcNMTkwNzA5MTgxOTIyWjBvMQswCQYD
+VQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0
+IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h
+bCBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt/caM+by
+AAQtOeBOW+0fvGwPzbX6I7bO3psRM5ekKUx9k5+9SryT7QMa44/P5W1QWtaXKZRa
+gLBJetsulf24yr83OC0ePpFBrXBWx/BPP+gynnTKyJBU6cZfD3idmkA8Dqxhql4U
+j56HoWpQ3NeaTq8Fs6ZxlJxxs1BgCscTnTgHhgKo6ahpJhiQq0ywTyOrOk+E2N/O
+n+Fpb7vXQtdrROTHre5tQV9yWnEIN7N5ZaRZoJQ39wAvDcKSctrQOHLbFKhFxF0q
+fbe01sTurM0TRLfJK91DACX6YblpalgjEbenM49WdVn1zSnXRrcKK2W200JvFbK4
+e/vv6V1T1TRaJwIDAQABo4G9MIG6MB8GA1UdIwQYMBaAFKFyXyYbKJhDlV0HN9WF
+lp1L0sNFMB0GA1UdDgQWBBStvZh6NLQm9/rEJlTvA73gJMtUGjAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQIwRAYDVR0f
+BD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly
+c3QtSGFyZHdhcmUuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQByQhANOs4kClrwF8BW
+onvUOGCSjRK52zYZgDXYNjDtmr5rJ6NyPFDNn+JxkLpjYetIFMTbSRe679Bt8m7a
+gIAoQYFQtxMuyLnJegB2aEbQiIxh/tC21UcFF7ktdnDoTlA6w3pLuvunaI84Of3o
+2YBrhzkTbCfaYk5JRlTpudW9DkUkHBsyx3nknPKnplkIGaK0jgn8E0n+SFabYaHk
+I9LroYT/+JtLefh9lgBdAgVv0UPbzoGfuDsrk/Zh+UrgbLFpHoVnElhzbkh64Z0X
+OGaJunQc68cCZu5HTn/aK7fBGMcVflRCXLVEQpU9PIAdGA8Ynvg684t8GMaKsRl1
+jIGZ
-----END CERTIFICATE-----
- 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC
- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC
+ 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
+ i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
-----BEGIN CERTIFICATE-----
-MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
-kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
-IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
-EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
-VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
-dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
-E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
-D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
-4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
-lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
-bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
-o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
-MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
-LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
-BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
-AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
-Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
-j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
-KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
-2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
-mfnGV/TJVTl4uix5yaaIK/QI
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
-----END CERTIFICATE-----
diff --git a/lib-python/2.7/test/string_tests.py b/lib-python/2.7/test/string_tests.py
--- a/lib-python/2.7/test/string_tests.py
+++ b/lib-python/2.7/test/string_tests.py
@@ -5,6 +5,7 @@
import unittest, string, sys, struct
from test import test_support
from UserList import UserList
+import _testcapi
class Sequence:
def __init__(self, seq='wxyz'): self.seq = seq
@@ -1113,6 +1114,23 @@
self.checkraises(TypeError, '%10.*f', '__mod__', ('foo', 42.))
self.checkraises(ValueError, '%10', '__mod__', (42,))
+ width = int(_testcapi.PY_SSIZE_T_MAX + 1)
+ if width <= sys.maxint:
+ self.checkraises(OverflowError, '%*s', '__mod__', (width, ''))
+ prec = int(_testcapi.INT_MAX + 1)
+ if prec <= sys.maxint:
+ self.checkraises(OverflowError, '%.*f', '__mod__', (prec, 1. / 7))
+ # Issue 15989
+ width = int(1 << (_testcapi.PY_SSIZE_T_MAX.bit_length() + 1))
+ if width <= sys.maxint:
+ self.checkraises(OverflowError, '%*s', '__mod__', (width, ''))
+ prec = int(_testcapi.UINT_MAX + 1)
+ if prec <= sys.maxint:
+ self.checkraises(OverflowError, '%.*f', '__mod__', (prec, 1. / 7))
+
+ class X(object): pass
+ self.checkraises(TypeError, 'abc', '__mod__', X())
+
def test_floatformatting(self):
# float formatting
for prec in xrange(100):
diff --git a/lib-python/2.7/test/subprocessdata/sigchild_ignore.py b/lib-python/2.7/test/subprocessdata/sigchild_ignore.py
--- a/lib-python/2.7/test/subprocessdata/sigchild_ignore.py
+++ b/lib-python/2.7/test/subprocessdata/sigchild_ignore.py
@@ -1,6 +1,15 @@
-import signal, subprocess, sys
+import signal, subprocess, sys, time
# On Linux this causes os.waitpid to fail with OSError as the OS has already
# reaped our child process. The wait() passing the OSError on to the caller
# and causing us to exit with an error is what we are testing against.
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
subprocess.Popen([sys.executable, '-c', 'print("albatross")']).wait()
+# Also ensure poll() handles an errno.ECHILD appropriately.
+p = subprocess.Popen([sys.executable, '-c', 'print("albatross")'])
+num_polls = 0
+while p.poll() is None:
+ # Waiting for the process to finish.
+ time.sleep(0.01) # Avoid being a CPU busy loop.
+ num_polls += 1
+ if num_polls > 3000:
+ raise RuntimeError('poll should have returned 0 within 30 seconds')
diff --git a/lib-python/2.7/test/test_StringIO.py b/lib-python/2.7/test/test_StringIO.py
--- a/lib-python/2.7/test/test_StringIO.py
+++ b/lib-python/2.7/test/test_StringIO.py
@@ -5,6 +5,7 @@
import cStringIO
import types
import array
+import sys
from test import test_support
@@ -27,6 +28,8 @@
eq = self.assertEqual
self.assertRaises(TypeError, self._fp.seek)
eq(self._fp.read(10), self._line[:10])
+ eq(self._fp.read(0), '')
+ eq(self._fp.readline(0), '')
eq(self._fp.readline(), self._line[10:] + '\n')
eq(len(self._fp.readlines(60)), 2)
self._fp.seek(0)
@@ -105,6 +108,45 @@
self._fp.close()
self.assertRaises(ValueError, self._fp.getvalue)
+ @test_support.bigmemtest(test_support._2G + 2**26, memuse=2.001)
+ def test_reads_from_large_stream(self, size):
+ linesize = 2**26 # 64 MiB
+ lines = ['x' * (linesize - 1) + '\n'] * (size // linesize) + \
+ ['y' * (size % linesize)]
+ f = self.MODULE.StringIO(''.join(lines))
+ for i, expected in enumerate(lines):
+ line = f.read(len(expected))
+ self.assertEqual(len(line), len(expected))
+ self.assertEqual(line, expected)
+ self.assertEqual(f.read(), '')
+ f.seek(0)
+ for i, expected in enumerate(lines):
+ line = f.readline()
+ self.assertEqual(len(line), len(expected))
+ self.assertEqual(line, expected)
+ self.assertEqual(f.readline(), '')
+ f.seek(0)
+ self.assertEqual(f.readlines(), lines)
+ self.assertEqual(f.readlines(), [])
+ f.seek(0)
+ self.assertEqual(f.readlines(size), lines)
+ self.assertEqual(f.readlines(), [])
+
+ # In worst case cStringIO requires 2 + 1 + 1/2 + 1/2**2 + ... = 4
+ # bytes per input character.
+ @test_support.bigmemtest(test_support._2G, memuse=4)
+ def test_writes_to_large_stream(self, size):
+ s = 'x' * 2**26 # 64 MiB
+ f = self.MODULE.StringIO()
+ n = size
+ while n > len(s):
+ f.write(s)
+ n -= len(s)
+ s = None
+ f.write('x' * n)
+ self.assertEqual(len(f.getvalue()), size)
+
+
class TestStringIO(TestGenericStringIO):
MODULE = StringIO
diff --git a/lib-python/2.7/test/test_aifc.py b/lib-python/2.7/test/test_aifc.py
--- a/lib-python/2.7/test/test_aifc.py
+++ b/lib-python/2.7/test/test_aifc.py
@@ -106,6 +106,13 @@
self.assertEqual(testfile.closed, False)
f.close()
self.assertEqual(testfile.closed, True)
+ testfile = open(TESTFN, 'wb')
+ fout = aifc.open(testfile, 'wb')
+ self.assertFalse(testfile.closed)
+ with self.assertRaises(aifc.Error):
+ fout.close()
+ self.assertTrue(testfile.closed)
+ fout.close() # do nothing
class AIFCLowLevelTest(unittest.TestCase):
diff --git a/lib-python/2.7/test/test_argparse.py b/lib-python/2.7/test/test_argparse.py
--- a/lib-python/2.7/test/test_argparse.py
+++ b/lib-python/2.7/test/test_argparse.py
@@ -1374,6 +1374,7 @@
('X @hello', NS(a=None, x='X', y=['hello world!'])),
('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])),
('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])),
+ (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])),
]
@@ -1466,6 +1467,22 @@
('readonly', NS(x=None, spam=RFile('readonly'))),
]
+class TestFileTypeDefaults(TempDirMixin, ParserTestCase):
+ """Test that a file is not created unless the default is needed"""
+ def setUp(self):
+ super(TestFileTypeDefaults, self).setUp()
+ file = open(os.path.join(self.temp_dir, 'good'), 'w')
+ file.write('good')
+ file.close()
+
+ argument_signatures = [
+ Sig('-c', type=argparse.FileType('r'), default='no-file.txt'),
+ ]
+ # should provoke no such file error
+ failures = ['']
+ # should not provoke error because default file is created
+ successes = [('-c good', NS(c=RFile('good')))]
+
class TestFileTypeRB(TempDirMixin, ParserTestCase):
"""Test the FileType option/argument type for reading files"""
@@ -1763,6 +1780,14 @@
parser2.add_argument('-y', choices='123', help='y help')
parser2.add_argument('z', type=complex, nargs='*', help='z help')
+ # add third sub-parser
+ parser3_kwargs = dict(description='3 description')
+ if subparser_help:
+ parser3_kwargs['help'] = '3 help'
+ parser3 = subparsers.add_parser('3', **parser3_kwargs)
+ parser3.add_argument('t', type=int, help='t help')
+ parser3.add_argument('u', nargs='...', help='u help')
+
# return the main parser
return parser
@@ -1792,6 +1817,10 @@
self.parser.parse_args('--foo 0.125 1 c'.split()),
NS(foo=True, bar=0.125, w=None, x='c'),
)
+ self.assertEqual(
+ self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()),
+ NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']),
+ )
def test_parse_known_args(self):
self.assertEqual(
@@ -1826,15 +1855,15 @@
def test_help(self):
self.assertEqual(self.parser.format_usage(),
- 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
+ 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
- usage: PROG [-h] [--foo] bar {1,2} ...
+ usage: PROG [-h] [--foo] bar {1,2,3} ...
main description
positional arguments:
bar bar help
- {1,2} command help
+ {1,2,3} command help
optional arguments:
-h, --help show this help message and exit
@@ -1845,15 +1874,15 @@
# Make sure - is still used for help if it is a non-first prefix char
parser = self._get_parser(prefix_chars='+:-')
self.assertEqual(parser.format_usage(),
- 'usage: PROG [-h] [++foo] bar {1,2} ...\n')
+ 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n')
self.assertEqual(parser.format_help(), textwrap.dedent('''\
- usage: PROG [-h] [++foo] bar {1,2} ...
+ usage: PROG [-h] [++foo] bar {1,2,3} ...
main description
positional arguments:
bar bar help
- {1,2} command help
+ {1,2,3} command help
optional arguments:
-h, --help show this help message and exit
@@ -1864,15 +1893,15 @@
def test_help_alternate_prefix_chars(self):
parser = self._get_parser(prefix_chars='+:/')
self.assertEqual(parser.format_usage(),
- 'usage: PROG [+h] [++foo] bar {1,2} ...\n')
+ 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n')
self.assertEqual(parser.format_help(), textwrap.dedent('''\
- usage: PROG [+h] [++foo] bar {1,2} ...
+ usage: PROG [+h] [++foo] bar {1,2,3} ...
main description
positional arguments:
bar bar help
- {1,2} command help
+ {1,2,3} command help
optional arguments:
+h, ++help show this help message and exit
@@ -1881,18 +1910,19 @@
def test_parser_command_help(self):
self.assertEqual(self.command_help_parser.format_usage(),
- 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
+ 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
self.assertEqual(self.command_help_parser.format_help(),
textwrap.dedent('''\
- usage: PROG [-h] [--foo] bar {1,2} ...
+ usage: PROG [-h] [--foo] bar {1,2,3} ...
main description
positional arguments:
bar bar help
- {1,2} command help
+ {1,2,3} command help
1 1 help
2 2 help
+ 3 3 help
optional arguments:
-h, --help show this help message and exit
@@ -4418,12 +4448,95 @@
else:
self.fail()
+# ================================================
+# Check that the type function is called only once
+# ================================================
+
+class TestTypeFunctionCallOnlyOnce(TestCase):
+
+ def test_type_function_call_only_once(self):
+ def spam(string_to_convert):
+ self.assertEqual(string_to_convert, 'spam!')
+ return 'foo_converted'
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--foo', type=spam, default='bar')
+ args = parser.parse_args('--foo spam!'.split())
+ self.assertEqual(NS(foo='foo_converted'), args)
+
+# ==================================================================
+# Check semantics regarding the default argument and type conversion
+# ==================================================================
+
+class TestTypeFunctionCalledOnDefault(TestCase):
+
+ def test_type_function_call_with_non_string_default(self):
+ def spam(int_to_convert):
+ self.assertEqual(int_to_convert, 0)
+ return 'foo_converted'
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--foo', type=spam, default=0)
+ args = parser.parse_args([])
+ # foo should *not* be converted because its default is not a string.
+ self.assertEqual(NS(foo=0), args)
+
+ def test_type_function_call_with_string_default(self):
+ def spam(int_to_convert):
+ return 'foo_converted'
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--foo', type=spam, default='0')
+ args = parser.parse_args([])
+ # foo is converted because its default is a string.
+ self.assertEqual(NS(foo='foo_converted'), args)
+
+ def test_no_double_type_conversion_of_default(self):
+ def extend(str_to_convert):
+ return str_to_convert + '*'
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--test', type=extend, default='*')
+ args = parser.parse_args([])
+ # The test argument will be two stars, one coming from the default
+ # value and one coming from the type conversion being called exactly
+ # once.
+ self.assertEqual(NS(test='**'), args)
+
+ def test_issue_15906(self):
+ # Issue #15906: When action='append', type=str, default=[] are
+ # providing, the dest value was the string representation "[]" when it
+ # should have been an empty list.
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--test', dest='test', type=str,
+ default=[], action='append')
+ args = parser.parse_args([])
+ self.assertEqual(args.test, [])
+
# ======================
# parse_known_args tests
# ======================
class TestParseKnownArgs(TestCase):
+ def test_arguments_tuple(self):
+ parser = argparse.ArgumentParser()
+ parser.parse_args(())
+
+ def test_arguments_list(self):
+ parser = argparse.ArgumentParser()
+ parser.parse_args([])
+
+ def test_arguments_tuple_positional(self):
+ parser = argparse.ArgumentParser()
+ parser.add_argument('x')
+ parser.parse_args(('x',))
+
+ def test_arguments_list_positional(self):
+ parser = argparse.ArgumentParser()
+ parser.add_argument('x')
+ parser.parse_args(['x'])
+
def test_optionals(self):
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
diff --git a/lib-python/2.7/test/test_array.py b/lib-python/2.7/test/test_array.py
--- a/lib-python/2.7/test/test_array.py
+++ b/lib-python/2.7/test/test_array.py
@@ -985,6 +985,19 @@
upper = long(pow(2, a.itemsize * 8)) - 1L
self.check_overflow(lower, upper)
+ @test_support.cpython_only
+ def test_sizeof_with_buffer(self):
+ a = array.array(self.typecode, self.example)
+ basesize = test_support.calcvobjsize('4P')
+ buffer_size = a.buffer_info()[1] * a.itemsize
+ test_support.check_sizeof(self, a, basesize + buffer_size)
+
+ @test_support.cpython_only
+ def test_sizeof_without_buffer(self):
+ a = array.array(self.typecode)
+ basesize = test_support.calcvobjsize('4P')
+ test_support.check_sizeof(self, a, basesize)
+
class ByteTest(SignedNumberTest):
typecode = 'b'
diff --git a/lib-python/2.7/test/test_ast.py b/lib-python/2.7/test/test_ast.py
--- a/lib-python/2.7/test/test_ast.py
+++ b/lib-python/2.7/test/test_ast.py
@@ -231,6 +231,12 @@
im = ast.parse("from . import y").body[0]
self.assertIsNone(im.module)
+ def test_non_interned_future_from_ast(self):
+ mod = ast.parse("from __future__ import division")
+ self.assertIsInstance(mod.body[0], ast.ImportFrom)
+ mod.body[0].module = " __future__ ".strip()
+ compile(mod, "<test>", "exec")
+
def test_base_classes(self):
self.assertTrue(issubclass(ast.For, ast.stmt))
self.assertTrue(issubclass(ast.Name, ast.expr))
diff --git a/lib-python/2.7/test/test_asyncore.py b/lib-python/2.7/test/test_asyncore.py
--- a/lib-python/2.7/test/test_asyncore.py
+++ b/lib-python/2.7/test/test_asyncore.py
@@ -7,6 +7,7 @@
import time
import warnings
import errno
+import struct
from test import test_support
from test.test_support import TESTFN, run_unittest, unlink
@@ -483,8 +484,9 @@
return self.socket.getsockname()[:2]
def handle_accept(self):
- sock, addr = self.accept()
- self.handler(sock)
+ pair = self.accept()
+ if pair is not None:
+ self.handler(pair[0])
def handle_error(self):
raise
@@ -703,6 +705,27 @@
finally:
sock.close()
+ @unittest.skipUnless(threading, 'Threading required for this test.')
+ @test_support.reap_threads
+ def test_quick_connect(self):
+ # see: http://bugs.python.org/issue10340
+ server = TCPServer()
+ t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, count=500))
+ t.start()
+ self.addCleanup(t.join)
+
+ for x in xrange(20):
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.settimeout(.2)
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
+ struct.pack('ii', 1, 0))
+ try:
+ s.connect(server.address)
+ except socket.error:
+ pass
+ finally:
+ s.close()
+
class TestAPI_UseSelect(BaseTestAPI):
use_poll = False
diff --git a/lib-python/2.7/test/test_audioop.py b/lib-python/2.7/test/test_audioop.py
--- a/lib-python/2.7/test/test_audioop.py
+++ b/lib-python/2.7/test/test_audioop.py
@@ -1,25 +1,33 @@
import audioop
+import sys
import unittest
+import struct
from test.test_support import run_unittest
-endian = 'big' if audioop.getsample('\0\1', 2, 0) == 1 else 'little'
-def gendata1():
- return '\0\1\2'
+formats = {
+ 1: 'b',
+ 2: 'h',
+ 4: 'i',
+}
-def gendata2():
- if endian == 'big':
- return '\0\0\0\1\0\2'
- else:
- return '\0\0\1\0\2\0'
+def pack(width, data):
+ return struct.pack('=%d%s' % (len(data), formats[width]), *data)
-def gendata4():
- if endian == 'big':
- return '\0\0\0\0\0\0\0\1\0\0\0\2'
- else:
- return '\0\0\0\0\1\0\0\0\2\0\0\0'
+packs = {
+ 1: lambda *data: pack(1, data),
+ 2: lambda *data: pack(2, data),
+ 4: lambda *data: pack(4, data),
+}
+maxvalues = {w: (1 << (8 * w - 1)) - 1 for w in (1, 2, 4)}
+minvalues = {w: -1 << (8 * w - 1) for w in (1, 2, 4)}
-data = [gendata1(), gendata2(), gendata4()]
+datas = {
+ 1: b'\x00\x12\x45\xbb\x7f\x80\xff',
+ 2: packs[2](0, 0x1234, 0x4567, -0x4567, 0x7fff, -0x8000, -1),
+ 4: packs[4](0, 0x12345678, 0x456789ab, -0x456789ab,
+ 0x7fffffff, -0x80000000, -1),
+}
INVALID_DATA = [
(b'abc', 0),
@@ -31,164 +39,315 @@
class TestAudioop(unittest.TestCase):
def test_max(self):
- self.assertEqual(audioop.max(data[0], 1), 2)
- self.assertEqual(audioop.max(data[1], 2), 2)
- self.assertEqual(audioop.max(data[2], 4), 2)
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.max(b'', w), 0)
+ p = packs[w]
+ self.assertEqual(audioop.max(p(5), w), 5)
+ self.assertEqual(audioop.max(p(5, -8, -1), w), 8)
+ self.assertEqual(audioop.max(p(maxvalues[w]), w), maxvalues[w])
+ self.assertEqual(audioop.max(p(minvalues[w]), w), -minvalues[w])
+ self.assertEqual(audioop.max(datas[w], w), -minvalues[w])
def test_minmax(self):
- self.assertEqual(audioop.minmax(data[0], 1), (0, 2))
- self.assertEqual(audioop.minmax(data[1], 2), (0, 2))
- self.assertEqual(audioop.minmax(data[2], 4), (0, 2))
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.minmax(b'', w),
+ (0x7fffffff, -0x80000000))
+ p = packs[w]
+ self.assertEqual(audioop.minmax(p(5), w), (5, 5))
+ self.assertEqual(audioop.minmax(p(5, -8, -1), w), (-8, 5))
+ self.assertEqual(audioop.minmax(p(maxvalues[w]), w),
+ (maxvalues[w], maxvalues[w]))
+ self.assertEqual(audioop.minmax(p(minvalues[w]), w),
+ (minvalues[w], minvalues[w]))
+ self.assertEqual(audioop.minmax(datas[w], w),
+ (minvalues[w], maxvalues[w]))
def test_maxpp(self):
- self.assertEqual(audioop.maxpp(data[0], 1), 0)
- self.assertEqual(audioop.maxpp(data[1], 2), 0)
- self.assertEqual(audioop.maxpp(data[2], 4), 0)
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.maxpp(b'', w), 0)
+ self.assertEqual(audioop.maxpp(packs[w](*range(100)), w), 0)
+ self.assertEqual(audioop.maxpp(packs[w](9, 10, 5, 5, 0, 1), w), 10)
+ self.assertEqual(audioop.maxpp(datas[w], w),
+ maxvalues[w] - minvalues[w])
def test_avg(self):
- self.assertEqual(audioop.avg(data[0], 1), 1)
- self.assertEqual(audioop.avg(data[1], 2), 1)
- self.assertEqual(audioop.avg(data[2], 4), 1)
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.avg(b'', w), 0)
+ p = packs[w]
+ self.assertEqual(audioop.avg(p(5), w), 5)
+ self .assertEqual(audioop.avg(p(5, 8), w), 6)
+ self.assertEqual(audioop.avg(p(5, -8), w), -2)
+ self.assertEqual(audioop.avg(p(maxvalues[w], maxvalues[w]), w),
+ maxvalues[w])
+ self.assertEqual(audioop.avg(p(minvalues[w], minvalues[w]), w),
+ minvalues[w])
+ self.assertEqual(audioop.avg(packs[4](0x50000000, 0x70000000), 4),
+ 0x60000000)
+ self.assertEqual(audioop.avg(packs[4](-0x50000000, -0x70000000), 4),
+ -0x60000000)
def test_avgpp(self):
- self.assertEqual(audioop.avgpp(data[0], 1), 0)
- self.assertEqual(audioop.avgpp(data[1], 2), 0)
- self.assertEqual(audioop.avgpp(data[2], 4), 0)
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.avgpp(b'', w), 0)
+ self.assertEqual(audioop.avgpp(packs[w](*range(100)), w), 0)
+ self.assertEqual(audioop.avgpp(packs[w](9, 10, 5, 5, 0, 1), w), 10)
+ self.assertEqual(audioop.avgpp(datas[1], 1), 196)
+ self.assertEqual(audioop.avgpp(datas[2], 2), 50534)
+ self.assertEqual(audioop.avgpp(datas[4], 4), 3311897002)
def test_rms(self):
- self.assertEqual(audioop.rms(data[0], 1), 1)
- self.assertEqual(audioop.rms(data[1], 2), 1)
- self.assertEqual(audioop.rms(data[2], 4), 1)
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.rms(b'', w), 0)
+ p = packs[w]
+ self.assertEqual(audioop.rms(p(*range(100)), w), 57)
+ self.assertAlmostEqual(audioop.rms(p(maxvalues[w]) * 5, w),
+ maxvalues[w], delta=1)
+ self.assertAlmostEqual(audioop.rms(p(minvalues[w]) * 5, w),
+ -minvalues[w], delta=1)
+ self.assertEqual(audioop.rms(datas[1], 1), 77)
+ self.assertEqual(audioop.rms(datas[2], 2), 20001)
+ self.assertEqual(audioop.rms(datas[4], 4), 1310854152)
def test_cross(self):
- self.assertEqual(audioop.cross(data[0], 1), 0)
- self.assertEqual(audioop.cross(data[1], 2), 0)
- self.assertEqual(audioop.cross(data[2], 4), 0)
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.cross(b'', w), -1)
+ p = packs[w]
+ self.assertEqual(audioop.cross(p(0, 1, 2), w), 0)
+ self.assertEqual(audioop.cross(p(1, 2, -3, -4), w), 1)
+ self.assertEqual(audioop.cross(p(-1, -2, 3, 4), w), 1)
+ self.assertEqual(audioop.cross(p(0, minvalues[w]), w), 1)
+ self.assertEqual(audioop.cross(p(minvalues[w], maxvalues[w]), w), 1)
def test_add(self):
- data2 = []
- for d in data:
- str = ''
- for s in d:
- str = str + chr(ord(s)*2)
- data2.append(str)
- self.assertEqual(audioop.add(data[0], data[0], 1), data2[0])
- self.assertEqual(audioop.add(data[1], data[1], 2), data2[1])
- self.assertEqual(audioop.add(data[2], data[2], 4), data2[2])
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.add(b'', b'', w), b'')
+ self.assertEqual(audioop.add(datas[w], b'\0' * len(datas[w]), w),
+ datas[w])
+ self.assertEqual(audioop.add(datas[1], datas[1], 1),
+ b'\x00\x24\x7f\x80\x7f\x80\xfe')
+ self.assertEqual(audioop.add(datas[2], datas[2], 2),
+ packs[2](0, 0x2468, 0x7fff, -0x8000, 0x7fff, -0x8000, -2))
+ self.assertEqual(audioop.add(datas[4], datas[4], 4),
+ packs[4](0, 0x2468acf0, 0x7fffffff, -0x80000000,
+ 0x7fffffff, -0x80000000, -2))
def test_bias(self):
- # Note: this test assumes that avg() works
- d1 = audioop.bias(data[0], 1, 100)
- d2 = audioop.bias(data[1], 2, 100)
- d4 = audioop.bias(data[2], 4, 100)
- self.assertEqual(audioop.avg(d1, 1), 101)
- self.assertEqual(audioop.avg(d2, 2), 101)
- self.assertEqual(audioop.avg(d4, 4), 101)
+ for w in 1, 2, 4:
+ for bias in 0, 1, -1, 127, -128, 0x7fffffff, -0x80000000:
+ self.assertEqual(audioop.bias(b'', w, bias), b'')
+ self.assertEqual(audioop.bias(datas[1], 1, 1),
+ b'\x01\x13\x46\xbc\x80\x81\x00')
+ self.assertEqual(audioop.bias(datas[1], 1, -1),
+ b'\xff\x11\x44\xba\x7e\x7f\xfe')
+ self.assertEqual(audioop.bias(datas[1], 1, 0x7fffffff),
+ b'\xff\x11\x44\xba\x7e\x7f\xfe')
+ self.assertEqual(audioop.bias(datas[1], 1, -0x80000000),
+ datas[1])
+ self.assertEqual(audioop.bias(datas[2], 2, 1),
+ packs[2](1, 0x1235, 0x4568, -0x4566, -0x8000, -0x7fff, 0))
+ self.assertEqual(audioop.bias(datas[2], 2, -1),
+ packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7ffe, 0x7fff, -2))
+ self.assertEqual(audioop.bias(datas[2], 2, 0x7fffffff),
+ packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7ffe, 0x7fff, -2))
+ self.assertEqual(audioop.bias(datas[2], 2, -0x80000000),
+ datas[2])
+ self.assertEqual(audioop.bias(datas[4], 4, 1),
+ packs[4](1, 0x12345679, 0x456789ac, -0x456789aa,
+ -0x80000000, -0x7fffffff, 0))
+ self.assertEqual(audioop.bias(datas[4], 4, -1),
+ packs[4](-1, 0x12345677, 0x456789aa, -0x456789ac,
+ 0x7ffffffe, 0x7fffffff, -2))
+ self.assertEqual(audioop.bias(datas[4], 4, 0x7fffffff),
+ packs[4](0x7fffffff, -0x6dcba989, -0x3a987656, 0x3a987654,
+ -2, -1, 0x7ffffffe))
+ self.assertEqual(audioop.bias(datas[4], 4, -0x80000000),
+ packs[4](-0x80000000, -0x6dcba988, -0x3a987655, 0x3a987655,
+ -1, 0, 0x7fffffff))
def test_lin2lin(self):
- # too simple: we test only the size
- for d1 in data:
- for d2 in data:
- got = len(d1)//3
- wtd = len(d2)//3
- self.assertEqual(len(audioop.lin2lin(d1, got, wtd)), len(d2))
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.lin2lin(datas[w], w, w), datas[w])
+
+ self.assertEqual(audioop.lin2lin(datas[1], 1, 2),
+ packs[2](0, 0x1200, 0x4500, -0x4500, 0x7f00, -0x8000, -0x100))
+ self.assertEqual(audioop.lin2lin(datas[1], 1, 4),
+ packs[4](0, 0x12000000, 0x45000000, -0x45000000,
+ 0x7f000000, -0x80000000, -0x1000000))
+ self.assertEqual(audioop.lin2lin(datas[2], 2, 1),
+ b'\x00\x12\x45\xba\x7f\x80\xff')
+ self.assertEqual(audioop.lin2lin(datas[2], 2, 4),
+ packs[4](0, 0x12340000, 0x45670000, -0x45670000,
+ 0x7fff0000, -0x80000000, -0x10000))
+ self.assertEqual(audioop.lin2lin(datas[4], 4, 1),
+ b'\x00\x12\x45\xba\x7f\x80\xff')
+ self.assertEqual(audioop.lin2lin(datas[4], 4, 2),
+ packs[2](0, 0x1234, 0x4567, -0x4568, 0x7fff, -0x8000, -1))
def test_adpcm2lin(self):
+ self.assertEqual(audioop.adpcm2lin(b'\x07\x7f\x7f', 1, None),
+ (b'\x00\x00\x00\xff\x00\xff', (-179, 40)))
+ self.assertEqual(audioop.adpcm2lin(b'\x07\x7f\x7f', 2, None),
+ (packs[2](0, 0xb, 0x29, -0x16, 0x72, -0xb3), (-179, 40)))
+ self.assertEqual(audioop.adpcm2lin(b'\x07\x7f\x7f', 4, None),
+ (packs[4](0, 0xb0000, 0x290000, -0x160000, 0x720000,
+ -0xb30000), (-179, 40)))
+
# Very cursory test
- self.assertEqual(audioop.adpcm2lin(b'\0\0', 1, None), (b'\0' * 4, (0,0)))
- self.assertEqual(audioop.adpcm2lin(b'\0\0', 2, None), (b'\0' * 8, (0,0)))
- self.assertEqual(audioop.adpcm2lin(b'\0\0', 4, None), (b'\0' * 16, (0,0)))
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.adpcm2lin(b'\0' * 5, w, None),
+ (b'\0' * w * 10, (0, 0)))
def test_lin2adpcm(self):
+ self.assertEqual(audioop.lin2adpcm(datas[1], 1, None),
+ (b'\x07\x7f\x7f', (-221, 39)))
+ self.assertEqual(audioop.lin2adpcm(datas[2], 2, None),
+ (b'\x07\x7f\x7f', (31, 39)))
+ self.assertEqual(audioop.lin2adpcm(datas[4], 4, None),
+ (b'\x07\x7f\x7f', (31, 39)))
+
# Very cursory test
- self.assertEqual(audioop.lin2adpcm('\0\0\0\0', 1, None), ('\0\0', (0,0)))
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.lin2adpcm(b'\0' * w * 10, w, None),
+ (b'\0' * 5, (0, 0)))
def test_lin2alaw(self):
- self.assertEqual(audioop.lin2alaw(data[0], 1), '\xd5\xc5\xf5')
- self.assertEqual(audioop.lin2alaw(data[1], 2), '\xd5\xd5\xd5')
- self.assertEqual(audioop.lin2alaw(data[2], 4), '\xd5\xd5\xd5')
+ self.assertEqual(audioop.lin2alaw(datas[1], 1),
+ b'\xd5\x87\xa4\x24\xaa\x2a\x5a')
+ self.assertEqual(audioop.lin2alaw(datas[2], 2),
+ b'\xd5\x87\xa4\x24\xaa\x2a\x55')
+ self.assertEqual(audioop.lin2alaw(datas[4], 4),
+ b'\xd5\x87\xa4\x24\xaa\x2a\x55')
def test_alaw2lin(self):
- # Cursory
- d = audioop.lin2alaw(data[0], 1)
- self.assertEqual(audioop.alaw2lin(d, 1), data[0])
- if endian == 'big':
- self.assertEqual(audioop.alaw2lin(d, 2),
- b'\x00\x08\x01\x08\x02\x10')
- self.assertEqual(audioop.alaw2lin(d, 4),
- b'\x00\x08\x00\x00\x01\x08\x00\x00\x02\x10\x00\x00')
- else:
- self.assertEqual(audioop.alaw2lin(d, 2),
- b'\x08\x00\x08\x01\x10\x02')
- self.assertEqual(audioop.alaw2lin(d, 4),
- b'\x00\x00\x08\x00\x00\x00\x08\x01\x00\x00\x10\x02')
+ encoded = b'\x00\x03\x24\x2a\x51\x54\x55\x58\x6b\x71\x7f'\
+ b'\x80\x83\xa4\xaa\xd1\xd4\xd5\xd8\xeb\xf1\xff'
+ src = [-688, -720, -2240, -4032, -9, -3, -1, -27, -244, -82, -106,
+ 688, 720, 2240, 4032, 9, 3, 1, 27, 244, 82, 106]
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.alaw2lin(encoded, w),
+ packs[w](*(x << (w * 8) >> 13 for x in src)))
+
+ encoded = ''.join(chr(x) for x in xrange(256))
+ for w in 2, 4:
+ decoded = audioop.alaw2lin(encoded, w)
+ self.assertEqual(audioop.lin2alaw(decoded, w), encoded)
def test_lin2ulaw(self):
- self.assertEqual(audioop.lin2ulaw(data[0], 1), '\xff\xe7\xdb')
- self.assertEqual(audioop.lin2ulaw(data[1], 2), '\xff\xff\xff')
- self.assertEqual(audioop.lin2ulaw(data[2], 4), '\xff\xff\xff')
+ self.assertEqual(audioop.lin2ulaw(datas[1], 1),
+ b'\xff\xad\x8e\x0e\x80\x00\x67')
+ self.assertEqual(audioop.lin2ulaw(datas[2], 2),
+ b'\xff\xad\x8e\x0e\x80\x00\x7e')
+ self.assertEqual(audioop.lin2ulaw(datas[4], 4),
+ b'\xff\xad\x8e\x0e\x80\x00\x7e')
def test_ulaw2lin(self):
- # Cursory
- d = audioop.lin2ulaw(data[0], 1)
- self.assertEqual(audioop.ulaw2lin(d, 1), data[0])
- if endian == 'big':
- self.assertEqual(audioop.ulaw2lin(d, 2),
- b'\x00\x00\x01\x04\x02\x0c')
- self.assertEqual(audioop.ulaw2lin(d, 4),
- b'\x00\x00\x00\x00\x01\x04\x00\x00\x02\x0c\x00\x00')
- else:
- self.assertEqual(audioop.ulaw2lin(d, 2),
- b'\x00\x00\x04\x01\x0c\x02')
- self.assertEqual(audioop.ulaw2lin(d, 4),
- b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x0c\x02')
+ encoded = b'\x00\x0e\x28\x3f\x57\x6a\x76\x7c\x7e\x7f'\
+ b'\x80\x8e\xa8\xbf\xd7\xea\xf6\xfc\xfe\xff'
+ src = [-8031, -4447, -1471, -495, -163, -53, -18, -6, -2, 0,
+ 8031, 4447, 1471, 495, 163, 53, 18, 6, 2, 0]
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.ulaw2lin(encoded, w),
+ packs[w](*(x << (w * 8) >> 14 for x in src)))
+
+ # Current u-law implementation has two codes fo 0: 0x7f and 0xff.
+ encoded = ''.join(chr(x) for x in range(127) + range(128, 256))
+ for w in 2, 4:
+ decoded = audioop.ulaw2lin(encoded, w)
+ self.assertEqual(audioop.lin2ulaw(decoded, w), encoded)
def test_mul(self):
- data2 = []
- for d in data:
- str = ''
- for s in d:
- str = str + chr(ord(s)*2)
- data2.append(str)
- self.assertEqual(audioop.mul(data[0], 1, 2), data2[0])
- self.assertEqual(audioop.mul(data[1],2, 2), data2[1])
- self.assertEqual(audioop.mul(data[2], 4, 2), data2[2])
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.mul(b'', w, 2), b'')
+ self.assertEqual(audioop.mul(datas[w], w, 0),
+ b'\0' * len(datas[w]))
+ self.assertEqual(audioop.mul(datas[w], w, 1),
+ datas[w])
+ self.assertEqual(audioop.mul(datas[1], 1, 2),
+ b'\x00\x24\x7f\x80\x7f\x80\xfe')
+ self.assertEqual(audioop.mul(datas[2], 2, 2),
+ packs[2](0, 0x2468, 0x7fff, -0x8000, 0x7fff, -0x8000, -2))
+ self.assertEqual(audioop.mul(datas[4], 4, 2),
+ packs[4](0, 0x2468acf0, 0x7fffffff, -0x80000000,
+ 0x7fffffff, -0x80000000, -2))
def test_ratecv(self):
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 8000, None),
+ (b'', (-1, ((0, 0),))))
+ self.assertEqual(audioop.ratecv(b'', w, 5, 8000, 8000, None),
+ (b'', (-1, ((0, 0),) * 5)))
+ self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 16000, None),
+ (b'', (-2, ((0, 0),))))
+ self.assertEqual(audioop.ratecv(datas[w], w, 1, 8000, 8000, None)[0],
+ datas[w])
state = None
- d1, state = audioop.ratecv(data[0], 1, 1, 8000, 16000, state)
- d2, state = audioop.ratecv(data[0], 1, 1, 8000, 16000, state)
- self.assertEqual(d1 + d2, '\000\000\001\001\002\001\000\000\001\001\002')
+ d1, state = audioop.ratecv(b'\x00\x01\x02', 1, 1, 8000, 16000, state)
+ d2, state = audioop.ratecv(b'\x00\x01\x02', 1, 1, 8000, 16000, state)
+ self.assertEqual(d1 + d2, b'\000\000\001\001\002\001\000\000\001\001\002')
+
+ for w in 1, 2, 4:
+ d0, state0 = audioop.ratecv(datas[w], w, 1, 8000, 16000, None)
+ d, state = b'', None
+ for i in range(0, len(datas[w]), w):
+ d1, state = audioop.ratecv(datas[w][i:i + w], w, 1,
+ 8000, 16000, state)
+ d += d1
+ self.assertEqual(d, d0)
+ self.assertEqual(state, state0)
def test_reverse(self):
- self.assertEqual(audioop.reverse(data[0], 1), '\2\1\0')
+ for w in 1, 2, 4:
+ self.assertEqual(audioop.reverse(b'', w), b'')
+ self.assertEqual(audioop.reverse(packs[w](0, 1, 2), w),
+ packs[w](2, 1, 0))
def test_tomono(self):
- data2 = ''
- for d in data[0]:
- data2 = data2 + d + d
- self.assertEqual(audioop.tomono(data2, 1, 0.5, 0.5), data[0])
+ for w in 1, 2, 4:
+ data1 = datas[w]
+ data2 = bytearray(2 * len(data1))
+ for k in range(w):
+ data2[k::2*w] = data1[k::w]
+ self.assertEqual(audioop.tomono(str(data2), w, 1, 0), data1)
+ self.assertEqual(audioop.tomono(str(data2), w, 0, 1), b'\0' * len(data1))
+ for k in range(w):
+ data2[k+w::2*w] = data1[k::w]
+ self.assertEqual(audioop.tomono(str(data2), w, 0.5, 0.5), data1)
def test_tostereo(self):
- data2 = ''
- for d in data[0]:
- data2 = data2 + d + d
- self.assertEqual(audioop.tostereo(data[0], 1, 1, 1), data2)
+ for w in 1, 2, 4:
+ data1 = datas[w]
+ data2 = bytearray(2 * len(data1))
+ for k in range(w):
+ data2[k::2*w] = data1[k::w]
+ self.assertEqual(audioop.tostereo(data1, w, 1, 0), data2)
+ self.assertEqual(audioop.tostereo(data1, w, 0, 0), b'\0' * len(data2))
+ for k in range(w):
+ data2[k+w::2*w] = data1[k::w]
+ self.assertEqual(audioop.tostereo(data1, w, 1, 1), data2)
def test_findfactor(self):
- self.assertEqual(audioop.findfactor(data[1], data[1]), 1.0)
+ self.assertEqual(audioop.findfactor(datas[2], datas[2]), 1.0)
+ self.assertEqual(audioop.findfactor(b'\0' * len(datas[2]), datas[2]),
+ 0.0)
def test_findfit(self):
- self.assertEqual(audioop.findfit(data[1], data[1]), (0, 1.0))
+ self.assertEqual(audioop.findfit(datas[2], datas[2]), (0, 1.0))
+ self.assertEqual(audioop.findfit(datas[2], packs[2](1, 2, 0)),
+ (1, 8038.8))
+ self.assertEqual(audioop.findfit(datas[2][:-2] * 5 + datas[2], datas[2]),
+ (30, 1.0))
def test_findmax(self):
- self.assertEqual(audioop.findmax(data[1], 1), 2)
+ self.assertEqual(audioop.findmax(datas[2], 1), 5)
def test_getsample(self):
- for i in range(3):
- self.assertEqual(audioop.getsample(data[0], 1, i), i)
- self.assertEqual(audioop.getsample(data[1], 2, i), i)
- self.assertEqual(audioop.getsample(data[2], 4, i), i)
+ for w in 1, 2, 4:
+ data = packs[w](0, 1, -1, maxvalues[w], minvalues[w])
+ self.assertEqual(audioop.getsample(data, w, 0), 0)
+ self.assertEqual(audioop.getsample(data, w, 1), 1)
+ self.assertEqual(audioop.getsample(data, w, 2), -1)
+ self.assertEqual(audioop.getsample(data, w, 3), maxvalues[w])
+ self.assertEqual(audioop.getsample(data, w, 4), minvalues[w])
def test_negativelen(self):
# from issue 3306, previously it segfaulted
@@ -220,9 +379,9 @@
self.assertRaises(audioop.error, audioop.lin2adpcm, data, size, state)
def test_wrongsize(self):
- data = b'abc'
+ data = b'abcdefgh'
state = None
- for size in (-1, 3, 5):
+ for size in (-1, 0, 3, 5, 1024):
self.assertRaises(audioop.error, audioop.ulaw2lin, data, size)
self.assertRaises(audioop.error, audioop.alaw2lin, data, size)
self.assertRaises(audioop.error, audioop.adpcm2lin, data, size, state)
diff --git a/lib-python/2.7/test/test_bigmem.py b/lib-python/2.7/test/test_bigmem.py
--- a/lib-python/2.7/test/test_bigmem.py
+++ b/lib-python/2.7/test/test_bigmem.py
@@ -118,12 +118,13 @@
except MemoryError:
pass # acceptable on 32-bit
- @precisionbigmemtest(size=_2G-1, memuse=2)
+ @precisionbigmemtest(size=_2G-1, memuse=4)
def test_decodeascii(self, size):
return self.basic_encode_test(size, 'ascii', c='A')
@precisionbigmemtest(size=_4G // 5, memuse=6+2)
def test_unicode_repr_oflw(self, size):
+ self.skipTest("test crashes - see issue #14904")
try:
s = u"\uAAAA"*size
r = repr(s)
@@ -485,7 +486,7 @@
self.assertEqual(s.count('.'), 3)
self.assertEqual(s.count('-'), size * 2)
- @bigmemtest(minsize=_2G + 10, memuse=2)
+ @bigmemtest(minsize=_2G + 10, memuse=5)
def test_repr_small(self, size):
s = '-' * size
s = repr(s)
@@ -497,7 +498,6 @@
# repr() will create a string four times as large as this 'binary
# string', but we don't want to allocate much more than twice
# size in total. (We do extra testing in test_repr_large())
- size = size // 5 * 2
s = '\x00' * size
s = repr(s)
self.assertEqual(len(s), size * 4 + 2)
@@ -541,7 +541,7 @@
self.assertEqual(len(s), size * 2)
self.assertEqual(s.count('.'), size * 2)
- @bigmemtest(minsize=_2G + 20, memuse=1)
+ @bigmemtest(minsize=_2G + 20, memuse=2)
def test_slice_and_getitem(self, size):
SUBSTR = '0123456789'
sublen = len(SUBSTR)
diff --git a/lib-python/2.7/test/test_bisect.py b/lib-python/2.7/test/test_bisect.py
--- a/lib-python/2.7/test/test_bisect.py
+++ b/lib-python/2.7/test/test_bisect.py
@@ -23,6 +23,28 @@
import bisect as c_bisect
+class Range(object):
+ """A trivial xrange()-like object without any integer width limitations."""
+ def __init__(self, start, stop):
+ self.start = start
+ self.stop = stop
+ self.last_insert = None
+
+ def __len__(self):
+ return self.stop - self.start
+
+ def __getitem__(self, idx):
+ n = self.stop - self.start
+ if idx < 0:
+ idx += n
+ if idx >= n:
+ raise IndexError(idx)
+ return self.start + idx
+
+ def insert(self, idx, item):
+ self.last_insert = idx, item
+
+
class TestBisect(unittest.TestCase):
module = None
@@ -122,6 +144,35 @@
self.assertRaises(ValueError, mod.insort_left, [1, 2, 3], 5, -1, 3),
self.assertRaises(ValueError, mod.insort_right, [1, 2, 3], 5, -1, 3),
+ def test_large_range(self):
+ # Issue 13496
+ mod = self.module
+ n = sys.maxsize
+ try:
+ data = xrange(n-1)
+ except OverflowError:
+ self.skipTest("can't create a xrange() object of size `sys.maxsize`")
+ self.assertEqual(mod.bisect_left(data, n-3), n-3)
+ self.assertEqual(mod.bisect_right(data, n-3), n-2)
+ self.assertEqual(mod.bisect_left(data, n-3, n-10, n), n-3)
+ self.assertEqual(mod.bisect_right(data, n-3, n-10, n), n-2)
+
+ def test_large_pyrange(self):
+ # Same as above, but without C-imposed limits on range() parameters
+ mod = self.module
+ n = sys.maxsize
+ data = Range(0, n-1)
+ self.assertEqual(mod.bisect_left(data, n-3), n-3)
+ self.assertEqual(mod.bisect_right(data, n-3), n-2)
+ self.assertEqual(mod.bisect_left(data, n-3, n-10, n), n-3)
+ self.assertEqual(mod.bisect_right(data, n-3, n-10, n), n-2)
+ x = n - 100
+ mod.insort_left(data, x, x - 50, x + 50)
+ self.assertEqual(data.last_insert, (x, x))
+ x = n - 200
+ mod.insort_right(data, x, x - 50, x + 50)
+ self.assertEqual(data.last_insert, (x + 1, x))
+
def test_random(self, n=25):
from random import randrange
for i in xrange(n):
@@ -191,7 +242,7 @@
else:
f = self.module.insort_right
f(insorted, digit)
- self.assertEqual(sorted(insorted), insorted)
+ self.assertEqual(sorted(insorted), insorted)
def test_backcompatibility(self):
self.assertEqual(self.module.insort, self.module.insort_right)
diff --git a/lib-python/2.7/test/test_builtin.py b/lib-python/2.7/test/test_builtin.py
--- a/lib-python/2.7/test/test_builtin.py
+++ b/lib-python/2.7/test/test_builtin.py
@@ -110,6 +110,7 @@
self.assertRaises(TypeError, all) # No args
self.assertRaises(TypeError, all, [2, 4, 6], []) # Too many args
self.assertEqual(all([]), True) # Empty iterator
+ self.assertEqual(all([0, TestFailingBool()]), False)# Short-circuit
S = [50, 60]
self.assertEqual(all(x > 42 for x in S), True)
S = [50, 40, 60]
@@ -119,11 +120,12 @@
self.assertEqual(any([None, None, None]), False)
self.assertEqual(any([None, 4, None]), True)
self.assertRaises(RuntimeError, any, [None, TestFailingBool(), 6])
- self.assertRaises(RuntimeError, all, TestFailingIter())
+ self.assertRaises(RuntimeError, any, TestFailingIter())
self.assertRaises(TypeError, any, 10) # Non-iterable
self.assertRaises(TypeError, any) # No args
self.assertRaises(TypeError, any, [2, 4, 6], []) # Too many args
self.assertEqual(any([]), False) # Empty iterator
+ self.assertEqual(any([1, TestFailingBool()]), True) # Short-circuit
S = [40, 60, 30]
self.assertEqual(any(x > 42 for x in S), True)
S = [10, 20, 30]
@@ -680,6 +682,8 @@
# Test input() later, together with raw_input
+ # test_int(): see test_int.py for int() tests.
+
def test_intern(self):
self.assertRaises(TypeError, intern)
# This fails if the test is run twice with a constant string,
diff --git a/lib-python/2.7/test/test_bytes.py b/lib-python/2.7/test/test_bytes.py
--- a/lib-python/2.7/test/test_bytes.py
+++ b/lib-python/2.7/test/test_bytes.py
@@ -635,6 +635,26 @@
b[3:0] = [42, 42, 42]
self.assertEqual(b, bytearray([0, 1, 2, 42, 42, 42, 3, 4, 5, 6, 7, 8, 9]))
+ b[3:] = b'foo'
+ self.assertEqual(b, bytearray([0, 1, 2, 102, 111, 111]))
+
+ b[:3] = memoryview(b'foo')
+ self.assertEqual(b, bytearray([102, 111, 111, 102, 111, 111]))
+
+ b[3:4] = []
+ self.assertEqual(b, bytearray([102, 111, 111, 111, 111]))
+
+ b[1:] = list(b'uuuu') # this works only on Python2
+ self.assertEqual(b, bytearray([102, 117, 117, 117, 117]))
+
+ for elem in [5, -5, 0, long(10e20), u'str', 2.3, [u'a', u'b'], [[]]]:
+ with self.assertRaises(TypeError):
+ b[3:4] = elem
+
+ for elem in [[254, 255, 256], [-256, 9000]]:
+ with self.assertRaises(ValueError):
+ b[3:4] = elem
+
def test_extended_set_del_slice(self):
indices = (0, None, 1, 3, 19, 300, 1<<333, -1, -2, -31, -300)
for start in indices:
@@ -905,6 +925,7 @@
self.assertEqual(bytes(b"abc") < b"ab", False)
self.assertEqual(bytes(b"abc") <= b"ab", False)
+ @test.test_support.requires_docstrings
def test_doc(self):
self.assertIsNotNone(bytearray.__doc__)
self.assertTrue(bytearray.__doc__.startswith("bytearray("), bytearray.__doc__)
diff --git a/lib-python/2.7/test/test_bz2.py b/lib-python/2.7/test/test_bz2.py
--- a/lib-python/2.7/test/test_bz2.py
+++ b/lib-python/2.7/test/test_bz2.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
from test import test_support
-from test.test_support import TESTFN, import_module
+from test.test_support import TESTFN, _4G, bigmemtest, import_module, findfile
import unittest
from cStringIO import StringIO
@@ -23,6 +23,10 @@
TEXT = 'root:x:0:0:root:/root:/bin/bash\nbin:x:1:1:bin:/bin:\ndaemon:x:2:2:daemon:/sbin:\nadm:x:3:4:adm:/var/adm:\nlp:x:4:7:lp:/var/spool/lpd:\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/spool/mail:\nnews:x:9:13:news:/var/spool/news:\nuucp:x:10:14:uucp:/var/spool/uucp:\noperator:x:11:0:operator:/root:\ngames:x:12:100:games:/usr/games:\ngopher:x:13:30:gopher:/usr/lib/gopher-data:\nftp:x:14:50:FTP User:/var/ftp:/bin/bash\nnobody:x:65534:65534:Nobody:/home:\npostfix:x:100:101:postfix:/var/spool/postfix:\nniemeyer:x:500:500::/home/niemeyer:/bin/bash\npostgres:x:101:102:PostgreSQL Server:/var/lib/pgsql:/bin/bash\nmysql:x:102:103:MySQL server:/var/lib/mysql:/bin/bash\nwww:x:103:104::/var/www:/bin/false\n'
DATA = 'BZh91AY&SY.\xc8N\x18\x00\x01>_\x80\x00\x10@\x02\xff\xf0\x01\x07n\x00?\xe7\xff\xe00\x01\x99\xaa\x00\xc0\x03F\x86\x8c#&\x83F\x9a\x03\x06\xa6\xd0\xa6\x93M\x0fQ\xa7\xa8\x06\x804hh\x12$\x11\xa4i4\xf14S\xd2<Q\xb5\x0fH\xd3\xd4\xdd\xd5\x87\xbb\xf8\x94\r\x8f\xafI\x12\xe1\xc9\xf8/E\x00pu\x89\x12]\xc9\xbbDL\nQ\x0e\t1\x12\xdf\xa0\xc0\x97\xac2O9\x89\x13\x94\x0e\x1c7\x0ed\x95I\x0c\xaaJ\xa4\x18L\x10\x05#\x9c\xaf\xba\xbc/\x97\x8a#C\xc8\xe1\x8cW\xf9\xe2\xd0\xd6M\xa7\x8bXa<e\x84t\xcbL\xb3\xa7\xd9\xcd\xd1\xcb\x84.\xaf\xb3\xab\xab\xad`n}\xa0lh\tE,\x8eZ\x15\x17VH>\x88\xe5\xcd9gd6\x0b\n\xe9\x9b\xd5\x8a\x99\xf7\x08.K\x8ev\xfb\xf7xw\xbb\xdf\xa1\x92\xf1\xdd|/";\xa2\xba\x9f\xd5\xb1#A\xb6\xf6\xb3o\xc9\xc5y\\\xebO\xe7\x85\x9a\xbc\xb6f8\x952\xd5\xd7"%\x89>V,\xf7\xa6z\xe2\x9f\xa3\xdf\x11\x11"\xd6E)I\xa9\x13^\xca\xf3r\xd0\x03U\x922\xf26\xec\xb6\xed\x8b\xc3U\x13\x9d\xc5\x170\xa4\xfa^\x92\xacDF\x8a\x97\xd6\x19\xfe\xdd\xb8\xbd\x1a\x9a\x19\xa3\x80ankR\x8b\xe5\xd83]\xa9\xc6\x08\x82f\xf6\xb9"6l$\xb8j@\xc0\x8a\xb0l1..\xbak\x83ls\x15\xbc\xf4\xc1\x13\xbe\xf8E\xb8\x9d\r\xa8\x9dk\x84\xd3n\xfa\xacQ\x07\xb1%y\xaav\xb4\x08\xe0z\x1b\x16\xf5\x04\xe9\xcc\xb9\x08z\x1en7.G\xfc]\xc9\x14\xe1B@\xbb!8`'
DATA_CRLF = 'BZh91AY&SY\xaez\xbbN\x00\x01H\xdf\x80\x00\x12@\x02\xff\xf0\x01\x07n\x00?\xe7\xff\xe0@\x01\xbc\xc6`\x86*\x8d=M\xa9\x9a\x86\xd0L@\x0fI\xa6!\xa1\x13\xc8\x88jdi\x8d@\x03@\x1a\x1a\x0c\x0c\x83 \x00\xc4h2\x19\x01\x82D\x84e\t\xe8\x99\x89\x19\x1ah\x00\r\x1a\x11\xaf\x9b\x0fG\xf5(\x1b\x1f?\t\x12\xcf\xb5\xfc\x95E\x00ps\x89\x12^\xa4\xdd\xa2&\x05(\x87\x04\x98\x89u\xe40%\xb6\x19\'\x8c\xc4\x89\xca\x07\x0e\x1b!\x91UIFU%C\x994!DI\xd2\xfa\xf0\xf1N8W\xde\x13A\xf5\x9cr%?\x9f3;I45A\xd1\x8bT\xb1<l\xba\xcb_\xc00xY\x17r\x17\x88\x08\x08@\xa0\ry@\x10\x04$)`\xf2\xce\x89z\xb0s\xec\x9b.iW\x9d\x81\xb5-+t\x9f\x1a\'\x97dB\xf5x\xb5\xbe.[.\xd7\x0e\x81\xe7\x08\x1cN`\x88\x10\xca\x87\xc3!"\x80\x92R\xa1/\xd1\xc0\xe6mf\xac\xbd\x99\xcca\xb3\x8780>\xa4\xc7\x8d\x1a\\"\xad\xa1\xabyBg\x15\xb9l\x88\x88\x91k"\x94\xa4\xd4\x89\xae*\xa6\x0b\x10\x0c\xd6\xd4m\xe86\xec\xb5j\x8a\x86j\';\xca.\x01I\xf2\xaaJ\xe8\x88\x8cU+t3\xfb\x0c\n\xa33\x13r2\r\x16\xe0\xb3(\xbf\x1d\x83r\xe7M\xf0D\x1365\xd8\x88\xd3\xa4\x92\xcb2\x06\x04\\\xc1\xb0\xea//\xbek&\xd8\xe6+t\xe5\xa1\x13\xada\x16\xder5"w]\xa2i\xb7[\x97R \xe2IT\xcd;Z\x04dk4\xad\x8a\t\xd3\x81z\x10\xf1:^`\xab\x1f\xc5\xdc\x91N\x14$+\x9e\xae\xd3\x80'
+ EMPTY_DATA = 'BZh9\x17rE8P\x90\x00\x00\x00\x00'
+
+ with open(findfile("testbz2_bigmem.bz2"), "rb") as f:
+ DATA_BIGMEM = f.read()
if has_cmdline_bunzip2:
def decompress(self, data):
@@ -43,6 +47,7 @@
def decompress(self, data):
return bz2.decompress(data)
+
class BZ2FileTest(BaseTest):
"Test BZ2File type miscellaneous methods."
@@ -323,6 +328,24 @@
self.assertRaises(ValueError, f.readline)
self.assertRaises(ValueError, f.readlines)
+ def test_read_truncated(self):
+ # Drop the eos_magic field (6 bytes) and CRC (4 bytes).
+ truncated = self.DATA[:-10]
+ with open(self.filename, 'wb') as f:
+ f.write(truncated)
+ with BZ2File(self.filename) as f:
+ self.assertRaises(EOFError, f.read)
+ with BZ2File(self.filename) as f:
+ self.assertEqual(f.read(len(self.TEXT)), self.TEXT)
+ self.assertRaises(EOFError, f.read, 1)
+ # Incomplete 4-byte file header, and block header of at least 146 bits.
+ for i in range(22):
+ with open(self.filename, 'wb') as f:
+ f.write(truncated[:i])
+ with BZ2File(self.filename) as f:
+ self.assertRaises(EOFError, f.read, 1)
+
+
class BZ2CompressorTest(BaseTest):
def testCompress(self):
# "Test BZ2Compressor.compress()/flush()"
@@ -332,6 +355,13 @@
data += bz2c.flush()
self.assertEqual(self.decompress(data), self.TEXT)
+ def testCompressEmptyString(self):
+ # "Test BZ2Compressor.compress()/flush() of empty string"
+ bz2c = BZ2Compressor()
+ data = bz2c.compress('')
+ data += bz2c.flush()
+ self.assertEqual(data, self.EMPTY_DATA)
+
def testCompressChunks10(self):
# "Test BZ2Compressor.compress()/flush() with chunks of 10 bytes"
bz2c = BZ2Compressor()
@@ -346,6 +376,17 @@
data += bz2c.flush()
self.assertEqual(self.decompress(data), self.TEXT)
+ @bigmemtest(_4G, memuse=1.25)
+ def testBigmem(self, size):
+ text = "a" * size
+ bz2c = bz2.BZ2Compressor()
+ data = bz2c.compress(text) + bz2c.flush()
+ del text
+ text = self.decompress(data)
+ self.assertEqual(len(text), size)
+ self.assertEqual(text.strip("a"), "")
+
+
class BZ2DecompressorTest(BaseTest):
def test_Constructor(self):
self.assertRaises(TypeError, BZ2Decompressor, 42)
@@ -383,6 +424,16 @@
bz2d = BZ2Decompressor()
text = bz2d.decompress(self.DATA)
self.assertRaises(EOFError, bz2d.decompress, "anything")
+ self.assertRaises(EOFError, bz2d.decompress, "")
+
+ @bigmemtest(_4G, memuse=1.25)
+ def testBigmem(self, size):
+ # Issue #14398: decompression fails when output data is >=2GB.
+ if size < _4G:
+ self.skipTest("Test needs 5GB of memory to run.")
+ text = bz2.BZ2Decompressor().decompress(self.DATA_BIGMEM)
+ self.assertEqual(len(text), _4G)
+ self.assertEqual(text.strip("\0"), "")
class FuncTest(BaseTest):
@@ -393,6 +444,11 @@
data = bz2.compress(self.TEXT)
self.assertEqual(self.decompress(data), self.TEXT)
+ def testCompressEmptyString(self):
+ # "Test compress() of empty string"
+ text = bz2.compress('')
+ self.assertEqual(text, self.EMPTY_DATA)
+
def testDecompress(self):
# "Test decompress() function"
text = bz2.decompress(self.DATA)
@@ -403,10 +459,33 @@
text = bz2.decompress("")
self.assertEqual(text, "")
+ def testDecompressToEmptyString(self):
+ # "Test decompress() of minimal bz2 data to empty string"
+ text = bz2.decompress(self.EMPTY_DATA)
+ self.assertEqual(text, '')
+
def testDecompressIncomplete(self):
# "Test decompress() function with incomplete data"
self.assertRaises(ValueError, bz2.decompress, self.DATA[:-10])
+ @bigmemtest(_4G, memuse=1.25)
+ def testCompressBigmem(self, size):
+ text = "a" * size
+ data = bz2.compress(text)
+ del text
+ text = self.decompress(data)
+ self.assertEqual(len(text), size)
+ self.assertEqual(text.strip("a"), "")
+
+ @bigmemtest(_4G, memuse=1.25)
+ def testDecompressBigmem(self, size):
+ # Issue #14398: decompression fails when output data is >=2GB.
+ if size < _4G:
+ self.skipTest("Test needs 5GB of memory to run.")
+ text = bz2.decompress(self.DATA_BIGMEM)
+ self.assertEqual(len(text), _4G)
+ self.assertEqual(text.strip("\0"), "")
+
def test_main():
test_support.run_unittest(
BZ2FileTest,
diff --git a/lib-python/2.7/test/test_calendar.py b/lib-python/2.7/test/test_calendar.py
--- a/lib-python/2.7/test/test_calendar.py
+++ b/lib-python/2.7/test/test_calendar.py
@@ -3,6 +3,7 @@
from test import test_support
import locale
+import datetime
result_2004_text = """
@@ -254,13 +255,30 @@
# (it is still not thread-safe though)
old_october = calendar.TextCalendar().formatmonthname(2010, 10, 10)
try:
- calendar.LocaleTextCalendar(locale='').formatmonthname(2010, 10, 10)
+ cal = calendar.LocaleTextCalendar(locale='')
+ local_weekday = cal.formatweekday(1, 10)
+ local_month = cal.formatmonthname(2010, 10, 10)
except locale.Error:
# cannot set the system default locale -- skip rest of test
- return
- calendar.LocaleHTMLCalendar(locale='').formatmonthname(2010, 10)
+ raise unittest.SkipTest('cannot set the system default locale')
+ # should be encodable
+ local_weekday.encode('utf-8')
+ local_month.encode('utf-8')
+ self.assertEqual(len(local_weekday), 10)
+ self.assertGreaterEqual(len(local_month), 10)
+ cal = calendar.LocaleHTMLCalendar(locale='')
+ local_weekday = cal.formatweekday(1)
+ local_month = cal.formatmonthname(2010, 10)
+ # should be encodable
+ local_weekday.encode('utf-8')
+ local_month.encode('utf-8')
new_october = calendar.TextCalendar().formatmonthname(2010, 10, 10)
- self.assertEquals(old_october, new_october)
+ self.assertEqual(old_october, new_october)
+
+ def test_itermonthdates(self):
+ # ensure itermonthdates doesn't overflow after datetime.MAXYEAR
+ # see #15421
+ list(calendar.Calendar().itermonthdates(datetime.MAXYEAR, 12))
class MonthCalendarTestCase(unittest.TestCase):
diff --git a/lib-python/2.7/test/test_capi.py b/lib-python/2.7/test/test_capi.py
--- a/lib-python/2.7/test/test_capi.py
+++ b/lib-python/2.7/test/test_capi.py
@@ -8,8 +8,10 @@
import unittest
from test import test_support
try:
+ import thread
import threading
except ImportError:
+ thread = None
threading = None
import _testcapi
@@ -96,8 +98,32 @@
self.pendingcalls_wait(l, n)
+ at unittest.skipUnless(threading and thread, 'Threading required for this test.')
+class TestThreadState(unittest.TestCase):
+
+ @test_support.reap_threads
+ def test_thread_state(self):
+ # some extra thread-state tests driven via _testcapi
+ def target():
+ idents = []
+
+ def callback():
+ idents.append(thread.get_ident())
+
+ _testcapi._test_thread_state(callback)
+ a = b = callback
+ time.sleep(1)
+ # Check our main thread is in the list exactly 3 times.
+ self.assertEqual(idents.count(thread.get_ident()), 3,
+ "Couldn't find main thread correctly in the list")
+
+ target()
+ t = threading.Thread(target=target)
+ t.start()
+ t.join()
+
+
def test_main():
-
for name in dir(_testcapi):
if name.startswith('test_'):
test = getattr(_testcapi, name)
@@ -108,33 +134,7 @@
except _testcapi.error:
raise test_support.TestFailed, sys.exc_info()[1]
- # some extra thread-state tests driven via _testcapi
- def TestThreadState():
- if test_support.verbose:
- print "auto-thread-state"
-
- idents = []
-
- def callback():
- idents.append(thread.get_ident())
-
- _testcapi._test_thread_state(callback)
- a = b = callback
- time.sleep(1)
- # Check our main thread is in the list exactly 3 times.
- if idents.count(thread.get_ident()) != 3:
- raise test_support.TestFailed, \
- "Couldn't find main thread correctly in the list"
-
- if threading:
- import thread
- import time
- TestThreadState()
- t=threading.Thread(target=TestThreadState)
- t.start()
- t.join()
-
- test_support.run_unittest(TestPendingCalls)
+ test_support.run_unittest(TestPendingCalls, TestThreadState)
if __name__ == "__main__":
test_main()
diff --git a/lib-python/2.7/test/test_cmd.py b/lib-python/2.7/test/test_cmd.py
--- a/lib-python/2.7/test/test_cmd.py
+++ b/lib-python/2.7/test/test_cmd.py
@@ -84,11 +84,11 @@
<BLANKLINE>
Documented commands (type help <topic>):
========================================
- add
+ add help
<BLANKLINE>
Undocumented commands:
======================
- exit help shell
+ exit shell
<BLANKLINE>
Test for the function print_topics():
@@ -125,11 +125,11 @@
<BLANKLINE>
Documented commands (type help <topic>):
========================================
- add
+ add help
<BLANKLINE>
Undocumented commands:
======================
- exit help shell
+ exit shell
<BLANKLINE>
help text for add
Hello from postloop
diff --git a/lib-python/2.7/test/test_cmd_line.py b/lib-python/2.7/test/test_cmd_line.py
--- a/lib-python/2.7/test/test_cmd_line.py
+++ b/lib-python/2.7/test/test_cmd_line.py
@@ -2,9 +2,13 @@
# All tests are executed with environment variables ignored
# See test_cmd_line_script.py for testing of script execution
-import test.test_support, unittest
+import test.test_support
import sys
-from test.script_helper import spawn_python, kill_python, python_exit_code
+import unittest
+from test.script_helper import (
+ assert_python_ok, assert_python_failure, spawn_python, kill_python,
+ python_exit_code
+)
class CmdLineTest(unittest.TestCase):
@@ -101,6 +105,36 @@
data = self.start_python('-R', '-c', code)
self.assertTrue('hash_randomization=1' in data)
+ def test_del___main__(self):
+ # Issue #15001: PyRun_SimpleFileExFlags() did crash because it kept a
+ # borrowed reference to the dict of __main__ module and later modify
+ # the dict whereas the module was destroyed
+ filename = test.test_support.TESTFN
+ self.addCleanup(test.test_support.unlink, filename)
+ with open(filename, "w") as script:
+ print >>script, "import sys"
+ print >>script, "del sys.modules['__main__']"
+ assert_python_ok(filename)
+
+ def test_unknown_options(self):
+ rc, out, err = assert_python_failure('-E', '-z')
+ self.assertIn(b'Unknown option: -z', err)
+ self.assertEqual(err.splitlines().count(b'Unknown option: -z'), 1)
+ self.assertEqual(b'', out)
+ # Add "without='-E'" to prevent _assert_python to append -E
+ # to env_vars and change the output of stderr
+ rc, out, err = assert_python_failure('-z', without='-E')
+ self.assertIn(b'Unknown option: -z', err)
+ self.assertEqual(err.splitlines().count(b'Unknown option: -z'), 1)
+ self.assertEqual(b'', out)
+ rc, out, err = assert_python_failure('-a', '-z', without='-E')
+ self.assertIn(b'Unknown option: -a', err)
+ # only the first unknown option is reported
+ self.assertNotIn(b'Unknown option: -z', err)
+ self.assertEqual(err.splitlines().count(b'Unknown option: -a'), 1)
+ self.assertEqual(b'', out)
+
+
def test_main():
test.test_support.run_unittest(CmdLineTest)
test.test_support.reap_children()
diff --git a/lib-python/2.7/test/test_cmd_line_script.py b/lib-python/2.7/test/test_cmd_line_script.py
--- a/lib-python/2.7/test/test_cmd_line_script.py
+++ b/lib-python/2.7/test/test_cmd_line_script.py
@@ -6,11 +6,14 @@
import test.test_support
from test.script_helper import (run_python,
temp_dir, make_script, compile_script,
- make_pkg, make_zip_script, make_zip_pkg)
+ assert_python_failure, make_pkg,
+ make_zip_script, make_zip_pkg)
verbose = test.test_support.verbose
+example_args = ['test1', 'test2', 'test3']
+
test_source = """\
# Script may be run with optimisation enabled, so don't rely on assert
# statements being executed
@@ -204,6 +207,19 @@
launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg')
self._check_import_error(launch_name, msg)
+ def test_dash_m_error_code_is_one(self):
+ # If a module is invoked with the -m command line flag
+ # and results in an error that the return code to the
+ # shell is '1'
+ with temp_dir() as script_dir:
+ pkg_dir = os.path.join(script_dir, 'test_pkg')
+ make_pkg(pkg_dir)
+ script_name = _make_test_script(pkg_dir, 'other', "if __name__ == '__main__': raise ValueError")
+ rc, out, err = assert_python_failure('-m', 'test_pkg.other', *example_args)
+ if verbose > 1:
+ print(out)
+ self.assertEqual(rc, 1)
+
def test_main():
test.test_support.run_unittest(CmdLineTest)
diff --git a/lib-python/2.7/test/test_codeccallbacks.py b/lib-python/2.7/test/test_codeccallbacks.py
--- a/lib-python/2.7/test/test_codeccallbacks.py
+++ b/lib-python/2.7/test/test_codeccallbacks.py
@@ -262,12 +262,12 @@
self.assertEqual(
"\\u3042\u3xxx".decode("unicode-escape", "test.handler1"),
- u"\u3042[<92><117><51><120>]xx"
+ u"\u3042[<92><117><51>]xxx"
)
self.assertEqual(
"\\u3042\u3xx".decode("unicode-escape", "test.handler1"),
- u"\u3042[<92><117><51><120><120>]"
+ u"\u3042[<92><117><51>]xx"
)
self.assertEqual(
@@ -717,7 +717,7 @@
raise ValueError
self.assertRaises(UnicodeError, codecs.charmap_decode, "\xff", "strict", {0xff: None})
self.assertRaises(ValueError, codecs.charmap_decode, "\xff", "strict", D())
- self.assertRaises(TypeError, codecs.charmap_decode, "\xff", "strict", {0xff: sys.maxunicode+1})
+ self.assertRaises(TypeError, codecs.charmap_decode, "\xff", "strict", {0xff: 0x110000})
def test_encodehelper(self):
# enhance coverage of:
diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py
--- a/lib-python/2.7/test/test_codecs.py
+++ b/lib-python/2.7/test/test_codecs.py
@@ -4,6 +4,11 @@
import locale
import sys, StringIO, _testcapi
+def coding_checker(self, coder):
+ def check(input, expect):
+ self.assertEqual(coder(input), (expect, len(input)))
+ return check
+
class Queue(object):
"""
queue: write bytes at one end, read bytes from the other end
@@ -281,7 +286,7 @@
def test_partial(self):
self.check_partial(
- u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
[
u"", # first byte of BOM read
u"", # second byte of BOM read
@@ -303,6 +308,10 @@
u"\x00\xff\u0100",
u"\x00\xff\u0100",
u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
]
)
@@ -331,7 +340,7 @@
def test_partial(self):
self.check_partial(
- u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
[
u"",
u"",
@@ -349,6 +358,10 @@
u"\x00\xff\u0100",
u"\x00\xff\u0100",
u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
]
)
@@ -371,7 +384,7 @@
def test_partial(self):
self.check_partial(
- u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
[
u"",
u"",
@@ -389,6 +402,10 @@
u"\x00\xff\u0100",
u"\x00\xff\u0100",
u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
]
)
@@ -439,7 +456,7 @@
def test_partial(self):
self.check_partial(
- u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
[
u"", # first byte of BOM read
u"", # second byte of BOM read => byteorder known
@@ -451,6 +468,10 @@
u"\x00\xff\u0100",
u"\x00\xff\u0100",
u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
]
)
@@ -481,7 +502,7 @@
def test_partial(self):
self.check_partial(
- u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
[
u"",
u"\x00",
@@ -491,18 +512,34 @@
u"\x00\xff\u0100",
u"\x00\xff\u0100",
u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
]
)
def test_errors(self):
- self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, "\xff", "strict", True)
+ tests = [
+ (b'\xff', u'\ufffd'),
+ (b'A\x00Z', u'A\ufffd'),
+ (b'A\x00B\x00C\x00D\x00Z', u'ABCD\ufffd'),
+ (b'\x00\xd8', u'\ufffd'),
+ (b'\x00\xd8A', u'\ufffd'),
+ (b'\x00\xd8A\x00', u'\ufffdA'),
+ (b'\x00\xdcA\x00', u'\ufffdA'),
+ ]
+ for raw, expected in tests:
+ self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode,
+ raw, 'strict', True)
+ self.assertEqual(raw.decode('utf-16le', 'replace'), expected)
class UTF16BETest(ReadTest):
encoding = "utf-16-be"
def test_partial(self):
self.check_partial(
- u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
[
u"",
u"\x00",
@@ -512,18 +549,34 @@
u"\x00\xff\u0100",
u"\x00\xff\u0100",
u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff",
+ u"\x00\xff\u0100\uffff\U00010000",
]
)
def test_errors(self):
- self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, "\xff", "strict", True)
+ tests = [
+ (b'\xff', u'\ufffd'),
+ (b'\x00A\xff', u'A\ufffd'),
+ (b'\x00A\x00B\x00C\x00DZ', u'ABCD\ufffd'),
+ (b'\xd8\x00', u'\ufffd'),
+ (b'\xd8\x00\xdc', u'\ufffd'),
+ (b'\xd8\x00\x00A', u'\ufffdA'),
+ (b'\xdc\x00\x00A', u'\ufffdA'),
+ ]
+ for raw, expected in tests:
+ self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode,
+ raw, 'strict', True)
+ self.assertEqual(raw.decode('utf-16be', 'replace'), expected)
class UTF8Test(ReadTest):
encoding = "utf-8"
def test_partial(self):
self.check_partial(
- u"\x00\xff\u07ff\u0800\uffff",
+ u"\x00\xff\u07ff\u0800\uffff\U00010000",
[
u"\x00",
u"\x00",
@@ -536,6 +589,10 @@
u"\x00\xff\u07ff\u0800",
u"\x00\xff\u07ff\u0800",
u"\x00\xff\u07ff\u0800\uffff",
+ u"\x00\xff\u07ff\u0800\uffff",
+ u"\x00\xff\u07ff\u0800\uffff",
+ u"\x00\xff\u07ff\u0800\uffff",
+ u"\x00\xff\u07ff\u0800\uffff\U00010000",
]
)
@@ -595,7 +652,7 @@
def test_partial(self):
self.check_partial(
- u"\ufeff\x00\xff\u07ff\u0800\uffff",
+ u"\ufeff\x00\xff\u07ff\u0800\uffff\U00010000",
[
u"",
u"",
@@ -614,6 +671,10 @@
u"\ufeff\x00\xff\u07ff\u0800",
u"\ufeff\x00\xff\u07ff\u0800",
u"\ufeff\x00\xff\u07ff\u0800\uffff",
+ u"\ufeff\x00\xff\u07ff\u0800\uffff",
+ u"\ufeff\x00\xff\u07ff\u0800\uffff",
+ u"\ufeff\x00\xff\u07ff\u0800\uffff",
+ u"\ufeff\x00\xff\u07ff\u0800\uffff\U00010000",
]
)
@@ -674,6 +735,54 @@
def test_empty(self):
self.assertEqual(codecs.escape_decode(""), ("", 0))
+ def test_raw(self):
+ decode = codecs.escape_decode
+ for b in range(256):
+ b = chr(b)
+ if b != '\\':
+ self.assertEqual(decode(b + '0'), (b + '0', 2))
+
+ def test_escape(self):
+ decode = codecs.escape_decode
+ check = coding_checker(self, decode)
+ check(b"[\\\n]", b"[]")
+ check(br'[\"]', b'["]')
+ check(br"[\']", b"[']")
+ check(br"[\\]", br"[\]")
+ check(br"[\a]", b"[\x07]")
+ check(br"[\b]", b"[\x08]")
+ check(br"[\t]", b"[\x09]")
+ check(br"[\n]", b"[\x0a]")
+ check(br"[\v]", b"[\x0b]")
+ check(br"[\f]", b"[\x0c]")
+ check(br"[\r]", b"[\x0d]")
+ check(br"[\7]", b"[\x07]")
+ check(br"[\8]", br"[\8]")
+ check(br"[\78]", b"[\x078]")
+ check(br"[\41]", b"[!]")
+ check(br"[\418]", b"[!8]")
+ check(br"[\101]", b"[A]")
+ check(br"[\1010]", b"[A0]")
+ check(br"[\501]", b"[A]")
+ check(br"[\x41]", b"[A]")
+ check(br"[\X41]", br"[\X41]")
+ check(br"[\x410]", b"[A0]")
+ for b in range(256):
+ b = chr(b)
+ if b not in '\n"\'\\abtnvfr01234567x':
+ check('\\' + b, '\\' + b)
+
+ def test_errors(self):
+ decode = codecs.escape_decode
+ self.assertRaises(ValueError, decode, br"\x")
+ self.assertRaises(ValueError, decode, br"[\x]")
+ self.assertEqual(decode(br"[\x]\x", "ignore"), (b"[]", 6))
+ self.assertEqual(decode(br"[\x]\x", "replace"), (b"[?]?", 6))
+ self.assertRaises(ValueError, decode, br"\x0")
+ self.assertRaises(ValueError, decode, br"[\x0]")
+ self.assertEqual(decode(br"[\x0]\x0", "ignore"), (b"[]", 8))
+ self.assertEqual(decode(br"[\x0]\x0", "replace"), (b"[?]?", 8))
+
class RecodingTest(unittest.TestCase):
def test_recoding(self):
f = StringIO.StringIO()
@@ -1495,6 +1604,14 @@
(u"abc", 3)
)
+ self.assertRaises(UnicodeDecodeError,
+ codecs.charmap_decode, b"\x00\x01\x02", "strict", u"ab"
+ )
+
+ self.assertRaises(UnicodeDecodeError,
+ codecs.charmap_decode, "\x00\x01\x02", "strict", u"ab\ufffe"
+ )
+
self.assertEqual(
codecs.charmap_decode("\x00\x01\x02", "replace", u"ab"),
(u"ab\ufffd", 3)
@@ -1521,6 +1638,149 @@
(u"", len(allbytes))
)
+ def test_decode_with_int2str_map(self):
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "strict",
+ {0: u'a', 1: u'b', 2: u'c'}),
+ (u"abc", 3)
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "strict",
+ {0: u'Aa', 1: u'Bb', 2: u'Cc'}),
+ (u"AaBbCc", 3)
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "strict",
+ {0: u'\U0010FFFF', 1: u'b', 2: u'c'}),
+ (u"\U0010FFFFbc", 3)
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "strict",
+ {0: u'a', 1: u'b', 2: u''}),
+ (u"ab", 3)
+ )
+
+ self.assertRaises(UnicodeDecodeError,
+ codecs.charmap_decode, "\x00\x01\x02", "strict",
+ {0: u'a', 1: u'b'}
+ )
+
+ self.assertRaises(UnicodeDecodeError,
+ codecs.charmap_decode, "\x00\x01\x02", "strict",
+ {0: u'a', 1: u'b', 2: None}
+ )
+
+ # Issue #14850
+ self.assertRaises(UnicodeDecodeError,
+ codecs.charmap_decode, "\x00\x01\x02", "strict",
+ {0: u'a', 1: u'b', 2: u'\ufffe'}
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "replace",
+ {0: u'a', 1: u'b'}),
+ (u"ab\ufffd", 3)
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "replace",
+ {0: u'a', 1: u'b', 2: None}),
+ (u"ab\ufffd", 3)
+ )
+
+ # Issue #14850
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "replace",
+ {0: u'a', 1: u'b', 2: u'\ufffe'}),
+ (u"ab\ufffd", 3)
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "ignore",
+ {0: u'a', 1: u'b'}),
+ (u"ab", 3)
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "ignore",
+ {0: u'a', 1: u'b', 2: None}),
+ (u"ab", 3)
+ )
+
+ # Issue #14850
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "ignore",
+ {0: u'a', 1: u'b', 2: u'\ufffe'}),
+ (u"ab", 3)
+ )
+
+ allbytes = "".join(chr(i) for i in xrange(256))
+ self.assertEqual(
+ codecs.charmap_decode(allbytes, "ignore", {}),
+ (u"", len(allbytes))
+ )
+
+ def test_decode_with_int2int_map(self):
+ a = ord(u'a')
+ b = ord(u'b')
+ c = ord(u'c')
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "strict",
+ {0: a, 1: b, 2: c}),
+ (u"abc", 3)
+ )
+
+ # Issue #15379
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "strict",
+ {0: 0x10FFFF, 1: b, 2: c}),
+ (u"\U0010FFFFbc", 3)
+ )
+
+ self.assertRaises(TypeError,
+ codecs.charmap_decode, "\x00\x01\x02", "strict",
+ {0: 0x110000, 1: b, 2: c}
+ )
+
+ self.assertRaises(UnicodeDecodeError,
+ codecs.charmap_decode, "\x00\x01\x02", "strict",
+ {0: a, 1: b},
+ )
+
+ self.assertRaises(UnicodeDecodeError,
+ codecs.charmap_decode, "\x00\x01\x02", "strict",
+ {0: a, 1: b, 2: 0xFFFE},
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "replace",
+ {0: a, 1: b}),
+ (u"ab\ufffd", 3)
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "replace",
+ {0: a, 1: b, 2: 0xFFFE}),
+ (u"ab\ufffd", 3)
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "ignore",
+ {0: a, 1: b}),
+ (u"ab", 3)
+ )
+
+ self.assertEqual(
+ codecs.charmap_decode("\x00\x01\x02", "ignore",
+ {0: a, 1: b, 2: 0xFFFE}),
+ (u"ab", 3)
+ )
+
+
class WithStmtTest(unittest.TestCase):
def test_encodedfile(self):
f = StringIO.StringIO("\xc3\xbc")
@@ -1535,6 +1795,134 @@
self.assertEqual(srw.read(), u"\xfc")
+class UnicodeEscapeTest(unittest.TestCase):
+ def test_empty(self):
+ self.assertEqual(codecs.unicode_escape_encode(u""), ("", 0))
+ self.assertEqual(codecs.unicode_escape_decode(""), (u"", 0))
+
+ def test_raw_encode(self):
+ encode = codecs.unicode_escape_encode
+ for b in range(32, 127):
+ if b != ord('\\'):
+ self.assertEqual(encode(unichr(b)), (chr(b), 1))
+
+ def test_raw_decode(self):
+ decode = codecs.unicode_escape_decode
+ for b in range(256):
+ if b != ord('\\'):
+ self.assertEqual(decode(chr(b) + '0'), (unichr(b) + u'0', 2))
+
+ def test_escape_encode(self):
+ encode = codecs.unicode_escape_encode
+ check = coding_checker(self, encode)
+ check(u'\t', r'\t')
+ check(u'\n', r'\n')
+ check(u'\r', r'\r')
+ check(u'\\', r'\\')
+ for b in range(32):
+ if chr(b) not in '\t\n\r':
+ check(unichr(b), '\\x%02x' % b)
+ for b in range(127, 256):
+ check(unichr(b), '\\x%02x' % b)
+ check(u'\u20ac', r'\u20ac')
+ check(u'\U0001d120', r'\U0001d120')
+
+ def test_escape_decode(self):
+ decode = codecs.unicode_escape_decode
+ check = coding_checker(self, decode)
+ check("[\\\n]", u"[]")
+ check(r'[\"]', u'["]')
+ check(r"[\']", u"[']")
+ check(r"[\\]", ur"[\]")
+ check(r"[\a]", u"[\x07]")
+ check(r"[\b]", u"[\x08]")
+ check(r"[\t]", u"[\x09]")
+ check(r"[\n]", u"[\x0a]")
+ check(r"[\v]", u"[\x0b]")
+ check(r"[\f]", u"[\x0c]")
+ check(r"[\r]", u"[\x0d]")
+ check(r"[\7]", u"[\x07]")
+ check(r"[\8]", ur"[\8]")
+ check(r"[\78]", u"[\x078]")
+ check(r"[\41]", u"[!]")
+ check(r"[\418]", u"[!8]")
+ check(r"[\101]", u"[A]")
+ check(r"[\1010]", u"[A0]")
+ check(r"[\x41]", u"[A]")
+ check(r"[\x410]", u"[A0]")
+ check(r"\u20ac", u"\u20ac")
+ check(r"\U0001d120", u"\U0001d120")
+ for b in range(256):
+ if chr(b) not in '\n"\'\\abtnvfr01234567xuUN':
+ check('\\' + chr(b), u'\\' + unichr(b))
+
+ def test_decode_errors(self):
+ decode = codecs.unicode_escape_decode
+ for c, d in ('x', 2), ('u', 4), ('U', 4):
+ for i in range(d):
+ self.assertRaises(UnicodeDecodeError, decode,
+ "\\" + c + "0"*i)
+ self.assertRaises(UnicodeDecodeError, decode,
+ "[\\" + c + "0"*i + "]")
+ data = "[\\" + c + "0"*i + "]\\" + c + "0"*i
+ self.assertEqual(decode(data, "ignore"), (u"[]", len(data)))
+ self.assertEqual(decode(data, "replace"),
+ (u"[\ufffd]\ufffd", len(data)))
+ self.assertRaises(UnicodeDecodeError, decode, r"\U00110000")
+ self.assertEqual(decode(r"\U00110000", "ignore"), (u"", 10))
+ self.assertEqual(decode(r"\U00110000", "replace"), (u"\ufffd", 10))
+
+
+class RawUnicodeEscapeTest(unittest.TestCase):
+ def test_empty(self):
+ self.assertEqual(codecs.raw_unicode_escape_encode(u""), ("", 0))
+ self.assertEqual(codecs.raw_unicode_escape_decode(""), (u"", 0))
+
+ def test_raw_encode(self):
+ encode = codecs.raw_unicode_escape_encode
+ for b in range(256):
+ self.assertEqual(encode(unichr(b)), (chr(b), 1))
+
+ def test_raw_decode(self):
+ decode = codecs.raw_unicode_escape_decode
+ for b in range(256):
+ self.assertEqual(decode(chr(b) + '0'), (unichr(b) + u'0', 2))
+
+ def test_escape_encode(self):
+ encode = codecs.raw_unicode_escape_encode
+ check = coding_checker(self, encode)
+ for b in range(256):
+ if chr(b) not in 'uU':
+ check(u'\\' + unichr(b), '\\' + chr(b))
+ check(u'\u20ac', r'\u20ac')
+ check(u'\U0001d120', r'\U0001d120')
+
+ def test_escape_decode(self):
+ decode = codecs.raw_unicode_escape_decode
+ check = coding_checker(self, decode)
+ for b in range(256):
+ if chr(b) not in 'uU':
+ check('\\' + chr(b), u'\\' + unichr(b))
+ check(r"\u20ac", u"\u20ac")
+ check(r"\U0001d120", u"\U0001d120")
+
+ def test_decode_errors(self):
+ decode = codecs.raw_unicode_escape_decode
+ for c, d in ('u', 4), ('U', 4):
+ for i in range(d):
+ self.assertRaises(UnicodeDecodeError, decode,
+ "\\" + c + "0"*i)
+ self.assertRaises(UnicodeDecodeError, decode,
+ "[\\" + c + "0"*i + "]")
+ data = "[\\" + c + "0"*i + "]\\" + c + "0"*i
+ self.assertEqual(decode(data, "ignore"), (u"[]", len(data)))
+ self.assertEqual(decode(data, "replace"),
+ (u"[\ufffd]\ufffd", len(data)))
+ self.assertRaises(UnicodeDecodeError, decode, r"\U00110000")
+ self.assertEqual(decode(r"\U00110000", "ignore"), (u"", 10))
+ self.assertEqual(decode(r"\U00110000", "replace"), (u"\ufffd", 10))
+
+
class BomTest(unittest.TestCase):
def test_seek0(self):
data = u"1234567890"
@@ -1620,6 +2008,8 @@
BasicStrTest,
CharmapTest,
WithStmtTest,
+ UnicodeEscapeTest,
+ RawUnicodeEscapeTest,
BomTest,
)
diff --git a/lib-python/2.7/test/test_codeop.py b/lib-python/2.7/test/test_codeop.py
--- a/lib-python/2.7/test/test_codeop.py
+++ b/lib-python/2.7/test/test_codeop.py
@@ -50,7 +50,7 @@
'''succeed iff str is the start of an invalid piece of code'''
try:
compile_command(str,symbol=symbol)
- self.fail("No exception thrown for invalid code")
+ self.fail("No exception raised for invalid code")
except SyntaxError:
self.assertTrue(is_syntax)
except OverflowError:
diff --git a/lib-python/2.7/test/test_compile.py b/lib-python/2.7/test/test_compile.py
--- a/lib-python/2.7/test/test_compile.py
+++ b/lib-python/2.7/test/test_compile.py
@@ -61,6 +61,34 @@
except SyntaxError:
pass
+ def test_exec_functional_style(self):
+ # Exec'ing a tuple of length 2 works.
+ g = {'b': 2}
+ exec("a = b + 1", g)
+ self.assertEqual(g['a'], 3)
+
+ # As does exec'ing a tuple of length 3.
+ l = {'b': 3}
+ g = {'b': 5, 'c': 7}
+ exec("a = b + c", g, l)
+ self.assertNotIn('a', g)
+ self.assertEqual(l['a'], 10)
+
+ # Tuples not of length 2 or 3 are invalid.
+ with self.assertRaises(TypeError):
+ exec("a = b + 1",)
+
+ with self.assertRaises(TypeError):
+ exec("a = b + 1", {}, {}, {})
+
+ # Can't mix and match the two calling forms.
+ g = {'a': 3, 'b': 4}
+ l = {}
+ with self.assertRaises(TypeError):
+ exec("a = b + 1", g) in g
+ with self.assertRaises(TypeError):
+ exec("a = b + 1", g, l) in g, l
+
def test_exec_with_general_mapping_for_locals(self):
class M:
diff --git a/lib-python/2.7/test/test_cookie.py b/lib-python/2.7/test/test_cookie.py
--- a/lib-python/2.7/test/test_cookie.py
+++ b/lib-python/2.7/test/test_cookie.py
@@ -64,13 +64,13 @@
# loading 'expires'
C = Cookie.SimpleCookie()
- C.load('Customer="W"; expires=Wed, 01-Jan-2010 00:00:00 GMT')
+ C.load('Customer="W"; expires=Wed, 01 Jan 2010 00:00:00 GMT')
self.assertEqual(C['Customer']['expires'],
- 'Wed, 01-Jan-2010 00:00:00 GMT')
+ 'Wed, 01 Jan 2010 00:00:00 GMT')
C = Cookie.SimpleCookie()
- C.load('Customer="W"; expires=Wed, 01-Jan-98 00:00:00 GMT')
+ C.load('Customer="W"; expires=Wed, 01 Jan 98 00:00:00 GMT')
self.assertEqual(C['Customer']['expires'],
- 'Wed, 01-Jan-98 00:00:00 GMT')
+ 'Wed, 01 Jan 98 00:00:00 GMT')
def test_extended_encode(self):
# Issue 9824: some browsers don't follow the standard; we now
@@ -90,9 +90,10 @@
def test_main():
run_unittest(CookieTests)
- with check_warnings(('.+Cookie class is insecure; do not use it',
- DeprecationWarning)):
- run_doctest(Cookie)
+ if Cookie.__doc__ is not None:
+ with check_warnings(('.+Cookie class is insecure; do not use it',
+ DeprecationWarning)):
+ run_doctest(Cookie)
if __name__ == '__main__':
test_main()
diff --git a/lib-python/2.7/test/test_cpickle.py b/lib-python/2.7/test/test_cpickle.py
--- a/lib-python/2.7/test/test_cpickle.py
+++ b/lib-python/2.7/test/test_cpickle.py
@@ -1,7 +1,9 @@
import cPickle, unittest
from cStringIO import StringIO
-from test.pickletester import AbstractPickleTests, AbstractPickleModuleTests
-from test.pickletester import AbstractPicklerUnpicklerObjectTests
+from test.pickletester import (AbstractPickleTests,
+ AbstractPickleModuleTests,
+ AbstractPicklerUnpicklerObjectTests,
+ BigmemPickleTests)
from test import test_support
class cPickleTests(AbstractPickleTests, AbstractPickleModuleTests):
@@ -101,6 +103,16 @@
pickler_class = cPickle.Pickler
unpickler_class = cPickle.Unpickler
+class cPickleBigmemPickleTests(BigmemPickleTests):
+
+ def dumps(self, arg, proto=0, fast=0):
+ # Ignore fast
+ return cPickle.dumps(arg, proto)
+
+ def loads(self, buf):
+ # Ignore fast
+ return cPickle.loads(buf)
+
class Node(object):
pass
@@ -133,6 +145,7 @@
cPickleFastPicklerTests,
cPickleDeepRecursive,
cPicklePicklerUnpicklerObjectTests,
+ cPickleBigmemPickleTests,
)
if __name__ == "__main__":
diff --git a/lib-python/2.7/test/test_csv.py b/lib-python/2.7/test/test_csv.py
--- a/lib-python/2.7/test/test_csv.py
+++ b/lib-python/2.7/test/test_csv.py
@@ -243,6 +243,15 @@
self.assertRaises(csv.Error, self._read_test, ['a,b\nc,d'], [])
self.assertRaises(csv.Error, self._read_test, ['a,b\r\nc,d'], [])
+ def test_read_eof(self):
+ self._read_test(['a,"'], [['a', '']])
+ self._read_test(['"a'], [['a']])
+ self._read_test(['^'], [['\n']], escapechar='^')
+ self.assertRaises(csv.Error, self._read_test, ['a,"'], [], strict=True)
+ self.assertRaises(csv.Error, self._read_test, ['"a'], [], strict=True)
+ self.assertRaises(csv.Error, self._read_test,
+ ['^'], [], escapechar='^', strict=True)
+
def test_read_escape(self):
self._read_test(['a,\\b,c'], [['a', 'b', 'c']], escapechar='\\')
self._read_test(['a,b\\,c'], [['a', 'b,c']], escapechar='\\')
diff --git a/lib-python/2.7/test/test_decimal.py b/lib-python/2.7/test/test_decimal.py
--- a/lib-python/2.7/test/test_decimal.py
+++ b/lib-python/2.7/test/test_decimal.py
@@ -1448,6 +1448,18 @@
self.assertEqual(float(d1), 66)
self.assertEqual(float(d2), 15.32)
+ def test_nan_to_float(self):
+ # Test conversions of decimal NANs to float.
+ # See http://bugs.python.org/issue15544
+ for s in ('nan', 'nan1234', '-nan', '-nan2468'):
+ f = float(Decimal(s))
+ self.assertTrue(math.isnan(f))
+
+ def test_snan_to_float(self):
+ for s in ('snan', '-snan', 'snan1357', '-snan1234'):
+ d = Decimal(s)
+ self.assertRaises(ValueError, float, d)
+
def test_eval_round_trip(self):
#with zero
diff --git a/lib-python/2.7/test/test_deque.py b/lib-python/2.7/test/test_deque.py
--- a/lib-python/2.7/test/test_deque.py
+++ b/lib-python/2.7/test/test_deque.py
@@ -6,6 +6,7 @@
import copy
import cPickle as pickle
import random
+import struct
BIG = 100000
@@ -517,6 +518,21 @@
gc.collect()
self.assertTrue(ref() is None, "Cycle was not collected")
+ check_sizeof = test_support.check_sizeof
+
+ @test_support.cpython_only
+ def test_sizeof(self):
+ BLOCKLEN = 62
+ basesize = test_support.calcobjsize('2P4PlP')
+ blocksize = struct.calcsize('2P%dP' % BLOCKLEN)
+ self.assertEqual(object.__sizeof__(deque()), basesize)
+ check = self.check_sizeof
+ check(deque(), basesize + blocksize)
+ check(deque('a'), basesize + blocksize)
+ check(deque('a' * (BLOCKLEN // 2)), basesize + blocksize)
+ check(deque('a' * (BLOCKLEN // 2 + 1)), basesize + 2 * blocksize)
+ check(deque('a' * (42 * BLOCKLEN)), basesize + 43 * blocksize)
+
class TestVariousIteratorArgs(unittest.TestCase):
def test_constructor(self):
diff --git a/lib-python/2.7/test/test_descr.py b/lib-python/2.7/test/test_descr.py
--- a/lib-python/2.7/test/test_descr.py
+++ b/lib-python/2.7/test/test_descr.py
@@ -1419,6 +1419,22 @@
self.assertEqual(x, spam.spamlist)
self.assertEqual(a, a1)
self.assertEqual(d, d1)
+ spam_cm = spam.spamlist.__dict__['classmeth']
+ x2, a2, d2 = spam_cm(spam.spamlist, *a, **d)
+ self.assertEqual(x2, spam.spamlist)
+ self.assertEqual(a2, a1)
+ self.assertEqual(d2, d1)
+ class SubSpam(spam.spamlist): pass
+ x2, a2, d2 = spam_cm(SubSpam, *a, **d)
+ self.assertEqual(x2, SubSpam)
+ self.assertEqual(a2, a1)
+ self.assertEqual(d2, d1)
+ with self.assertRaises(TypeError):
+ spam_cm()
+ with self.assertRaises(TypeError):
+ spam_cm(spam.spamlist())
+ with self.assertRaises(TypeError):
+ spam_cm(list)
def test_staticmethods(self):
# Testing static methods...
@@ -4591,7 +4607,15 @@
pass
Foo.__repr__ = Foo.__str__
foo = Foo()
- str(foo)
+ self.assertRaises(RuntimeError, str, foo)
+ self.assertRaises(RuntimeError, repr, foo)
+
+ def test_mixing_slot_wrappers(self):
+ class X(dict):
+ __setattr__ = dict.__setitem__
+ x = X()
+ x.y = 42
+ self.assertEqual(x["y"], 42)
def test_cycle_through_dict(self):
# See bug #1469629
diff --git a/lib-python/2.7/test/test_dict.py b/lib-python/2.7/test/test_dict.py
--- a/lib-python/2.7/test/test_dict.py
+++ b/lib-python/2.7/test/test_dict.py
@@ -254,6 +254,14 @@
d = dict(zip(range(6), range(6)))
self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6)))
+ class baddict3(dict):
+ def __new__(cls):
+ return d
+ d = {i : i for i in range(10)}
+ res = d.copy()
+ res.update(a=None, b=None, c=None)
+ self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res)
+
def test_copy(self):
d = {1:1, 2:2, 3:3}
self.assertEqual(d.copy(), {1:1, 2:2, 3:3})
diff --git a/lib-python/2.7/test/test_dictcomps.py b/lib-python/2.7/test/test_dictcomps.py
--- a/lib-python/2.7/test/test_dictcomps.py
+++ b/lib-python/2.7/test/test_dictcomps.py
@@ -1,54 +1,91 @@
+import unittest
-doctests = """
+from test import test_support as support
- >>> k = "old value"
- >>> { k: None for k in range(10) }
- {0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}
- >>> k
- 'old value'
+# For scope testing.
+g = "Global variable"
- >>> { k: k+10 for k in range(10) }
- {0: 10, 1: 11, 2: 12, 3: 13, 4: 14, 5: 15, 6: 16, 7: 17, 8: 18, 9: 19}
- >>> g = "Global variable"
- >>> { k: g for k in range(10) }
- {0: 'Global variable', 1: 'Global variable', 2: 'Global variable', 3: 'Global variable', 4: 'Global variable', 5: 'Global variable', 6: 'Global variable', 7: 'Global variable', 8: 'Global variable', 9: 'Global variable'}
+class DictComprehensionTest(unittest.TestCase):
- >>> { k: v for k in range(10) for v in range(10) if k == v }
- {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
+ def test_basics(self):
+ expected = {0: 10, 1: 11, 2: 12, 3: 13, 4: 14, 5: 15, 6: 16, 7: 17,
+ 8: 18, 9: 19}
+ actual = {k: k + 10 for k in range(10)}
+ self.assertEqual(actual, expected)
- >>> { k: v for v in range(10) for k in range(v*9, v*10) }
- {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4, 38: 4, 39: 4, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 54: 6, 55: 6, 56: 6, 57: 6, 58: 6, 59: 6, 63: 7, 64: 7, 65: 7, 66: 7, 67: 7, 68: 7, 69: 7, 72: 8, 73: 8, 74: 8, 75: 8, 76: 8, 77: 8, 78: 8, 79: 8, 81: 9, 82: 9, 83: 9, 84: 9, 85: 9, 86: 9, 87: 9, 88: 9, 89: 9}
+ expected = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
+ actual = {k: v for k in range(10) for v in range(10) if k == v}
+ self.assertEqual(actual, expected)
- >>> { x: y for y, x in ((1, 2), (3, 4)) } = 5 # doctest: +IGNORE_EXCEPTION_DETAIL
- Traceback (most recent call last):
- ...
- SyntaxError: ...
+ def test_scope_isolation(self):
+ k = "Local Variable"
- >>> { x: y for y, x in ((1, 2), (3, 4)) } += 5 # doctest: +IGNORE_EXCEPTION_DETAIL
- Traceback (most recent call last):
- ...
- SyntaxError: ...
+ expected = {0: None, 1: None, 2: None, 3: None, 4: None, 5: None,
+ 6: None, 7: None, 8: None, 9: None}
+ actual = {k: None for k in range(10)}
+ self.assertEqual(actual, expected)
+ self.assertEqual(k, "Local Variable")
-"""
+ expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
+ 38: 4, 39: 4, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 54: 6,
+ 55: 6, 56: 6, 57: 6, 58: 6, 59: 6, 63: 7, 64: 7, 65: 7,
+ 66: 7, 67: 7, 68: 7, 69: 7, 72: 8, 73: 8, 74: 8, 75: 8,
+ 76: 8, 77: 8, 78: 8, 79: 8, 81: 9, 82: 9, 83: 9, 84: 9,
+ 85: 9, 86: 9, 87: 9, 88: 9, 89: 9}
+ actual = {k: v for v in range(10) for k in range(v * 9, v * 10)}
+ self.assertEqual(k, "Local Variable")
+ self.assertEqual(actual, expected)
-__test__ = {'doctests' : doctests}
+ def test_scope_isolation_from_global(self):
+ expected = {0: None, 1: None, 2: None, 3: None, 4: None, 5: None,
+ 6: None, 7: None, 8: None, 9: None}
+ actual = {g: None for g in range(10)}
+ self.assertEqual(actual, expected)
+ self.assertEqual(g, "Global variable")
-def test_main(verbose=None):
- import sys
- from test import test_support
- from test import test_dictcomps
- test_support.run_doctest(test_dictcomps, verbose)
+ expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
+ 38: 4, 39: 4, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 54: 6,
+ 55: 6, 56: 6, 57: 6, 58: 6, 59: 6, 63: 7, 64: 7, 65: 7,
+ 66: 7, 67: 7, 68: 7, 69: 7, 72: 8, 73: 8, 74: 8, 75: 8,
+ 76: 8, 77: 8, 78: 8, 79: 8, 81: 9, 82: 9, 83: 9, 84: 9,
+ 85: 9, 86: 9, 87: 9, 88: 9, 89: 9}
+ actual = {g: v for v in range(10) for g in range(v * 9, v * 10)}
+ self.assertEqual(g, "Global variable")
+ self.assertEqual(actual, expected)
- # verify reference counting
- if verbose and hasattr(sys, "gettotalrefcount"):
- import gc
- counts = [None] * 5
- for i in range(len(counts)):
- test_support.run_doctest(test_dictcomps, verbose)
- gc.collect()
- counts[i] = sys.gettotalrefcount()
- print(counts)
+ def test_global_visibility(self):
+ expected = {0: 'Global variable', 1: 'Global variable',
+ 2: 'Global variable', 3: 'Global variable',
+ 4: 'Global variable', 5: 'Global variable',
+ 6: 'Global variable', 7: 'Global variable',
+ 8: 'Global variable', 9: 'Global variable'}
+ actual = {k: g for k in range(10)}
+ self.assertEqual(actual, expected)
+
+ def test_local_visibility(self):
+ v = "Local variable"
+ expected = {0: 'Local variable', 1: 'Local variable',
+ 2: 'Local variable', 3: 'Local variable',
+ 4: 'Local variable', 5: 'Local variable',
+ 6: 'Local variable', 7: 'Local variable',
+ 8: 'Local variable', 9: 'Local variable'}
+ actual = {k: v for k in range(10)}
+ self.assertEqual(actual, expected)
+ self.assertEqual(v, "Local variable")
+
+ def test_illegal_assignment(self):
+ with self.assertRaisesRegexp(SyntaxError, "can't assign"):
+ compile("{x: y for y, x in ((1, 2), (3, 4))} = 5", "<test>",
+ "exec")
+
+ with self.assertRaisesRegexp(SyntaxError, "can't assign"):
+ compile("{x: y for y, x in ((1, 2), (3, 4))} += 5", "<test>",
+ "exec")
+
+
+def test_main():
+ support.run_unittest(__name__)
if __name__ == "__main__":
- test_main(verbose=True)
+ test_main()
diff --git a/lib-python/2.7/test/test_doctest.py b/lib-python/2.7/test/test_doctest.py
--- a/lib-python/2.7/test/test_doctest.py
+++ b/lib-python/2.7/test/test_doctest.py
@@ -2006,6 +2006,31 @@
>>> suite.run(unittest.TestResult())
<unittest.result.TestResult run=9 errors=0 failures=4>
+ The module need not contain any doctest examples:
+
+ >>> suite = doctest.DocTestSuite('test.sample_doctest_no_doctests')
+ >>> suite.run(unittest.TestResult())
+ <unittest.result.TestResult run=0 errors=0 failures=0>
+
+ However, if DocTestSuite finds no docstrings, it raises an error:
+
+ >>> try:
+ ... doctest.DocTestSuite('test.sample_doctest_no_docstrings')
+ ... except ValueError as e:
+ ... error = e
+
+ >>> print(error.args[1])
+ has no docstrings
+
+ You can prevent this error by passing a DocTestFinder instance with
+ the `exclude_empty` keyword argument set to False:
+
+ >>> finder = doctest.DocTestFinder(exclude_empty=False)
+ >>> suite = doctest.DocTestSuite('test.sample_doctest_no_docstrings',
+ ... test_finder=finder)
+ >>> suite.run(unittest.TestResult())
+ <unittest.result.TestResult run=0 errors=0 failures=0>
+
We can use the current module:
>>> suite = test.sample_doctest.test_suite()
@@ -2648,7 +2673,9 @@
from test import test_doctest
# Ignore all warnings about the use of class Tester in this module.
- deprecations = [("class Tester is deprecated", DeprecationWarning)]
+ deprecations = []
+ if __debug__:
+ deprecations.append(("class Tester is deprecated", DeprecationWarning))
if sys.py3kwarning:
deprecations += [("backquote not supported", SyntaxWarning),
("execfile.. not supported", DeprecationWarning)]
diff --git a/lib-python/2.7/test/test_docxmlrpc.py b/lib-python/2.7/test/test_docxmlrpc.py
--- a/lib-python/2.7/test/test_docxmlrpc.py
+++ b/lib-python/2.7/test/test_docxmlrpc.py
@@ -100,7 +100,7 @@
self.assertEqual(response.status, 200)
self.assertEqual(response.getheader("Content-type"), "text/html")
- # Server throws an exception if we don't start to read the data
+ # Server raises an exception if we don't start to read the data
response.read()
def test_invalid_get_response(self):
diff --git a/lib-python/2.7/test/test_email.py b/lib-python/2.7/test/test_email.py
--- a/lib-python/2.7/test/test_email.py
+++ b/lib-python/2.7/test/test_email.py
@@ -3,10 +3,12 @@
# The specific tests now live in Lib/email/test
from email.test.test_email import suite
+from email.test.test_email_renamed import suite as suite2
from test import test_support
def test_main():
test_support.run_unittest(suite())
+ test_support.run_unittest(suite2())
if __name__ == '__main__':
test_main()
diff --git a/lib-python/2.7/test/test_exceptions.py b/lib-python/2.7/test/test_exceptions.py
--- a/lib-python/2.7/test/test_exceptions.py
+++ b/lib-python/2.7/test/test_exceptions.py
@@ -479,6 +479,18 @@
except AssertionError as e:
self.assertEqual(str(e), "(3,)")
+ def test_bad_exception_clearing(self):
+ # See issue 16445: use of Py_XDECREF instead of Py_CLEAR in
+ # BaseException_set_message gave a possible way to segfault the
+ # interpreter.
+ class Nasty(str):
+ def __del__(message):
+ del e.message
+
+ e = ValueError(Nasty("msg"))
+ e.args = ()
+ del e.message
+
# Helper class used by TestSameStrAndUnicodeMsg
class ExcWithOverriddenStr(Exception):
diff --git a/lib-python/2.7/test/test_fcntl.py b/lib-python/2.7/test/test_fcntl.py
--- a/lib-python/2.7/test/test_fcntl.py
+++ b/lib-python/2.7/test/test_fcntl.py
@@ -6,6 +6,7 @@
import os
import struct
import sys
+import _testcapi
import unittest
from test.test_support import (verbose, TESTFN, unlink, run_unittest,
import_module)
@@ -81,6 +82,26 @@
rv = fcntl.fcntl(self.f, fcntl.F_SETLKW, lockdata)
self.f.close()
+ def test_fcntl_bad_file(self):
+ class F:
+ def __init__(self, fn):
+ self.fn = fn
+ def fileno(self):
+ return self.fn
+ self.assertRaises(ValueError, fcntl.fcntl, -1, fcntl.F_SETFL, os.O_NONBLOCK)
+ self.assertRaises(ValueError, fcntl.fcntl, F(-1), fcntl.F_SETFL, os.O_NONBLOCK)
+ self.assertRaises(TypeError, fcntl.fcntl, 'spam', fcntl.F_SETFL, os.O_NONBLOCK)
+ self.assertRaises(TypeError, fcntl.fcntl, F('spam'), fcntl.F_SETFL, os.O_NONBLOCK)
+ # Issue 15989
+ self.assertRaises(ValueError, fcntl.fcntl, _testcapi.INT_MAX + 1,
+ fcntl.F_SETFL, os.O_NONBLOCK)
+ self.assertRaises(ValueError, fcntl.fcntl, F(_testcapi.INT_MAX + 1),
+ fcntl.F_SETFL, os.O_NONBLOCK)
+ self.assertRaises(ValueError, fcntl.fcntl, _testcapi.INT_MIN - 1,
+ fcntl.F_SETFL, os.O_NONBLOCK)
+ self.assertRaises(ValueError, fcntl.fcntl, F(_testcapi.INT_MIN - 1),
+ fcntl.F_SETFL, os.O_NONBLOCK)
+
def test_fcntl_64_bit(self):
# Issue #1309352: fcntl shouldn't fail when the third arg fits in a
# C 'long' but not in a C 'int'.
diff --git a/lib-python/2.7/test/test_file2k.py b/lib-python/2.7/test/test_file2k.py
--- a/lib-python/2.7/test/test_file2k.py
+++ b/lib-python/2.7/test/test_file2k.py
@@ -2,6 +2,9 @@
import os
import unittest
import itertools
+import select
+import signal
+import subprocess
import time
from array import array
from weakref import proxy
@@ -602,6 +605,148 @@
self._test_close_open_io(io_func)
+ at unittest.skipUnless(os.name == 'posix', 'test requires a posix system.')
+class TestFileSignalEINTR(unittest.TestCase):
+ def _test_reading(self, data_to_write, read_and_verify_code, method_name,
+ universal_newlines=False):
+ """Generic buffered read method test harness to verify EINTR behavior.
+
+ Also validates that Python signal handlers are run during the read.
+
+ Args:
+ data_to_write: String to write to the child process for reading
+ before sending it a signal, confirming the signal was handled,
+ writing a final newline char and closing the infile pipe.
+ read_and_verify_code: Single "line" of code to read from a file
+ object named 'infile' and validate the result. This will be
+ executed as part of a python subprocess fed data_to_write.
+ method_name: The name of the read method being tested, for use in
+ an error message on failure.
+ universal_newlines: If True, infile will be opened in universal
+ newline mode in the child process.
+ """
+ if universal_newlines:
+ # Test the \r\n -> \n conversion while we're at it.
+ data_to_write = data_to_write.replace('\n', '\r\n')
+ infile_setup_code = 'infile = os.fdopen(sys.stdin.fileno(), "rU")'
+ else:
+ infile_setup_code = 'infile = sys.stdin'
+ # Total pipe IO in this function is smaller than the minimum posix OS
+ # pipe buffer size of 512 bytes. No writer should block.
+ assert len(data_to_write) < 512, 'data_to_write must fit in pipe buf.'
+
+ child_code = (
+ 'import os, signal, sys ;'
+ 'signal.signal('
+ 'signal.SIGINT, lambda s, f: sys.stderr.write("$\\n")) ;'
+ + infile_setup_code + ' ;' +
+ 'assert isinstance(infile, file) ;'
+ 'sys.stderr.write("Go.\\n") ;'
+ + read_and_verify_code)
+ reader_process = subprocess.Popen(
+ [sys.executable, '-c', child_code],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ # Wait for the signal handler to be installed.
+ go = reader_process.stderr.read(4)
+ if go != 'Go.\n':
+ reader_process.kill()
+ self.fail('Error from %s process while awaiting "Go":\n%s' % (
+ method_name, go+reader_process.stderr.read()))
+ reader_process.stdin.write(data_to_write)
+ signals_sent = 0
+ rlist = []
+ # We don't know when the read_and_verify_code in our child is actually
+ # executing within the read system call we want to interrupt. This
+ # loop waits for a bit before sending the first signal to increase
+ # the likelihood of that. Implementations without correct EINTR
+ # and signal handling usually fail this test.
+ while not rlist:
+ rlist, _, _ = select.select([reader_process.stderr], (), (), 0.05)
+ reader_process.send_signal(signal.SIGINT)
+ # Give the subprocess time to handle it before we loop around and
+ # send another one. On OSX the second signal happening close to
+ # immediately after the first was causing the subprocess to crash
+ # via the OS's default SIGINT handler.
+ time.sleep(0.1)
+ signals_sent += 1
+ if signals_sent > 200:
+ reader_process.kill()
+ self.fail("failed to handle signal during %s." % method_name)
+ # This assumes anything unexpected that writes to stderr will also
+ # write a newline. That is true of the traceback printing code.
+ signal_line = reader_process.stderr.readline()
+ if signal_line != '$\n':
+ reader_process.kill()
+ self.fail('Error from %s process while awaiting signal:\n%s' % (
+ method_name, signal_line+reader_process.stderr.read()))
+ # We append a newline to our input so that a readline call can
+ # end on its own before the EOF is seen.
+ stdout, stderr = reader_process.communicate(input='\n')
+ if reader_process.returncode != 0:
+ self.fail('%s() process exited rc=%d.\nSTDOUT:\n%s\nSTDERR:\n%s' % (
+ method_name, reader_process.returncode, stdout, stderr))
+
+ def test_readline(self, universal_newlines=False):
+ """file.readline must handle signals and not lose data."""
+ self._test_reading(
+ data_to_write='hello, world!',
+ read_and_verify_code=(
+ 'line = infile.readline() ;'
+ 'expected_line = "hello, world!\\n" ;'
+ 'assert line == expected_line, ('
+ '"read %r expected %r" % (line, expected_line))'
+ ),
+ method_name='readline',
+ universal_newlines=universal_newlines)
+
+ def test_readline_with_universal_newlines(self):
+ self.test_readline(universal_newlines=True)
+
+ def test_readlines(self, universal_newlines=False):
+ """file.readlines must handle signals and not lose data."""
+ self._test_reading(
+ data_to_write='hello\nworld!',
+ read_and_verify_code=(
+ 'lines = infile.readlines() ;'
+ 'expected_lines = ["hello\\n", "world!\\n"] ;'
+ 'assert lines == expected_lines, ('
+ '"readlines returned wrong data.\\n" '
+ '"got lines %r\\nexpected %r" '
+ '% (lines, expected_lines))'
+ ),
+ method_name='readlines',
+ universal_newlines=universal_newlines)
+
+ def test_readlines_with_universal_newlines(self):
+ self.test_readlines(universal_newlines=True)
+
+ def test_readall(self):
+ """Unbounded file.read() must handle signals and not lose data."""
+ self._test_reading(
+ data_to_write='hello, world!abcdefghijklm',
+ read_and_verify_code=(
+ 'data = infile.read() ;'
+ 'expected_data = "hello, world!abcdefghijklm\\n";'
+ 'assert data == expected_data, ('
+ '"read %r expected %r" % (data, expected_data))'
+ ),
+ method_name='unbounded read')
+
+ def test_readinto(self):
+ """file.readinto must handle signals and not lose data."""
+ self._test_reading(
+ data_to_write='hello, world!',
+ read_and_verify_code=(
+ 'data = bytearray(50) ;'
+ 'num_read = infile.readinto(data) ;'
+ 'expected_data = "hello, world!\\n";'
+ 'assert data[:num_read] == expected_data, ('
+ '"read %r expected %r" % (data, expected_data))'
+ ),
+ method_name='readinto')
+
+
class StdoutTests(unittest.TestCase):
def test_move_stdout_on_write(self):
@@ -678,7 +823,7 @@
# So get rid of it no matter what.
try:
run_unittest(AutoFileTests, OtherFileTests, FileSubclassTests,
- FileThreadingTests, StdoutTests)
+ FileThreadingTests, TestFileSignalEINTR, StdoutTests)
finally:
if os.path.exists(TESTFN):
os.unlink(TESTFN)
diff --git a/lib-python/2.7/test/test_fileio.py b/lib-python/2.7/test/test_fileio.py
--- a/lib-python/2.7/test/test_fileio.py
+++ b/lib-python/2.7/test/test_fileio.py
@@ -9,6 +9,8 @@
from array import array
from weakref import proxy
from functools import wraps
+from UserList import UserList
+import _testcapi
from test.test_support import TESTFN, check_warnings, run_unittest, make_bad_fd
from test.test_support import py3k_bytes as bytes
@@ -71,6 +73,26 @@
n = self.f.readinto(a)
self.assertEqual(array(b'b', [1, 2]), a[:n])
+ def testWritelinesList(self):
+ l = [b'123', b'456']
+ self.f.writelines(l)
+ self.f.close()
+ self.f = _FileIO(TESTFN, 'rb')
+ buf = self.f.read()
+ self.assertEqual(buf, b'123456')
+
+ def testWritelinesUserList(self):
+ l = UserList([b'123', b'456'])
+ self.f.writelines(l)
+ self.f.close()
+ self.f = _FileIO(TESTFN, 'rb')
+ buf = self.f.read()
+ self.assertEqual(buf, b'123456')
+
+ def testWritelinesError(self):
+ self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
+ self.assertRaises(TypeError, self.f.writelines, None)
+
def test_none_args(self):
self.f.write(b"hi\nbye\nabc")
self.f.close()
@@ -130,6 +152,14 @@
else:
self.fail("Should have raised IOError")
+ @unittest.skipIf(os.name == 'nt', "test only works on a POSIX-like system")
+ def testOpenDirFD(self):
+ fd = os.open('.', os.O_RDONLY)
+ with self.assertRaises(IOError) as cm:
+ _FileIO(fd, 'r')
+ os.close(fd)
+ self.assertEqual(cm.exception.errno, errno.EISDIR)
+
#A set of functions testing that we get expected behaviour if someone has
#manually closed the internal file descriptor. First, a decorator:
def ClosedFD(func):
@@ -314,6 +344,9 @@
if sys.platform == 'win32':
import msvcrt
self.assertRaises(IOError, msvcrt.get_osfhandle, make_bad_fd())
+ # Issue 15989
+ self.assertRaises(TypeError, _FileIO, _testcapi.INT_MAX + 1)
+ self.assertRaises(TypeError, _FileIO, _testcapi.INT_MIN - 1)
def testBadModeArgument(self):
# verify that we get a sensible error message for bad mode argument
@@ -417,10 +450,22 @@
env = dict(os.environ)
env[b'LC_CTYPE'] = b'C'
_, out = run_python('-c', 'import _io; _io.FileIO(%r)' % filename, env=env)
- if ('UnicodeEncodeError' not in out and
- 'IOError: [Errno 2] No such file or directory' not in out):
+ if ('UnicodeEncodeError' not in out and not
+ ( ('IOError: [Errno 2] No such file or directory' in out) or
+ ('IOError: [Errno 22] Invalid argument' in out) ) ):
self.fail('Bad output: %r' % out)
+ def testUnclosedFDOnException(self):
+ class MyException(Exception): pass
+ class MyFileIO(_FileIO):
+ def __setattr__(self, name, value):
+ if name == "name":
+ raise MyException("blocked setting name")
+ return super(MyFileIO, self).__setattr__(name, value)
+ fd = os.open(__file__, os.O_RDONLY)
+ self.assertRaises(MyException, MyFileIO, fd)
+ os.close(fd) # should not raise OSError(EBADF)
+
def test_main():
# Historically, these tests have been sloppy about removing TESTFN.
# So get rid of it no matter what.
diff --git a/lib-python/2.7/test/test_format.py b/lib-python/2.7/test/test_format.py
--- a/lib-python/2.7/test/test_format.py
+++ b/lib-python/2.7/test/test_format.py
@@ -234,6 +234,16 @@
testformat('%g', 1.1, '1.1')
testformat('%#g', 1.1, '1.10000')
+ # Regression test for http://bugs.python.org/issue15516.
+ class IntFails(object):
+ def __int__(self):
+ raise TestFailed
+ def __long__(self):
+ return 0
+
+ fst = IntFails()
+ testformat("%x", fst, '0')
+
# Test exception for unknown format characters
if verbose:
print 'Testing exceptions'
diff --git a/lib-python/2.7/test/test_functools.py b/lib-python/2.7/test/test_functools.py
--- a/lib-python/2.7/test/test_functools.py
+++ b/lib-python/2.7/test/test_functools.py
@@ -151,6 +151,23 @@
f_copy = pickle.loads(pickle.dumps(f))
self.assertEqual(signature(f), signature(f_copy))
+ # Issue 6083: Reference counting bug
+ def test_setstate_refcount(self):
+ class BadSequence:
+ def __len__(self):
+ return 4
+ def __getitem__(self, key):
+ if key == 0:
+ return max
+ elif key == 1:
+ return tuple(range(1000000))
+ elif key in (2, 3):
+ return {}
+ raise IndexError
+
+ f = self.thetype(object)
+ self.assertRaises(SystemError, f.__setstate__, BadSequence())
+
class PartialSubclass(functools.partial):
pass
@@ -164,6 +181,7 @@
# the python version isn't picklable
def test_pickle(self): pass
+ def test_setstate_refcount(self): pass
class TestUpdateWrapper(unittest.TestCase):
@@ -232,6 +250,7 @@
self.assertEqual(wrapper.attr, 'This is a different test')
self.assertEqual(wrapper.dict_attr, f.dict_attr)
+ @test_support.requires_docstrings
def test_builtin_update(self):
# Test for bug #1576241
def wrapper():
@@ -258,7 +277,7 @@
self.assertEqual(wrapper.__name__, 'f')
self.assertEqual(wrapper.attr, 'This is also a test')
- @unittest.skipIf(not sys.flags.optimize <= 1,
+ @unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
def test_default_update_doc(self):
wrapper = self._default_update()
diff --git a/lib-python/2.7/test/test_gc.py b/lib-python/2.7/test/test_gc.py
--- a/lib-python/2.7/test/test_gc.py
+++ b/lib-python/2.7/test/test_gc.py
@@ -1,9 +1,15 @@
import unittest
from test.test_support import verbose, run_unittest
import sys
+import time
import gc
import weakref
+try:
+ import threading
+except ImportError:
+ threading = None
+
### Support code
###############################################################################
@@ -299,6 +305,69 @@
v = {1: v, 2: Ouch()}
gc.disable()
+ @unittest.skipUnless(threading, "test meaningless on builds without threads")
+ def test_trashcan_threads(self):
+ # Issue #13992: trashcan mechanism should be thread-safe
+ NESTING = 60
+ N_THREADS = 2
+
+ def sleeper_gen():
+ """A generator that releases the GIL when closed or dealloc'ed."""
+ try:
+ yield
+ finally:
+ time.sleep(0.000001)
+
+ class C(list):
+ # Appending to a list is atomic, which avoids the use of a lock.
+ inits = []
+ dels = []
+ def __init__(self, alist):
+ self[:] = alist
+ C.inits.append(None)
+ def __del__(self):
+ # This __del__ is called by subtype_dealloc().
+ C.dels.append(None)
+ # `g` will release the GIL when garbage-collected. This
+ # helps assert subtype_dealloc's behaviour when threads
+ # switch in the middle of it.
+ g = sleeper_gen()
+ next(g)
+ # Now that __del__ is finished, subtype_dealloc will proceed
+ # to call list_dealloc, which also uses the trashcan mechanism.
+
+ def make_nested():
+ """Create a sufficiently nested container object so that the
+ trashcan mechanism is invoked when deallocating it."""
+ x = C([])
+ for i in range(NESTING):
+ x = [C([x])]
+ del x
+
+ def run_thread():
+ """Exercise make_nested() in a loop."""
+ while not exit:
+ make_nested()
+
+ old_checkinterval = sys.getcheckinterval()
+ sys.setcheckinterval(3)
+ try:
+ exit = False
+ threads = []
+ for i in range(N_THREADS):
+ t = threading.Thread(target=run_thread)
+ threads.append(t)
+ for t in threads:
+ t.start()
+ time.sleep(1.0)
+ exit = True
+ for t in threads:
+ t.join()
+ finally:
+ sys.setcheckinterval(old_checkinterval)
+ gc.collect()
+ self.assertEqual(len(C.inits), len(C.dels))
+
def test_boom(self):
class Boom:
def __getattr__(self, someattribute):
diff --git a/lib-python/2.7/test/test_gdb.py b/lib-python/2.7/test/test_gdb.py
--- a/lib-python/2.7/test/test_gdb.py
+++ b/lib-python/2.7/test/test_gdb.py
@@ -19,19 +19,48 @@
# This is what "no gdb" looks like. There may, however, be other
# errors that manifest this way too.
raise unittest.SkipTest("Couldn't find gdb on the path")
-gdb_version_number = re.search(r"^GNU gdb [^\d]*(\d+)\.", gdb_version)
-if int(gdb_version_number.group(1)) < 7:
+gdb_version_number = re.search("^GNU gdb [^\d]*(\d+)\.(\d)", gdb_version)
+gdb_major_version = int(gdb_version_number.group(1))
+gdb_minor_version = int(gdb_version_number.group(2))
+if gdb_major_version < 7:
raise unittest.SkipTest("gdb versions before 7.0 didn't support python embedding"
" Saw:\n" + gdb_version)
+# Location of custom hooks file in a repository checkout.
+checkout_hook_path = os.path.join(os.path.dirname(sys.executable),
+ 'python-gdb.py')
+
+def run_gdb(*args, **env_vars):
+ """Runs gdb in --batch mode with the additional arguments given by *args.
+
+ Returns its (stdout, stderr)
+ """
+ if env_vars:
+ env = os.environ.copy()
+ env.update(env_vars)
+ else:
+ env = None
+ base_cmd = ('gdb', '--batch')
+ if (gdb_major_version, gdb_minor_version) >= (7, 4):
+ base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path)
+ out, err = subprocess.Popen(base_cmd + args,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env,
+ ).communicate()
+ return out, err
+
# Verify that "gdb" was built with the embedded python support enabled:
-cmd = "--eval-command=python import sys; print sys.version_info"
-p = subprocess.Popen(["gdb", "--batch", cmd],
- stdout=subprocess.PIPE)
-gdbpy_version, _ = p.communicate()
-if gdbpy_version == '':
+gdbpy_version, _ = run_gdb("--eval-command=python import sys; print sys.version_info")
+if not gdbpy_version:
raise unittest.SkipTest("gdb not built with embedded python support")
+# Verify that "gdb" can load our custom hooks. In theory this should never
+# fail, but we don't handle the case of the hooks file not existing if the
+# tests are run from an installed Python (we'll produce failures in that case).
+cmd = ['--args', sys.executable]
+_, gdbpy_errors = run_gdb('--args', sys.executable)
+if "auto-loading has been declined" in gdbpy_errors:
+ msg = "gdb security settings prevent use of custom hooks: "
+
def python_is_optimized():
cflags = sysconfig.get_config_vars()['PY_CFLAGS']
final_opt = ""
@@ -42,10 +71,7 @@
def gdb_has_frame_select():
# Does this build of gdb have gdb.Frame.select ?
- cmd = "--eval-command=python print(dir(gdb.Frame))"
- p = subprocess.Popen(["gdb", "--batch", cmd],
- stdout=subprocess.PIPE)
- stdout, _ = p.communicate()
+ stdout, _ = run_gdb("--eval-command=python print(dir(gdb.Frame))")
m = re.match(r'.*\[(.*)\].*', stdout)
if not m:
raise unittest.SkipTest("Unable to parse output from gdb.Frame.select test")
@@ -58,21 +84,6 @@
"""Test that the debugger can debug Python."""
- def run_gdb(self, *args, **env_vars):
- """Runs gdb with the command line given by *args.
-
- Returns its stdout, stderr
- """
- if env_vars:
- env = os.environ.copy()
- env.update(env_vars)
- else:
- env = None
- out, err = subprocess.Popen(
- args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env
- ).communicate()
- return out, err
-
def get_stack_trace(self, source=None, script=None,
breakpoint='PyObject_Print',
cmds_after_breakpoint=None,
@@ -129,7 +140,7 @@
# print ' '.join(args)
# Use "args" to invoke gdb, capturing stdout, stderr:
- out, err = self.run_gdb(*args, PYTHONHASHSEED='0')
+ out, err = run_gdb(*args, PYTHONHASHSEED='0')
# Ignore some noise on stderr due to the pending breakpoint:
err = err.replace('Function "%s" not defined.\n' % breakpoint, '')
@@ -141,6 +152,16 @@
err = err.replace("warning: Cannot initialize thread debugging"
" library: Debugger service failed\n",
'')
+ err = err.replace('warning: Could not load shared library symbols for '
+ 'linux-vdso.so.1.\n'
+ 'Do you need "set solib-search-path" or '
+ '"set sysroot"?\n',
+ '')
+ err = err.replace('warning: Could not load shared library symbols for '
+ 'linux-gate.so.1.\n'
+ 'Do you need "set solib-search-path" or '
+ '"set sysroot"?\n',
+ '')
# Ensure no unexpected error messages:
self.assertEqual(err, '')
diff --git a/lib-python/2.7/test/test_generators.py b/lib-python/2.7/test/test_generators.py
--- a/lib-python/2.7/test/test_generators.py
+++ b/lib-python/2.7/test/test_generators.py
@@ -383,7 +383,8 @@
<type 'generator'>
>>> [s for s in dir(i) if not s.startswith('_')]
['close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']
->>> print i.next.__doc__
+>>> from test.test_support import HAVE_DOCSTRINGS
+>>> print(i.next.__doc__ if HAVE_DOCSTRINGS else 'x.next() -> the next value, or raise StopIteration')
x.next() -> the next value, or raise StopIteration
>>> iter(i) is i
True
diff --git a/lib-python/2.7/test/test_genexps.py b/lib-python/2.7/test/test_genexps.py
--- a/lib-python/2.7/test/test_genexps.py
+++ b/lib-python/2.7/test/test_genexps.py
@@ -223,7 +223,8 @@
>>> set(attr for attr in dir(g) if not attr.startswith('__')) >= expected
True
- >>> print g.next.__doc__
+ >>> from test.test_support import HAVE_DOCSTRINGS
+ >>> print(g.next.__doc__ if HAVE_DOCSTRINGS else 'x.next() -> the next value, or raise StopIteration')
x.next() -> the next value, or raise StopIteration
>>> import types
>>> isinstance(g, types.GeneratorType)
diff --git a/lib-python/2.7/test/test_glob.py b/lib-python/2.7/test/test_glob.py
--- a/lib-python/2.7/test/test_glob.py
+++ b/lib-python/2.7/test/test_glob.py
@@ -1,8 +1,15 @@
-import unittest
-from test.test_support import run_unittest, TESTFN
import glob
import os
import shutil
+import sys
+import unittest
+
+from test.test_support import run_unittest, TESTFN
+
+
+def fsdecode(s):
+ return unicode(s, sys.getfilesystemencoding())
+
class GlobTests(unittest.TestCase):
@@ -18,16 +25,19 @@
f.close()
def setUp(self):
- self.tempdir = TESTFN+"_dir"
+ self.tempdir = TESTFN + "_dir"
self.mktemp('a', 'D')
self.mktemp('aab', 'F')
+ self.mktemp('.aa', 'G')
+ self.mktemp('.bb', 'H')
self.mktemp('aaa', 'zzzF')
self.mktemp('ZZZ')
self.mktemp('a', 'bcd', 'EF')
self.mktemp('a', 'bcd', 'efg', 'ha')
if hasattr(os, 'symlink'):
os.symlink(self.norm('broken'), self.norm('sym1'))
- os.symlink(self.norm('broken'), self.norm('sym2'))
+ os.symlink('broken', self.norm('sym2'))
+ os.symlink(os.path.join('a', 'bcd'), self.norm('sym3'))
def tearDown(self):
shutil.rmtree(self.tempdir)
@@ -40,10 +50,16 @@
p = os.path.join(self.tempdir, pattern)
res = glob.glob(p)
self.assertEqual(list(glob.iglob(p)), res)
+ ures = [fsdecode(x) for x in res]
+ self.assertEqual(glob.glob(fsdecode(p)), ures)
+ self.assertEqual(list(glob.iglob(fsdecode(p))), ures)
return res
def assertSequencesEqual_noorder(self, l1, l2):
+ l1 = list(l1)
+ l2 = list(l2)
self.assertEqual(set(l1), set(l2))
+ self.assertEqual(sorted(l1), sorted(l2))
def test_glob_literal(self):
eq = self.assertSequencesEqual_noorder
@@ -52,20 +68,26 @@
eq(self.glob('aab'), [self.norm('aab')])
eq(self.glob('zymurgy'), [])
+ res = glob.glob('*')
+ self.assertEqual({type(r) for r in res}, {str})
+ res = glob.glob(os.path.join(os.curdir, '*'))
+ self.assertEqual({type(r) for r in res}, {str})
+
# test return types are unicode, but only if os.listdir
# returns unicode filenames
- uniset = set([unicode])
- tmp = os.listdir(u'.')
- if set(type(x) for x in tmp) == uniset:
- u1 = glob.glob(u'*')
- u2 = glob.glob(u'./*')
- self.assertEqual(set(type(r) for r in u1), uniset)
- self.assertEqual(set(type(r) for r in u2), uniset)
+ tmp = os.listdir(fsdecode(os.curdir))
+ if {type(x) for x in tmp} == {unicode}:
+ res = glob.glob(u'*')
+ self.assertEqual({type(r) for r in res}, {unicode})
+ res = glob.glob(os.path.join(fsdecode(os.curdir), u'*'))
+ self.assertEqual({type(r) for r in res}, {unicode})
def test_glob_one_directory(self):
eq = self.assertSequencesEqual_noorder
eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa']))
eq(self.glob('*a'), map(self.norm, ['a', 'aaa']))
+ eq(self.glob('.*'), map(self.norm, ['.aa', '.bb']))
+ eq(self.glob('?aa'), map(self.norm, ['aaa']))
eq(self.glob('aa?'), map(self.norm, ['aaa', 'aab']))
eq(self.glob('aa[ab]'), map(self.norm, ['aaa', 'aab']))
eq(self.glob('*q'), [])
@@ -87,23 +109,68 @@
eq(self.glob('*', '*a'), [])
eq(self.glob('a', '*', '*', '*a'),
[self.norm('a', 'bcd', 'efg', 'ha')])
- eq(self.glob('?a?', '*F'), map(self.norm, [os.path.join('aaa', 'zzzF'),
- os.path.join('aab', 'F')]))
+ eq(self.glob('?a?', '*F'), [self.norm('aaa', 'zzzF'),
+ self.norm('aab', 'F')])
def test_glob_directory_with_trailing_slash(self):
- # We are verifying that when there is wildcard pattern which
- # ends with os.sep doesn't blow up.
- res = glob.glob(self.tempdir + '*' + os.sep)
- self.assertEqual(len(res), 1)
- # either of these results are reasonable
- self.assertIn(res[0], [self.tempdir, self.tempdir + os.sep])
+ # Patterns ending with a slash shouldn't match non-dirs
+ res = glob.glob(self.norm('Z*Z') + os.sep)
+ self.assertEqual(res, [])
+ res = glob.glob(self.norm('ZZZ') + os.sep)
+ self.assertEqual(res, [])
+ # When there is a wildcard pattern which ends with os.sep, glob()
+ # doesn't blow up.
+ res = glob.glob(self.norm('aa*') + os.sep)
+ self.assertEqual(len(res), 2)
+ # either of these results is reasonable
+ self.assertIn(set(res), [
+ {self.norm('aaa'), self.norm('aab')},
+ {self.norm('aaa') + os.sep, self.norm('aab') + os.sep},
+ ])
+ def test_glob_unicode_directory_with_trailing_slash(self):
+ # Same as test_glob_directory_with_trailing_slash, but with an
+ # unicode argument.
+ res = glob.glob(fsdecode(self.norm('Z*Z') + os.sep))
+ self.assertEqual(res, [])
+ res = glob.glob(fsdecode(self.norm('ZZZ') + os.sep))
+ self.assertEqual(res, [])
+ res = glob.glob(fsdecode(self.norm('aa*') + os.sep))
+ self.assertEqual(len(res), 2)
+ # either of these results is reasonable
+ self.assertIn(set(res), [
+ {fsdecode(self.norm('aaa')), fsdecode(self.norm('aab'))},
+ {fsdecode(self.norm('aaa') + os.sep),
+ fsdecode(self.norm('aab') + os.sep)},
+ ])
+
+ @unittest.skipUnless(hasattr(os, 'symlink'), "Requires symlink support")
+ def test_glob_symlinks(self):
+ eq = self.assertSequencesEqual_noorder
+ eq(self.glob('sym3'), [self.norm('sym3')])
+ eq(self.glob('sym3', '*'), [self.norm('sym3', 'EF'),
+ self.norm('sym3', 'efg')])
+ self.assertIn(self.glob('sym3' + os.sep),
+ [[self.norm('sym3')], [self.norm('sym3') + os.sep]])
+ eq(self.glob('*', '*F'),
+ [self.norm('aaa', 'zzzF'), self.norm('aab', 'F'),
+ self.norm('sym3', 'EF')])
+
+ @unittest.skipUnless(hasattr(os, 'symlink'), "Requires symlink support")
def test_glob_broken_symlinks(self):
- if hasattr(os, 'symlink'):
- eq = self.assertSequencesEqual_noorder
- eq(self.glob('sym*'), [self.norm('sym1'), self.norm('sym2')])
- eq(self.glob('sym1'), [self.norm('sym1')])
- eq(self.glob('sym2'), [self.norm('sym2')])
+ eq = self.assertSequencesEqual_noorder
+ eq(self.glob('sym*'), [self.norm('sym1'), self.norm('sym2'),
+ self.norm('sym3')])
+ eq(self.glob('sym1'), [self.norm('sym1')])
+ eq(self.glob('sym2'), [self.norm('sym2')])
+
+ @unittest.skipUnless(sys.platform == "win32", "Win32 specific test")
+ def test_glob_magic_in_drive(self):
+ eq = self.assertSequencesEqual_noorder
+ eq(glob.glob('*:'), [])
+ eq(glob.glob(u'*:'), [])
+ eq(glob.glob('?:'), [])
+ eq(glob.glob(u'?:'), [])
def test_main():
diff --git a/lib-python/2.7/test/test_gzip.py b/lib-python/2.7/test/test_gzip.py
--- a/lib-python/2.7/test/test_gzip.py
+++ b/lib-python/2.7/test/test_gzip.py
@@ -53,6 +53,13 @@
d = f.read()
self.assertEqual(d, data1*50)
+ def test_read_universal_newlines(self):
+ # Issue #5148: Reading breaks when mode contains 'U'.
+ self.test_write()
+ with gzip.GzipFile(self.filename, 'rU') as f:
+ d = f.read()
+ self.assertEqual(d, data1*50)
+
def test_io_on_closed_object(self):
# Test that I/O operations on closed GzipFile objects raise a
# ValueError, just like the corresponding functions on file objects.
@@ -282,6 +289,24 @@
with gzip.GzipFile(fileobj=f, mode="w") as g:
self.assertEqual(g.name, "")
+ def test_read_truncated(self):
+ data = data1*50
+ buf = io.BytesIO()
+ with gzip.GzipFile(fileobj=buf, mode="w") as f:
+ f.write(data)
+ # Drop the CRC (4 bytes) and file size (4 bytes).
+ truncated = buf.getvalue()[:-8]
+ with gzip.GzipFile(fileobj=io.BytesIO(truncated)) as f:
+ self.assertRaises(EOFError, f.read)
+ with gzip.GzipFile(fileobj=io.BytesIO(truncated)) as f:
+ self.assertEqual(f.read(len(data)), data)
+ self.assertRaises(EOFError, f.read, 1)
+ # Incomplete 10-byte header.
+ for i in range(2, 10):
+ with gzip.GzipFile(fileobj=io.BytesIO(truncated[:i])) as f:
+ self.assertRaises(EOFError, f.read, 1)
+
+
def test_main(verbose=None):
test_support.run_unittest(TestGzip)
diff --git a/lib-python/2.7/test/test_hashlib.py b/lib-python/2.7/test/test_hashlib.py
--- a/lib-python/2.7/test/test_hashlib.py
+++ b/lib-python/2.7/test/test_hashlib.py
@@ -108,12 +108,8 @@
_algo.islower()]))
def test_unknown_hash(self):
- try:
- hashlib.new('spam spam spam spam spam')
- except ValueError:
- pass
- else:
- self.assertTrue(0 == "hashlib didn't reject bogus hash name")
+ self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
+ self.assertRaises(TypeError, hashlib.new, 1)
def test_get_builtin_constructor(self):
get_builtin_constructor = hashlib.__dict__[
@@ -132,6 +128,7 @@
sys.modules['_md5'] = _md5
else:
del sys.modules['_md5']
+ self.assertRaises(TypeError, get_builtin_constructor, 3)
def test_hexdigest(self):
for name in self.supported_hash_names:
@@ -170,6 +167,21 @@
% (name, hash_object_constructor,
computed, len(data), digest))
+ def check_update(self, name, data, digest):
+ constructors = self.constructors_to_test[name]
+ # 2 is for hashlib.name(...) and hashlib.new(name, ...)
+ self.assertGreaterEqual(len(constructors), 2)
+ for hash_object_constructor in constructors:
+ h = hash_object_constructor()
+ h.update(data)
+ computed = h.hexdigest()
+ self.assertEqual(
+ computed, digest,
+ "Hash algorithm %s using %s when updated returned hexdigest"
+ " %r for %d byte input data that should have hashed to %r."
+ % (name, hash_object_constructor,
+ computed, len(data), digest))
+
def check_unicode(self, algorithm_name):
# Unicode objects are not allowed as input.
expected = hashlib.new(algorithm_name, str(u'spam')).hexdigest()
@@ -203,6 +215,15 @@
except OverflowError:
pass # 32-bit arch
+ @precisionbigmemtest(size=_4G + 5, memuse=1)
+ def test_case_md5_huge_update(self, size):
+ if size == _4G + 5:
+ try:
+ self.check_update('md5', 'A'*size,
+ 'c9af2dff37468ce5dfee8f2cfc0a9c6d')
+ except OverflowError:
+ pass # 32-bit arch
+
@precisionbigmemtest(size=_4G - 1, memuse=1)
def test_case_md5_uintmax(self, size):
if size == _4G - 1:
@@ -231,6 +252,23 @@
self.check('sha1', "a" * 1000000,
"34aa973cd4c4daa4f61eeb2bdbad27316534016f")
+ @precisionbigmemtest(size=_4G + 5, memuse=1)
+ def test_case_sha1_huge(self, size):
+ if size == _4G + 5:
+ try:
+ self.check('sha1', 'A'*size,
+ '87d745c50e6b2879ffa0fb2c930e9fbfe0dc9a5b')
+ except OverflowError:
+ pass # 32-bit arch
+
+ @precisionbigmemtest(size=_4G + 5, memuse=1)
+ def test_case_sha1_huge_update(self, size):
+ if size == _4G + 5:
+ try:
+ self.check_update('sha1', 'A'*size,
+ '87d745c50e6b2879ffa0fb2c930e9fbfe0dc9a5b')
+ except OverflowError:
+ pass # 32-bit arch
# use the examples from Federal Information Processing Standards
# Publication 180-2, Secure Hash Standard, 2002 August 1
diff --git a/lib-python/2.7/test/test_heapq.py b/lib-python/2.7/test/test_heapq.py
--- a/lib-python/2.7/test/test_heapq.py
+++ b/lib-python/2.7/test/test_heapq.py
@@ -315,6 +315,16 @@
'Test multiple tiers of iterators'
return chain(imap(lambda x:x, R(Ig(G(seqn)))))
+class SideEffectLT:
+ def __init__(self, value, heap):
+ self.value = value
+ self.heap = heap
+
+ def __lt__(self, other):
+ self.heap[:] = []
+ return self.value < other.value
+
+
class TestErrorHandling(TestCase):
module = None
@@ -361,6 +371,22 @@
self.assertRaises(TypeError, f, 2, N(s))
self.assertRaises(ZeroDivisionError, f, 2, E(s))
+ # Issue #17278: the heap may change size while it's being walked.
+
+ def test_heappush_mutating_heap(self):
+ heap = []
+ heap.extend(SideEffectLT(i, heap) for i in range(200))
+ # Python version raises IndexError, C version RuntimeError
+ with self.assertRaises((IndexError, RuntimeError)):
+ self.module.heappush(heap, SideEffectLT(5, heap))
+
+ def test_heappop_mutating_heap(self):
+ heap = []
+ heap.extend(SideEffectLT(i, heap) for i in range(200))
+ # Python version raises IndexError, C version RuntimeError
+ with self.assertRaises((IndexError, RuntimeError)):
+ self.module.heappop(heap)
+
class TestErrorHandlingPython(TestErrorHandling):
module = py_heapq
diff --git a/lib-python/2.7/test/test_htmlparser.py b/lib-python/2.7/test/test_htmlparser.py
--- a/lib-python/2.7/test/test_htmlparser.py
+++ b/lib-python/2.7/test/test_htmlparser.py
@@ -260,6 +260,16 @@
('starttag', 'a', [('foo', None), ('=', None), ('bar', None)])
]
self._run_check(html, expected)
+ #see issue #14538
+ html = ('<meta><meta / ><meta // ><meta / / >'
+ '<meta/><meta /><meta //><meta//>')
+ expected = [
+ ('starttag', 'meta', []), ('starttag', 'meta', []),
+ ('starttag', 'meta', []), ('starttag', 'meta', []),
+ ('startendtag', 'meta', []), ('startendtag', 'meta', []),
+ ('startendtag', 'meta', []), ('startendtag', 'meta', []),
+ ]
+ self._run_check(html, expected)
def test_declaration_junk_chars(self):
self._run_check("<!DOCTYPE foo $ >", [('decl', 'DOCTYPE foo $ ')])
diff --git a/lib-python/2.7/test/test_httplib.py b/lib-python/2.7/test/test_httplib.py
--- a/lib-python/2.7/test/test_httplib.py
+++ b/lib-python/2.7/test/test_httplib.py
@@ -90,6 +90,34 @@
conn.request('POST', '/', body, headers)
self.assertEqual(conn._buffer.count[header.lower()], 1)
+ def test_content_length_0(self):
+
+ class ContentLengthChecker(list):
+ def __init__(self):
+ list.__init__(self)
+ self.content_length = None
+ def append(self, item):
+ kv = item.split(':', 1)
+ if len(kv) > 1 and kv[0].lower() == 'content-length':
+ self.content_length = kv[1].strip()
+ list.append(self, item)
+
+ # POST with empty body
+ conn = httplib.HTTPConnection('example.com')
+ conn.sock = FakeSocket(None)
+ conn._buffer = ContentLengthChecker()
+ conn.request('POST', '/', '')
+ self.assertEqual(conn._buffer.content_length, '0',
+ 'Header Content-Length not set')
+
+ # PUT request with empty body
+ conn = httplib.HTTPConnection('example.com')
+ conn.sock = FakeSocket(None)
+ conn._buffer = ContentLengthChecker()
+ conn.request('PUT', '/', '')
+ self.assertEqual(conn._buffer.content_length, '0',
+ 'Header Content-Length not set')
+
def test_putheader(self):
conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket(None)
@@ -138,7 +166,7 @@
self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
def test_partial_reads(self):
- # if we have a lenght, the system knows when to close itself
+ # if we have a length, the system knows when to close itself
# same behaviour than when we read the whole thing with read()
body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
sock = FakeSocket(body)
@@ -149,6 +177,32 @@
self.assertEqual(resp.read(2), 'xt')
self.assertTrue(resp.isclosed())
+ def test_partial_reads_no_content_length(self):
+ # when no length is present, the socket should be gracefully closed when
+ # all data was read
+ body = "HTTP/1.1 200 Ok\r\n\r\nText"
+ sock = FakeSocket(body)
+ resp = httplib.HTTPResponse(sock)
+ resp.begin()
+ self.assertEqual(resp.read(2), 'Te')
+ self.assertFalse(resp.isclosed())
+ self.assertEqual(resp.read(2), 'xt')
+ self.assertEqual(resp.read(1), '')
+ self.assertTrue(resp.isclosed())
+
+ def test_partial_reads_incomplete_body(self):
+ # if the server shuts down the connection before the whole
+ # content-length is delivered, the socket is gracefully closed
+ body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
+ sock = FakeSocket(body)
+ resp = httplib.HTTPResponse(sock)
+ resp.begin()
+ self.assertEqual(resp.read(2), 'Te')
+ self.assertFalse(resp.isclosed())
+ self.assertEqual(resp.read(2), 'xt')
+ self.assertEqual(resp.read(1), '')
+ self.assertTrue(resp.isclosed())
+
def test_host_port(self):
# Check invalid host_port
@@ -279,7 +333,7 @@
resp = httplib.HTTPResponse(sock, method="GET")
resp.begin()
self.assertEqual(resp.read(), 'Hello\r\n')
- resp.close()
+ self.assertTrue(resp.isclosed())
def test_incomplete_read(self):
sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
@@ -293,10 +347,9 @@
"IncompleteRead(7 bytes read, 3 more expected)")
self.assertEqual(str(i),
"IncompleteRead(7 bytes read, 3 more expected)")
+ self.assertTrue(resp.isclosed())
else:
self.fail('IncompleteRead expected')
- finally:
- resp.close()
def test_epipe(self):
sock = EPipeSocket(
@@ -349,6 +402,14 @@
resp.begin()
self.assertRaises(httplib.LineTooLong, resp.read)
+ def test_early_eof(self):
+ # Test httpresponse with no \r\n termination,
+ body = "HTTP/1.1 200 Ok"
+ sock = FakeSocket(body)
+ resp = httplib.HTTPResponse(sock)
+ resp.begin()
+ self.assertEqual(resp.read(), '')
+ self.assertTrue(resp.isclosed())
class OfflineTest(TestCase):
def test_responses(self):
diff --git a/lib-python/2.7/test/test_httpservers.py b/lib-python/2.7/test/test_httpservers.py
--- a/lib-python/2.7/test/test_httpservers.py
+++ b/lib-python/2.7/test/test_httpservers.py
@@ -4,11 +4,6 @@
Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest.
"""
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-from SimpleHTTPServer import SimpleHTTPRequestHandler
-from CGIHTTPServer import CGIHTTPRequestHandler
-import CGIHTTPServer
-
import os
import sys
import re
@@ -17,12 +12,17 @@
import urllib
import httplib
import tempfile
+import unittest
+import CGIHTTPServer
-import unittest
+from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from SimpleHTTPServer import SimpleHTTPRequestHandler
+from CGIHTTPServer import CGIHTTPRequestHandler
from StringIO import StringIO
+from test import test_support
-from test import test_support
+
threading = test_support.import_module('threading')
@@ -43,7 +43,7 @@
self.end_headers()
self.wfile.write(b'<html><body>Data</body></html>\r\n')
- def log_message(self, format, *args):
+ def log_message(self, fmt, *args):
pass
@@ -97,9 +97,9 @@
self.handler = SocketlessRequestHandler()
def send_typical_request(self, message):
- input = StringIO(message)
+ input_msg = StringIO(message)
output = StringIO()
- self.handler.rfile = input
+ self.handler.rfile = input_msg
self.handler.wfile = output
self.handler.handle_one_request()
output.seek(0)
@@ -296,7 +296,7 @@
os.chdir(self.cwd)
try:
shutil.rmtree(self.tempdir)
- except:
+ except OSError:
pass
finally:
BaseTestCase.tearDown(self)
@@ -418,42 +418,44 @@
finally:
BaseTestCase.tearDown(self)
- def test_url_collapse_path_split(self):
+ def test_url_collapse_path(self):
+ # verify tail is the last portion and head is the rest on proper urls
test_vectors = {
- '': ('/', ''),
+ '': '//',
'..': IndexError,
'/.//..': IndexError,
- '/': ('/', ''),
- '//': ('/', ''),
- '/\\': ('/', '\\'),
- '/.//': ('/', ''),
- 'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
- '/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
- '/cgi-bin/file1.py/PATH-INFO': ('/cgi-bin', 'file1.py/PATH-INFO'),
- 'a': ('/', 'a'),
- '/a': ('/', 'a'),
- '//a': ('/', 'a'),
- './a': ('/', 'a'),
- './C:/': ('/C:', ''),
- '/a/b': ('/a', 'b'),
- '/a/b/': ('/a/b', ''),
- '/a/b/c/..': ('/a/b', ''),
- '/a/b/c/../d': ('/a/b', 'd'),
- '/a/b/c/../d/e/../f': ('/a/b/d', 'f'),
- '/a/b/c/../d/e/../../f': ('/a/b', 'f'),
- '/a/b/c/../d/e/.././././..//f': ('/a/b', 'f'),
+ '/': '//',
+ '//': '//',
+ '/\\': '//\\',
+ '/.//': '//',
+ 'cgi-bin/file1.py': '/cgi-bin/file1.py',
+ '/cgi-bin/file1.py': '/cgi-bin/file1.py',
+ 'a': '//a',
+ '/a': '//a',
+ '//a': '//a',
+ './a': '//a',
+ './C:/': '/C:/',
+ '/a/b': '/a/b',
+ '/a/b/': '/a/b/',
+ '/a/b/.': '/a/b/',
+ '/a/b/c/..': '/a/b/',
+ '/a/b/c/../d': '/a/b/d',
+ '/a/b/c/../d/e/../f': '/a/b/d/f',
+ '/a/b/c/../d/e/../../f': '/a/b/f',
+ '/a/b/c/../d/e/.././././..//f': '/a/b/f',
'../a/b/c/../d/e/.././././..//f': IndexError,
- '/a/b/c/../d/e/../../../f': ('/a', 'f'),
- '/a/b/c/../d/e/../../../../f': ('/', 'f'),
+ '/a/b/c/../d/e/../../../f': '/a/f',
+ '/a/b/c/../d/e/../../../../f': '//f',
'/a/b/c/../d/e/../../../../../f': IndexError,
- '/a/b/c/../d/e/../../../../f/..': ('/', ''),
+ '/a/b/c/../d/e/../../../../f/..': '//',
+ '/a/b/c/../d/e/../../../../f/../.': '//',
}
for path, expected in test_vectors.iteritems():
if isinstance(expected, type) and issubclass(expected, Exception):
self.assertRaises(expected,
- CGIHTTPServer._url_collapse_path_split, path)
+ CGIHTTPServer._url_collapse_path, path)
else:
- actual = CGIHTTPServer._url_collapse_path_split(path)
+ actual = CGIHTTPServer._url_collapse_path(path)
self.assertEqual(expected, actual,
msg='path = %r\nGot: %r\nWanted: %r' %
(path, actual, expected))
diff --git a/lib-python/2.7/test/test_imaplib.py b/lib-python/2.7/test/test_imaplib.py
--- a/lib-python/2.7/test/test_imaplib.py
+++ b/lib-python/2.7/test/test_imaplib.py
@@ -79,7 +79,7 @@
return
line += part
except IOError:
- # ..but SSLSockets throw exceptions.
+ # ..but SSLSockets raise exceptions.
return
if line.endswith('\r\n'):
break
diff --git a/lib-python/2.7/test/test_import.py b/lib-python/2.7/test/test_import.py
--- a/lib-python/2.7/test/test_import.py
+++ b/lib-python/2.7/test/test_import.py
@@ -5,6 +5,7 @@
import py_compile
import random
import stat
+import struct
import sys
import unittest
import textwrap
@@ -15,12 +16,23 @@
from test import symlink_support
from test import script_helper
+def _files(name):
+ return (name + os.extsep + "py",
+ name + os.extsep + "pyc",
+ name + os.extsep + "pyo",
+ name + os.extsep + "pyw",
+ name + "$py.class")
+
+def chmod_files(name):
+ for f in _files(name):
+ try:
+ os.chmod(f, 0600)
+ except OSError as exc:
+ if exc.errno != errno.ENOENT:
+ raise
+
def remove_files(name):
- for f in (name + os.extsep + "py",
- name + os.extsep + "pyc",
- name + os.extsep + "pyo",
- name + os.extsep + "pyw",
- name + "$py.class"):
+ for f in _files(name):
unlink(f)
@@ -120,6 +132,40 @@
unload(TESTFN)
del sys.path[0]
+ def test_rewrite_pyc_with_read_only_source(self):
+ # Issue 6074: a long time ago on posix, and more recently on Windows,
+ # a read only source file resulted in a read only pyc file, which
+ # led to problems with updating it later
+ sys.path.insert(0, os.curdir)
+ fname = TESTFN + os.extsep + "py"
+ try:
+ # Write a Python file, make it read-only and import it
+ with open(fname, 'w') as f:
+ f.write("x = 'original'\n")
+ # Tweak the mtime of the source to ensure pyc gets updated later
+ s = os.stat(fname)
+ os.utime(fname, (s.st_atime, s.st_mtime-100000000))
+ os.chmod(fname, 0400)
+ m1 = __import__(TESTFN)
+ self.assertEqual(m1.x, 'original')
+ # Change the file and then reimport it
+ os.chmod(fname, 0600)
+ with open(fname, 'w') as f:
+ f.write("x = 'rewritten'\n")
+ unload(TESTFN)
+ m2 = __import__(TESTFN)
+ self.assertEqual(m2.x, 'rewritten')
+ # Now delete the source file and check the pyc was rewritten
+ unlink(fname)
+ unload(TESTFN)
+ m3 = __import__(TESTFN)
+ self.assertEqual(m3.x, 'rewritten')
+ finally:
+ chmod_files(TESTFN)
+ remove_files(TESTFN)
+ unload(TESTFN)
+ del sys.path[0]
+
def test_imp_module(self):
# Verify that the imp module can correctly load and find .py files
@@ -305,6 +351,46 @@
del sys.path[0]
remove_files(TESTFN)
+ def test_pyc_mtime(self):
+ # Test for issue #13863: .pyc timestamp sometimes incorrect on Windows.
+ sys.path.insert(0, os.curdir)
+ try:
+ # Jan 1, 2012; Jul 1, 2012.
+ mtimes = 1325376000, 1341100800
+
+ # Different names to avoid running into import caching.
+ tails = "spam", "eggs"
+ for mtime, tail in zip(mtimes, tails):
+ module = TESTFN + tail
+ source = module + ".py"
+ compiled = source + ('c' if __debug__ else 'o')
+
+ # Create a new Python file with the given mtime.
+ with open(source, 'w') as f:
+ f.write("# Just testing\nx=1, 2, 3\n")
+ os.utime(source, (mtime, mtime))
+
+ # Generate the .pyc/o file; if it couldn't be created
+ # for some reason, skip the test.
+ m = __import__(module)
+ if not os.path.exists(compiled):
+ unlink(source)
+ self.skipTest("Couldn't create .pyc/.pyo file.")
+
+ # Actual modification time of .py file.
+ mtime1 = int(os.stat(source).st_mtime) & 0xffffffff
+
+ # mtime that was encoded in the .pyc file.
+ with open(compiled, 'rb') as f:
+ mtime2 = struct.unpack('<L', f.read(8)[4:])[0]
+
+ unlink(compiled)
+ unlink(source)
+
+ self.assertEqual(mtime1, mtime2)
+ finally:
+ sys.path.pop(0)
+
class PycRewritingTests(unittest.TestCase):
# Test that the `co_filename` attribute on code objects always points
@@ -427,6 +513,13 @@
drive = path[0]
unc = "\\\\%s\\%s$"%(hn, drive)
unc += path[2:]
+ try:
+ os.listdir(unc)
+ except OSError as e:
+ if e.errno in (errno.EPERM, errno.EACCES):
+ # See issue #15338
+ self.skipTest("cannot access administrative share %r" % (unc,))
+ raise
sys.path.append(path)
mod = __import__("test_trailing_slash")
self.assertEqual(mod.testdata, 'test_trailing_slash')
diff --git a/lib-python/2.7/test/test_int.py b/lib-python/2.7/test/test_int.py
--- a/lib-python/2.7/test/test_int.py
+++ b/lib-python/2.7/test/test_int.py
@@ -1,6 +1,7 @@
import sys
import unittest
+from test import test_support
from test.test_support import run_unittest, have_unicode
import math
@@ -44,7 +45,27 @@
(unichr(0x200), ValueError),
]
-class IntTestCases(unittest.TestCase):
+class IntLongCommonTests(object):
+
+ """Mixin of test cases to share between both test_int and test_long."""
+
+ # Change to int or long in the TestCase subclass.
+ ntype = None
+
+ def test_no_args(self):
+ self.assertEqual(self.ntype(), 0)
+
+ def test_keyword_args(self):
+ # Test invoking constructor using keyword arguments.
+ self.assertEqual(self.ntype(x=1.2), 1)
+ self.assertEqual(self.ntype('100', base=2), 4)
+ self.assertEqual(self.ntype(x='100', base=2), 4)
+ self.assertRaises(TypeError, self.ntype, base=10)
+ self.assertRaises(TypeError, self.ntype, base=0)
+
+class IntTestCases(IntLongCommonTests, unittest.TestCase):
+
+ ntype = int
def test_basic(self):
self.assertEqual(int(314), 314)
@@ -315,6 +336,46 @@
self.assertEqual(int(float(2**54+10)), 2**54+8)
self.assertEqual(int(float(2**54+11)), 2**54+12)
+ def test_valid_non_numeric_input_types_for_x(self):
+ # Test possible valid non-numeric types for x, including subclasses
+ # of the allowed built-in types.
+ class CustomStr(str): pass
+ values = ['100', CustomStr('100')]
+
+ if have_unicode:
+ class CustomUnicode(unicode): pass
+ values += [unicode('100'), CustomUnicode(unicode('100'))]
+
+ for x in values:
+ msg = 'x has value %s and type %s' % (x, type(x).__name__)
+ try:
+ self.assertEqual(int(x), 100, msg=msg)
+ self.assertEqual(int(x, 2), 4, msg=msg)
+ except TypeError, err:
+ raise AssertionError('For %s got TypeError: %s' %
+ (type(x).__name__, err))
+
+ def test_error_on_string_float_for_x(self):
+ self.assertRaises(ValueError, int, '1.2')
+
+ def test_error_on_bytearray_for_x(self):
+ self.assertRaises(TypeError, int, bytearray('100'), 2)
+
+ def test_error_on_invalid_int_bases(self):
+ for base in [-1, 1, 1000]:
+ self.assertRaises(ValueError, int, '100', base)
+
+ def test_error_on_string_base(self):
+ self.assertRaises(TypeError, int, 100, base='foo')
+
+ @test_support.cpython_only
+ def test_small_ints(self):
+ self.assertIs(int('10'), 10)
+ self.assertIs(int('-1'), -1)
+ if have_unicode:
+ self.assertIs(int(u'10'), 10)
+ self.assertIs(int(u'-1'), -1)
+
def test_intconversion(self):
# Test __int__()
class ClassicMissingMethods:
diff --git a/lib-python/2.7/test/test_io.py b/lib-python/2.7/test/test_io.py
--- a/lib-python/2.7/test/test_io.py
+++ b/lib-python/2.7/test/test_io.py
@@ -34,7 +34,9 @@
import errno
from itertools import cycle, count
from collections import deque
+from UserList import UserList
from test import test_support as support
+import contextlib
import codecs
import io # C implementation of io
@@ -572,6 +574,7 @@
raise IOError()
f.flush = bad_flush
self.assertRaises(IOError, f.close) # exception not swallowed
+ self.assertTrue(f.closed)
def test_multi_close(self):
f = self.open(support.TESTFN, "wb", buffering=0)
@@ -593,6 +596,19 @@
self.assertEqual(rawio.read(2), None)
self.assertEqual(rawio.read(2), b"")
+ def test_fileio_closefd(self):
+ # Issue #4841
+ with self.open(__file__, 'rb') as f1, \
+ self.open(__file__, 'rb') as f2:
+ fileio = self.FileIO(f1.fileno(), closefd=False)
+ # .__init__() must not close f1
+ fileio.__init__(f2.fileno(), closefd=False)
+ f1.readline()
+ # .close() must not close f2
+ fileio.close()
+ f2.readline()
+
+
class CIOTest(IOTest):
def test_IOBase_finalize(self):
@@ -718,6 +734,21 @@
raw.flush = bad_flush
b = self.tp(raw)
self.assertRaises(IOError, b.close) # exception not swallowed
+ self.assertTrue(b.closed)
+
+ def test_close_error_on_close(self):
+ raw = self.MockRawIO()
+ def bad_flush():
+ raise IOError('flush')
+ def bad_close():
+ raise IOError('close')
+ raw.close = bad_close
+ b = self.tp(raw)
+ b.flush = bad_flush
+ with self.assertRaises(IOError) as err: # exception not swallowed
+ b.close()
+ self.assertEqual(err.exception.args, ('close',))
+ self.assertFalse(b.closed)
def test_multi_close(self):
raw = self.MockRawIO()
@@ -735,6 +766,20 @@
buf.raw = x
+class SizeofTest:
+
+ @support.cpython_only
+ def test_sizeof(self):
+ bufsize1 = 4096
+ bufsize2 = 8192
+ rawio = self.MockRawIO()
+ bufio = self.tp(rawio, buffer_size=bufsize1)
+ size = sys.getsizeof(bufio) - bufsize1
+ rawio = self.MockRawIO()
+ bufio = self.tp(rawio, buffer_size=bufsize2)
+ self.assertEqual(sys.getsizeof(bufio), size + bufsize2)
+
+
class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
read_mode = "rb"
@@ -918,7 +963,7 @@
"failed for {}: {} != 0".format(n, rawio._extraneous_reads))
-class CBufferedReaderTest(BufferedReaderTest):
+class CBufferedReaderTest(BufferedReaderTest, SizeofTest):
tp = io.BufferedReader
def test_constructor(self):
@@ -959,6 +1004,12 @@
support.gc_collect()
self.assertTrue(wr() is None, wr)
+ def test_args_error(self):
+ # Issue #17275
+ with self.assertRaisesRegexp(TypeError, "BufferedReader"):
+ self.tp(io.BytesIO(), 1024, 1024, 1024)
+
+
class PyBufferedReaderTest(BufferedReaderTest):
tp = pyio.BufferedReader
@@ -1099,6 +1150,28 @@
bufio.flush()
self.assertEqual(b"abc", writer._write_stack[0])
+ def test_writelines(self):
+ l = [b'ab', b'cd', b'ef']
+ writer = self.MockRawIO()
+ bufio = self.tp(writer, 8)
+ bufio.writelines(l)
+ bufio.flush()
+ self.assertEqual(b''.join(writer._write_stack), b'abcdef')
+
+ def test_writelines_userlist(self):
+ l = UserList([b'ab', b'cd', b'ef'])
+ writer = self.MockRawIO()
+ bufio = self.tp(writer, 8)
+ bufio.writelines(l)
+ bufio.flush()
+ self.assertEqual(b''.join(writer._write_stack), b'abcdef')
+
+ def test_writelines_error(self):
+ writer = self.MockRawIO()
+ bufio = self.tp(writer, 8)
+ self.assertRaises(TypeError, bufio.writelines, [1, 2, 3])
+ self.assertRaises(TypeError, bufio.writelines, None)
+
def test_destructor(self):
writer = self.MockRawIO()
bufio = self.tp(writer, 8)
@@ -1180,8 +1253,18 @@
DeprecationWarning)):
self.tp(self.MockRawIO(), 8, 12)
-
-class CBufferedWriterTest(BufferedWriterTest):
+ def test_write_error_on_close(self):
+ raw = self.MockRawIO()
+ def bad_write(b):
+ raise IOError()
+ raw.write = bad_write
+ b = self.tp(raw)
+ b.write(b'spam')
+ self.assertRaises(IOError, b.close) # exception not swallowed
+ self.assertTrue(b.closed)
+
+
+class CBufferedWriterTest(BufferedWriterTest, SizeofTest):
tp = io.BufferedWriter
def test_constructor(self):
@@ -1219,6 +1302,11 @@
with self.open(support.TESTFN, "rb") as f:
self.assertEqual(f.read(), b"123xxx")
+ def test_args_error(self):
+ # Issue #17275
+ with self.assertRaisesRegexp(TypeError, "BufferedWriter"):
+ self.tp(io.BytesIO(), 1024, 1024, 1024)
+
class PyBufferedWriterTest(BufferedWriterTest):
tp = pyio.BufferedWriter
@@ -1570,7 +1658,8 @@
self.assertEqual(raw.getvalue(), b'1b\n2def\n3\n')
-class CBufferedRandomTest(CBufferedReaderTest, CBufferedWriterTest, BufferedRandomTest):
+class CBufferedRandomTest(CBufferedReaderTest, CBufferedWriterTest,
+ BufferedRandomTest, SizeofTest):
tp = io.BufferedRandom
def test_constructor(self):
@@ -1587,6 +1676,12 @@
CBufferedReaderTest.test_garbage_collection(self)
CBufferedWriterTest.test_garbage_collection(self)
+ def test_args_error(self):
+ # Issue #17275
+ with self.assertRaisesRegexp(TypeError, "BufferedRandom"):
+ self.tp(io.BytesIO(), 1024, 1024, 1024)
+
+
class PyBufferedRandomTest(BufferedRandomTest):
tp = pyio.BufferedRandom
@@ -2183,6 +2278,28 @@
reads += c
self.assertEqual(reads, "A"*127+"\nB")
+ def test_writelines(self):
+ l = ['ab', 'cd', 'ef']
+ buf = self.BytesIO()
+ txt = self.TextIOWrapper(buf)
+ txt.writelines(l)
+ txt.flush()
+ self.assertEqual(buf.getvalue(), b'abcdef')
+
+ def test_writelines_userlist(self):
+ l = UserList(['ab', 'cd', 'ef'])
+ buf = self.BytesIO()
+ txt = self.TextIOWrapper(buf)
+ txt.writelines(l)
+ txt.flush()
+ self.assertEqual(buf.getvalue(), b'abcdef')
+
+ def test_writelines_error(self):
+ txt = self.TextIOWrapper(self.BytesIO())
+ self.assertRaises(TypeError, txt.writelines, [1, 2, 3])
+ self.assertRaises(TypeError, txt.writelines, None)
+ self.assertRaises(TypeError, txt.writelines, b'abc')
+
def test_issue1395_1(self):
txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii")
@@ -2306,6 +2423,7 @@
raise IOError()
txt.flush = bad_flush
self.assertRaises(IOError, txt.close) # exception not swallowed
+ self.assertTrue(txt.closed)
def test_multi_close(self):
txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii")
@@ -2320,6 +2438,39 @@
with self.assertRaises((AttributeError, TypeError)):
txt.buffer = buf
+ def test_read_nonbytes(self):
+ # Issue #17106
+ # Crash when underlying read() returns non-bytes
+ class NonbytesStream(self.StringIO):
+ read1 = self.StringIO.read
+ class NonbytesStream(self.StringIO):
+ read1 = self.StringIO.read
+ t = self.TextIOWrapper(NonbytesStream('a'))
+ with self.maybeRaises(TypeError):
+ t.read(1)
+ t = self.TextIOWrapper(NonbytesStream('a'))
+ with self.maybeRaises(TypeError):
+ t.readline()
+ t = self.TextIOWrapper(NonbytesStream('a'))
+ self.assertEqual(t.read(), u'a')
+
+ def test_illegal_decoder(self):
+ # Issue #17106
+ # Crash when decoder returns non-string
+ t = self.TextIOWrapper(self.BytesIO(b'aaaaaa'), newline='\n',
+ encoding='quopri_codec')
+ with self.maybeRaises(TypeError):
+ t.read(1)
+ t = self.TextIOWrapper(self.BytesIO(b'aaaaaa'), newline='\n',
+ encoding='quopri_codec')
+ with self.maybeRaises(TypeError):
+ t.readline()
+ t = self.TextIOWrapper(self.BytesIO(b'aaaaaa'), newline='\n',
+ encoding='quopri_codec')
+ with self.maybeRaises(TypeError):
+ t.read()
+
+
class CTextIOWrapperTest(TextIOWrapperTest):
def test_initialization(self):
@@ -2361,9 +2512,13 @@
t2.buddy = t1
support.gc_collect()
+ maybeRaises = unittest.TestCase.assertRaises
+
class PyTextIOWrapperTest(TextIOWrapperTest):
- pass
+ @contextlib.contextmanager
+ def maybeRaises(self, *args, **kwds):
+ yield
class IncrementalNewlineDecoderTest(unittest.TestCase):
diff --git a/lib-python/2.7/test/test_iter.py b/lib-python/2.7/test/test_iter.py
--- a/lib-python/2.7/test/test_iter.py
+++ b/lib-python/2.7/test/test_iter.py
@@ -908,6 +908,21 @@
except TypeError:
pass
+ def test_extending_list_with_iterator_does_not_segfault(self):
+ # The code to extend a list with an iterator has a fair
+ # amount of nontrivial logic in terms of guessing how
+ # much memory to allocate in advance, "stealing" refs,
+ # and then shrinking at the end. This is a basic smoke
+ # test for that scenario.
+ def gen():
+ for i in range(500):
+ yield i
+ lst = [0] * 500
+ for i in range(240):
+ lst.pop(0)
+ lst.extend(gen())
+ self.assertEqual(len(lst), 760)
+
def test_main():
run_unittest(TestCase)
diff --git a/lib-python/2.7/test/test_itertools.py b/lib-python/2.7/test/test_itertools.py
--- a/lib-python/2.7/test/test_itertools.py
+++ b/lib-python/2.7/test/test_itertools.py
@@ -906,6 +906,12 @@
del a
self.assertRaises(ReferenceError, getattr, p, '__class__')
+ # Issue 13454: Crash when deleting backward iterator from tee()
+ def test_tee_del_backward(self):
+ forward, backward = tee(repeat(None, 20000000))
+ any(forward) # exhaust the iterator
+ del backward
+
def test_StopIteration(self):
self.assertRaises(StopIteration, izip().next)
diff --git a/lib-python/2.7/test/test_logging.py b/lib-python/2.7/test/test_logging.py
--- a/lib-python/2.7/test/test_logging.py
+++ b/lib-python/2.7/test/test_logging.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2001-2010 by Vinay Sajip. All Rights Reserved.
+# Copyright 2001-2012 by Vinay Sajip. All Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
@@ -18,7 +18,7 @@
"""Test harness for the logging module. Run all tests.
-Copyright (C) 2001-2010 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2012 Vinay Sajip. All Rights Reserved.
"""
import logging
@@ -31,6 +31,7 @@
import gc
import json
import os
+import random
import re
import select
import socket
@@ -40,6 +41,7 @@
import tempfile
from test.test_support import captured_stdout, run_with_locale, run_unittest
import textwrap
+import time
import unittest
import warnings
import weakref
@@ -1873,6 +1875,47 @@
self.assertTrue(c2 is c3)
+class HandlerTest(BaseTest):
+
+ @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.')
+ @unittest.skipUnless(threading, 'Threading required for this test.')
+ def test_race(self):
+ # Issue #14632 refers.
+ def remove_loop(fname, tries):
+ for _ in range(tries):
+ try:
+ os.unlink(fname)
+ except OSError:
+ pass
+ time.sleep(0.004 * random.randint(0, 4))
+
+ del_count = 500
+ log_count = 500
+
+ for delay in (False, True):
+ fd, fn = tempfile.mkstemp('.log', 'test_logging-3-')
+ os.close(fd)
+ remover = threading.Thread(target=remove_loop, args=(fn, del_count))
+ remover.daemon = True
+ remover.start()
+ h = logging.handlers.WatchedFileHandler(fn, delay=delay)
+ f = logging.Formatter('%(asctime)s: %(levelname)s: %(message)s')
+ h.setFormatter(f)
+ try:
+ for _ in range(log_count):
+ time.sleep(0.005)
+ r = logging.makeLogRecord({'msg': 'testing' })
+ h.handle(r)
+ finally:
+ remover.join()
+ try:
+ h.close()
+ except ValueError:
+ pass
+ if os.path.exists(fn):
+ os.unlink(fn)
+
+
# Set the locale to the platform-dependent default. I have no idea
# why the test does this, but in any case we save the current locale
# first and restore it at the end.
@@ -1882,7 +1925,7 @@
CustomLevelsAndFiltersTest, MemoryHandlerTest,
ConfigFileTest, SocketHandlerTest, MemoryTest,
EncodingTest, WarningsTest, ConfigDictTest, ManagerTest,
- ChildLoggerTest)
+ ChildLoggerTest, HandlerTest)
if __name__ == "__main__":
test_main()
diff --git a/lib-python/2.7/test/test_long.py b/lib-python/2.7/test/test_long.py
--- a/lib-python/2.7/test/test_long.py
+++ b/lib-python/2.7/test/test_long.py
@@ -1,10 +1,11 @@
import unittest
-from test import test_support
import sys
import random
import math
+from test import test_int, test_support
+
# Used for lazy formatting of failure messages
class Frm(object):
def __init__(self, format, *args):
@@ -78,8 +79,9 @@
(unichr(0x200), ValueError),
]
+class LongTest(test_int.IntLongCommonTests, unittest.TestCase):
-class LongTest(unittest.TestCase):
+ ntype = long
# Get quasi-random long consisting of ndigits digits (in base BASE).
# quasi == the most-significant digit will not be 0, and the number
diff --git a/lib-python/2.7/test/test_mailbox.py b/lib-python/2.7/test/test_mailbox.py
--- a/lib-python/2.7/test/test_mailbox.py
+++ b/lib-python/2.7/test/test_mailbox.py
@@ -8,6 +8,7 @@
import re
import shutil
import StringIO
+import tempfile
from test import test_support
import unittest
import mailbox
@@ -20,7 +21,7 @@
# Silence Py3k warning
rfc822 = test_support.import_module('rfc822', deprecated=True)
-class TestBase(unittest.TestCase):
+class TestBase:
def _check_sample(self, msg):
# Inspect a mailbox.Message representation of the sample message
@@ -39,15 +40,15 @@
def _delete_recursively(self, target):
# Delete a file or delete a directory recursively
if os.path.isdir(target):
- shutil.rmtree(target)
+ test_support.rmtree(target)
elif os.path.exists(target):
- os.remove(target)
+ test_support.unlink(target)
class TestMailbox(TestBase):
_factory = None # Overridden by subclasses to reuse tests
- _template = 'From: foo\n\n%s'
+ _template = 'From: foo\n\n%s\n'
def setUp(self):
self._path = test_support.TESTFN
@@ -75,6 +76,18 @@
for i in (1, 2, 3, 4):
self._check_sample(self._box[keys[i]])
+ def test_add_file(self):
+ with tempfile.TemporaryFile('w+') as f:
+ f.write(_sample_message)
+ f.seek(0)
+ key = self._box.add(f)
+ self.assertEqual(self._box.get_string(key).split('\n'),
+ _sample_message.split('\n'))
+
+ def test_add_StringIO(self):
+ key = self._box.add(StringIO.StringIO(self._template % "0"))
+ self.assertEqual(self._box.get_string(key), self._template % "0")
+
def test_remove(self):
# Remove messages using remove()
self._test_remove_or_delitem(self._box.remove)
@@ -124,7 +137,7 @@
key0 = self._box.add(self._template % 0)
msg = self._box.get(key0)
self.assertEqual(msg['from'], 'foo')
- self.assertEqual(msg.get_payload(), '0')
+ self.assertEqual(msg.get_payload(), '0\n')
self.assertIs(self._box.get('foo'), None)
self.assertFalse(self._box.get('foo', False))
self._box.close()
@@ -132,14 +145,15 @@
key1 = self._box.add(self._template % 1)
msg = self._box.get(key1)
self.assertEqual(msg['from'], 'foo')
- self.assertEqual(msg.fp.read(), '1')
+ self.assertEqual(msg.fp.read(), '1' + os.linesep)
+ msg.fp.close()
def test_getitem(self):
# Retrieve message using __getitem__()
key0 = self._box.add(self._template % 0)
msg = self._box[key0]
self.assertEqual(msg['from'], 'foo')
- self.assertEqual(msg.get_payload(), '0')
+ self.assertEqual(msg.get_payload(), '0\n')
self.assertRaises(KeyError, lambda: self._box['foo'])
self._box.discard(key0)
self.assertRaises(KeyError, lambda: self._box[key0])
@@ -151,7 +165,7 @@
msg0 = self._box.get_message(key0)
self.assertIsInstance(msg0, mailbox.Message)
self.assertEqual(msg0['from'], 'foo')
- self.assertEqual(msg0.get_payload(), '0')
+ self.assertEqual(msg0.get_payload(), '0\n')
self._check_sample(self._box.get_message(key1))
def test_get_string(self):
@@ -165,10 +179,14 @@
# Get file representations of messages
key0 = self._box.add(self._template % 0)
key1 = self._box.add(_sample_message)
- self.assertEqual(self._box.get_file(key0).read().replace(os.linesep, '\n'),
+ msg0 = self._box.get_file(key0)
+ self.assertEqual(msg0.read().replace(os.linesep, '\n'),
self._template % 0)
- self.assertEqual(self._box.get_file(key1).read().replace(os.linesep, '\n'),
+ msg1 = self._box.get_file(key1)
+ self.assertEqual(msg1.read().replace(os.linesep, '\n'),
_sample_message)
+ msg0.close()
+ msg1.close()
def test_get_file_can_be_closed_twice(self):
# Issue 11700
@@ -320,15 +338,15 @@
self.assertIn(key0, self._box)
key1 = self._box.add(self._template % 1)
self.assertIn(key1, self._box)
- self.assertEqual(self._box.pop(key0).get_payload(), '0')
+ self.assertEqual(self._box.pop(key0).get_payload(), '0\n')
self.assertNotIn(key0, self._box)
self.assertIn(key1, self._box)
key2 = self._box.add(self._template % 2)
self.assertIn(key2, self._box)
- self.assertEqual(self._box.pop(key2).get_payload(), '2')
+ self.assertEqual(self._box.pop(key2).get_payload(), '2\n')
self.assertNotIn(key2, self._box)
self.assertIn(key1, self._box)
- self.assertEqual(self._box.pop(key1).get_payload(), '1')
+ self.assertEqual(self._box.pop(key1).get_payload(), '1\n')
self.assertNotIn(key1, self._box)
self.assertEqual(len(self._box), 0)
@@ -386,6 +404,17 @@
# Write changes to disk
self._test_flush_or_close(self._box.flush, True)
+ def test_popitem_and_flush_twice(self):
+ # See #15036.
+ self._box.add(self._template % 0)
+ self._box.add(self._template % 1)
+ self._box.flush()
+
+ self._box.popitem()
+ self._box.flush()
+ self._box.popitem()
+ self._box.flush()
+
def test_lock_unlock(self):
# Lock and unlock the mailbox
self.assertFalse(os.path.exists(self._get_lock_path()))
@@ -403,6 +432,7 @@
self._box.add(contents[0])
self._box.add(contents[1])
self._box.add(contents[2])
+ oldbox = self._box
method()
if should_call_close:
self._box.close()
@@ -411,6 +441,7 @@
self.assertEqual(len(keys), 3)
for key in keys:
self.assertIn(self._box.get_string(key), contents)
+ oldbox.close()
def test_dump_message(self):
# Write message representations to disk
@@ -429,7 +460,7 @@
return self._path + '.lock'
-class TestMailboxSuperclass(TestBase):
+class TestMailboxSuperclass(TestBase, unittest.TestCase):
def test_notimplemented(self):
# Test that all Mailbox methods raise NotImplementedException.
@@ -464,7 +495,7 @@
self.assertRaises(NotImplementedError, lambda: box.close())
-class TestMaildir(TestMailbox):
+class TestMaildir(TestMailbox, unittest.TestCase):
_factory = lambda self, path, factory=None: mailbox.Maildir(path, factory)
@@ -506,7 +537,7 @@
msg_returned = self._box.get_message(key)
self.assertEqual(msg_returned.get_subdir(), 'new')
self.assertEqual(msg_returned.get_flags(), '')
- self.assertEqual(msg_returned.get_payload(), '1')
+ self.assertEqual(msg_returned.get_payload(), '1\n')
msg2 = mailbox.MaildirMessage(self._template % 2)
msg2.set_info('2,S')
self._box[key] = msg2
@@ -514,7 +545,7 @@
msg_returned = self._box.get_message(key)
self.assertEqual(msg_returned.get_subdir(), 'new')
self.assertEqual(msg_returned.get_flags(), 'S')
- self.assertEqual(msg_returned.get_payload(), '3')
+ self.assertEqual(msg_returned.get_payload(), '3\n')
def test_consistent_factory(self):
# Add a message.
@@ -636,13 +667,13 @@
self.assertTrue(match is not None, "Invalid file name: '%s'" % tail)
groups = match.groups()
if previous_groups is not None:
- self.assertTrue(int(groups[0] >= previous_groups[0]),
+ self.assertGreaterEqual(int(groups[0]), int(previous_groups[0]),
"Non-monotonic seconds: '%s' before '%s'" %
(previous_groups[0], groups[0]))
- self.assertTrue(int(groups[1] >= previous_groups[1]) or
- groups[0] != groups[1],
- "Non-monotonic milliseconds: '%s' before '%s'" %
- (previous_groups[1], groups[1]))
+ if int(groups[0]) == int(previous_groups[0]):
+ self.assertGreaterEqual(int(groups[1]), int(previous_groups[1]),
+ "Non-monotonic milliseconds: '%s' before '%s'" %
+ (previous_groups[1], groups[1]))
self.assertTrue(int(groups[2]) == pid,
"Process ID mismatch: '%s' should be '%s'" %
(groups[2], pid))
@@ -813,7 +844,49 @@
self._box._refresh()
self.assertTrue(refreshed())
-class _TestMboxMMDF(TestMailbox):
+
+class _TestSingleFile(TestMailbox):
+ '''Common tests for single-file mailboxes'''
+
+ def test_add_doesnt_rewrite(self):
+ # When only adding messages, flush() should not rewrite the
+ # mailbox file. See issue #9559.
+
+ # Inode number changes if the contents are written to another
+ # file which is then renamed over the original file. So we
+ # must check that the inode number doesn't change.
+ inode_before = os.stat(self._path).st_ino
+
+ self._box.add(self._template % 0)
+ self._box.flush()
+
+ inode_after = os.stat(self._path).st_ino
+ self.assertEqual(inode_before, inode_after)
+
+ # Make sure the message was really added
+ self._box.close()
+ self._box = self._factory(self._path)
+ self.assertEqual(len(self._box), 1)
+
+ def test_permissions_after_flush(self):
+ # See issue #5346
+
+ # Make the mailbox world writable. It's unlikely that the new
+ # mailbox file would have these permissions after flush(),
+ # because umask usually prevents it.
+ mode = os.stat(self._path).st_mode | 0o666
+ os.chmod(self._path, mode)
+
+ self._box.add(self._template % 0)
+ i = self._box.add(self._template % 1)
+ # Need to remove one message to make flush() create a new file
+ self._box.remove(i)
+ self._box.flush()
+
+ self.assertEqual(os.stat(self._path).st_mode, mode)
+
+
+class _TestMboxMMDF(_TestSingleFile):
def tearDown(self):
self._box.close()
@@ -823,14 +896,14 @@
def test_add_from_string(self):
# Add a string starting with 'From ' to the mailbox
- key = self._box.add('From foo at bar blah\nFrom: foo\n\n0')
+ key = self._box.add('From foo at bar blah\nFrom: foo\n\n0\n')
self.assertEqual(self._box[key].get_from(), 'foo at bar blah')
- self.assertEqual(self._box[key].get_payload(), '0')
+ self.assertEqual(self._box[key].get_payload(), '0\n')
def test_add_mbox_or_mmdf_message(self):
# Add an mboxMessage or MMDFMessage
for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage):
- msg = class_('From foo at bar blah\nFrom: foo\n\n0')
+ msg = class_('From foo at bar blah\nFrom: foo\n\n0\n')
key = self._box.add(msg)
def test_open_close_open(self):
@@ -914,7 +987,7 @@
self._box.close()
-class TestMbox(_TestMboxMMDF):
+class TestMbox(_TestMboxMMDF, unittest.TestCase):
_factory = lambda self, path, factory=None: mailbox.mbox(path, factory)
@@ -937,12 +1010,35 @@
perms = st.st_mode
self.assertFalse((perms & 0111)) # Execute bits should all be off.
-class TestMMDF(_TestMboxMMDF):
+ def test_terminating_newline(self):
+ message = email.message.Message()
+ message['From'] = 'john at example.com'
+ message.set_payload('No newline at the end')
+ i = self._box.add(message)
+
+ # A newline should have been appended to the payload
+ message = self._box.get(i)
+ self.assertEqual(message.get_payload(), 'No newline at the end\n')
+
+ def test_message_separator(self):
+ # Check there's always a single blank line after each message
+ self._box.add('From: foo\n\n0') # No newline at the end
+ with open(self._path) as f:
+ data = f.read()
+ self.assertEqual(data[-3:], '0\n\n')
+
+ self._box.add('From: foo\n\n0\n') # Newline at the end
+ with open(self._path) as f:
+ data = f.read()
+ self.assertEqual(data[-3:], '0\n\n')
+
+
+class TestMMDF(_TestMboxMMDF, unittest.TestCase):
_factory = lambda self, path, factory=None: mailbox.MMDF(path, factory)
-class TestMH(TestMailbox):
+class TestMH(TestMailbox, unittest.TestCase):
_factory = lambda self, path, factory=None: mailbox.MH(path, factory)
@@ -1074,7 +1170,7 @@
return os.path.join(self._path, '.mh_sequences.lock')
-class TestBabyl(TestMailbox):
+class TestBabyl(_TestSingleFile, unittest.TestCase):
_factory = lambda self, path, factory=None: mailbox.Babyl(path, factory)
@@ -1103,7 +1199,7 @@
self.assertEqual(set(self._box.get_labels()), set(['blah']))
-class TestMessage(TestBase):
+class TestMessage(TestBase, unittest.TestCase):
_factory = mailbox.Message # Overridden by subclasses to reuse tests
@@ -1174,7 +1270,7 @@
pass
-class TestMaildirMessage(TestMessage):
+class TestMaildirMessage(TestMessage, unittest.TestCase):
_factory = mailbox.MaildirMessage
@@ -1249,7 +1345,7 @@
self._check_sample(msg)
-class _TestMboxMMDFMessage(TestMessage):
+class _TestMboxMMDFMessage:
_factory = mailbox._mboxMMDFMessage
@@ -1296,12 +1392,12 @@
r"\d{2} \d{4}", msg.get_from()))
-class TestMboxMessage(_TestMboxMMDFMessage):
+class TestMboxMessage(_TestMboxMMDFMessage, TestMessage):
_factory = mailbox.mboxMessage
-class TestMHMessage(TestMessage):
+class TestMHMessage(TestMessage, unittest.TestCase):
_factory = mailbox.MHMessage
@@ -1332,7 +1428,7 @@
self.assertEqual(msg.get_sequences(), ['foobar', 'replied'])
-class TestBabylMessage(TestMessage):
+class TestBabylMessage(TestMessage, unittest.TestCase):
_factory = mailbox.BabylMessage
@@ -1387,12 +1483,12 @@
self.assertEqual(visible[header], msg[header])
-class TestMMDFMessage(_TestMboxMMDFMessage):
+class TestMMDFMessage(_TestMboxMMDFMessage, TestMessage):
_factory = mailbox.MMDFMessage
-class TestMessageConversion(TestBase):
+class TestMessageConversion(TestBase, unittest.TestCase):
def test_plain_to_x(self):
# Convert Message to all formats
@@ -1715,7 +1811,7 @@
proxy.close()
-class TestProxyFile(TestProxyFileBase):
+class TestProxyFile(TestProxyFileBase, unittest.TestCase):
def setUp(self):
self._path = test_support.TESTFN
@@ -1764,7 +1860,7 @@
self._test_close(mailbox._ProxyFile(self._file))
-class TestPartialFile(TestProxyFileBase):
+class TestPartialFile(TestProxyFileBase, unittest.TestCase):
def setUp(self):
self._path = test_support.TESTFN
@@ -1831,6 +1927,10 @@
def setUp(self):
# create a new maildir mailbox to work with:
self._dir = test_support.TESTFN
+ if os.path.isdir(self._dir):
+ test_support.rmtree(self._dir)
+ if os.path.isfile(self._dir):
+ test_support.unlink(self._dir)
os.mkdir(self._dir)
os.mkdir(os.path.join(self._dir, "cur"))
os.mkdir(os.path.join(self._dir, "tmp"))
@@ -1840,10 +1940,10 @@
def tearDown(self):
map(os.unlink, self._msgfiles)
- os.rmdir(os.path.join(self._dir, "cur"))
- os.rmdir(os.path.join(self._dir, "tmp"))
- os.rmdir(os.path.join(self._dir, "new"))
- os.rmdir(self._dir)
+ test_support.rmdir(os.path.join(self._dir, "cur"))
+ test_support.rmdir(os.path.join(self._dir, "tmp"))
+ test_support.rmdir(os.path.join(self._dir, "new"))
+ test_support.rmdir(self._dir)
def createMessage(self, dir, mbox=False):
t = int(time.time() % 1000000)
@@ -1879,7 +1979,9 @@
self.createMessage("cur")
self.mbox = mailbox.Maildir(test_support.TESTFN)
#self.assertTrue(len(self.mbox.boxes) == 1)
- self.assertIsNot(self.mbox.next(), None)
+ msg = self.mbox.next()
+ self.assertIsNot(msg, None)
+ msg.fp.close()
self.assertIs(self.mbox.next(), None)
self.assertIs(self.mbox.next(), None)
@@ -1887,7 +1989,9 @@
self.createMessage("new")
self.mbox = mailbox.Maildir(test_support.TESTFN)
#self.assertTrue(len(self.mbox.boxes) == 1)
- self.assertIsNot(self.mbox.next(), None)
+ msg = self.mbox.next()
+ self.assertIsNot(msg, None)
+ msg.fp.close()
self.assertIs(self.mbox.next(), None)
self.assertIs(self.mbox.next(), None)
@@ -1896,8 +2000,12 @@
self.createMessage("new")
self.mbox = mailbox.Maildir(test_support.TESTFN)
#self.assertTrue(len(self.mbox.boxes) == 2)
- self.assertIsNot(self.mbox.next(), None)
- self.assertIsNot(self.mbox.next(), None)
+ msg = self.mbox.next()
+ self.assertIsNot(msg, None)
+ msg.fp.close()
+ msg = self.mbox.next()
+ self.assertIsNot(msg, None)
+ msg.fp.close()
self.assertIs(self.mbox.next(), None)
self.assertIs(self.mbox.next(), None)
@@ -1906,11 +2014,13 @@
import email.parser
fname = self.createMessage("cur", True)
n = 0
- for msg in mailbox.PortableUnixMailbox(open(fname),
+ fid = open(fname)
+ for msg in mailbox.PortableUnixMailbox(fid,
email.parser.Parser().parse):
n += 1
self.assertEqual(msg["subject"], "Simple Test")
self.assertEqual(len(str(msg)), len(FROM_)+len(DUMMY_MESSAGE))
+ fid.close()
self.assertEqual(n, 1)
## End: classes from the original module (for backward compatibility).
diff --git a/lib-python/2.7/test/test_marshal.py b/lib-python/2.7/test/test_marshal.py
--- a/lib-python/2.7/test/test_marshal.py
+++ b/lib-python/2.7/test/test_marshal.py
@@ -269,6 +269,53 @@
invalid_string = 'l\x02\x00\x00\x00\x00\x00\x00\x00'
self.assertRaises(ValueError, marshal.loads, invalid_string)
+LARGE_SIZE = 2**31
+character_size = 4 if sys.maxunicode > 0xFFFF else 2
+pointer_size = 8 if sys.maxsize > 0xFFFFFFFF else 4
+
+ at unittest.skipIf(LARGE_SIZE > sys.maxsize, "test cannot run on 32-bit systems")
+class LargeValuesTestCase(unittest.TestCase):
+ def check_unmarshallable(self, data):
+ f = open(test_support.TESTFN, 'wb')
+ self.addCleanup(test_support.unlink, test_support.TESTFN)
+ with f:
+ self.assertRaises(ValueError, marshal.dump, data, f)
+
+ @test_support.precisionbigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False)
+ def test_string(self, size):
+ self.check_unmarshallable('x' * size)
+
+ @test_support.precisionbigmemtest(size=LARGE_SIZE,
+ memuse=character_size, dry_run=False)
+ def test_unicode(self, size):
+ self.check_unmarshallable(u'x' * size)
+
+ @test_support.precisionbigmemtest(size=LARGE_SIZE,
+ memuse=pointer_size, dry_run=False)
+ def test_tuple(self, size):
+ self.check_unmarshallable((None,) * size)
+
+ @test_support.precisionbigmemtest(size=LARGE_SIZE,
+ memuse=pointer_size, dry_run=False)
+ def test_list(self, size):
+ self.check_unmarshallable([None] * size)
+
+ @test_support.precisionbigmemtest(size=LARGE_SIZE,
+ memuse=pointer_size*12 + sys.getsizeof(LARGE_SIZE-1),
+ dry_run=False)
+ def test_set(self, size):
+ self.check_unmarshallable(set(range(size)))
+
+ @test_support.precisionbigmemtest(size=LARGE_SIZE,
+ memuse=pointer_size*12 + sys.getsizeof(LARGE_SIZE-1),
+ dry_run=False)
+ def test_frozenset(self, size):
+ self.check_unmarshallable(frozenset(range(size)))
+
+ @test_support.precisionbigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False)
+ def test_bytearray(self, size):
+ self.check_unmarshallable(bytearray(size))
+
def test_main():
test_support.run_unittest(IntTestCase,
@@ -277,7 +324,9 @@
CodeTestCase,
ContainerTestCase,
ExceptionTestCase,
- BugsTestCase)
+ BugsTestCase,
+ LargeValuesTestCase,
+ )
if __name__ == "__main__":
test_main()
diff --git a/lib-python/2.7/test/test_memoryio.py b/lib-python/2.7/test/test_memoryio.py
--- a/lib-python/2.7/test/test_memoryio.py
+++ b/lib-python/2.7/test/test_memoryio.py
@@ -328,9 +328,9 @@
self.assertEqual(memio.isatty(), False)
self.assertEqual(memio.closed, False)
memio.close()
- self.assertEqual(memio.writable(), True)
- self.assertEqual(memio.readable(), True)
- self.assertEqual(memio.seekable(), True)
+ self.assertRaises(ValueError, memio.writable)
+ self.assertRaises(ValueError, memio.readable)
+ self.assertRaises(ValueError, memio.seekable)
self.assertRaises(ValueError, memio.isatty)
self.assertEqual(memio.closed, True)
@@ -638,6 +638,16 @@
memio.close()
self.assertRaises(ValueError, memio.__setstate__, (b"closed", 0, None))
+ check_sizeof = support.check_sizeof
+
+ @support.cpython_only
+ def test_sizeof(self):
+ basesize = support.calcobjsize(b'P2PP2P')
+ check = self.check_sizeof
+ self.assertEqual(object.__sizeof__(io.BytesIO()), basesize)
+ check(io.BytesIO(), basesize )
+ check(io.BytesIO(b'a'), basesize + 1 + 1 )
+ check(io.BytesIO(b'a' * 1000), basesize + 1000 + 1 )
class CStringIOTest(PyStringIOTest):
ioclass = io.StringIO
diff --git a/lib-python/2.7/test/test_minidom.py b/lib-python/2.7/test/test_minidom.py
--- a/lib-python/2.7/test/test_minidom.py
+++ b/lib-python/2.7/test/test_minidom.py
@@ -1060,7 +1060,7 @@
'<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>',
"testEncodings - encoding EURO SIGN")
- # Verify that character decoding errors throw exceptions instead
+ # Verify that character decoding errors raise exceptions instead
# of crashing
self.assertRaises(UnicodeDecodeError, parseString,
'<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
diff --git a/lib-python/2.7/test/test_mmap.py b/lib-python/2.7/test/test_mmap.py
--- a/lib-python/2.7/test/test_mmap.py
+++ b/lib-python/2.7/test/test_mmap.py
@@ -466,6 +466,19 @@
f.flush ()
return mmap.mmap (f.fileno(), 0)
+ def test_empty_file (self):
+ f = open (TESTFN, 'w+b')
+ f.close()
+ with open(TESTFN, "rb") as f :
+ try:
+ m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
+ m.close()
+ self.fail("should not have been able to mmap empty file")
+ except ValueError as e:
+ self.assertEqual(e.message, "cannot mmap an empty file")
+ except:
+ self.fail("unexpected exception: " + str(e))
+
def test_offset (self):
f = open (TESTFN, 'w+b')
@@ -669,6 +682,13 @@
def test_large_filesize(self):
with self._make_test_file(0x17FFFFFFF, b" ") as f:
+ if sys.maxsize < 0x180000000:
+ # On 32 bit platforms the file is larger than sys.maxsize so
+ # mapping the whole file should fail -- Issue #16743
+ with self.assertRaises(OverflowError):
+ mmap.mmap(f.fileno(), 0x180000000, access=mmap.ACCESS_READ)
+ with self.assertRaises(ValueError):
+ mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ)
try:
self.assertEqual(m.size(), 0x180000000)
diff --git a/lib-python/2.7/test/test_multiprocessing.py b/lib-python/2.7/test/test_multiprocessing.py
--- a/lib-python/2.7/test/test_multiprocessing.py
+++ b/lib-python/2.7/test/test_multiprocessing.py
@@ -16,6 +16,7 @@
import random
import logging
import errno
+import test.script_helper
from test import test_support
from StringIO import StringIO
_multiprocessing = test_support.import_module('_multiprocessing')
@@ -325,6 +326,36 @@
]
self.assertEqual(result, expected)
+ @classmethod
+ def _test_sys_exit(cls, reason, testfn):
+ sys.stderr = open(testfn, 'w')
+ sys.exit(reason)
+
+ def test_sys_exit(self):
+ # See Issue 13854
+ if self.TYPE == 'threads':
+ return
+
+ testfn = test_support.TESTFN
+ self.addCleanup(test_support.unlink, testfn)
+
+ for reason, code in (([1, 2, 3], 1), ('ignore this', 0)):
+ p = self.Process(target=self._test_sys_exit, args=(reason, testfn))
+ p.daemon = True
+ p.start()
+ p.join(5)
+ self.assertEqual(p.exitcode, code)
+
+ with open(testfn, 'r') as f:
+ self.assertEqual(f.read().rstrip(), str(reason))
+
+ for reason in (True, False, 8):
+ p = self.Process(target=sys.exit, args=(reason,))
+ p.daemon = True
+ p.start()
+ p.join(5)
+ self.assertEqual(p.exitcode, reason)
+
#
#
#
@@ -1152,6 +1183,36 @@
join()
self.assertTrue(join.elapsed < 0.2)
+ def test_empty_iterable(self):
+ # See Issue 12157
+ p = self.Pool(1)
+
+ self.assertEqual(p.map(sqr, []), [])
+ self.assertEqual(list(p.imap(sqr, [])), [])
+ self.assertEqual(list(p.imap_unordered(sqr, [])), [])
+ self.assertEqual(p.map_async(sqr, []).get(), [])
+
+ p.close()
+ p.join()
+
+def unpickleable_result():
+ return lambda: 42
+
+class _TestPoolWorkerErrors(BaseTestCase):
+ ALLOWED_TYPES = ('processes', )
+
+ def test_unpickleable_result(self):
+ from multiprocessing.pool import MaybeEncodingError
+ p = multiprocessing.Pool(2)
+
+ # Make sure we don't lose pool processes because of encoding errors.
+ for iteration in range(20):
+ res = p.apply_async(unpickleable_result)
+ self.assertRaises(MaybeEncodingError, res.get)
+
+ p.close()
+ p.join()
+
class _TestPoolWorkerLifetime(BaseTestCase):
ALLOWED_TYPES = ('processes', )
@@ -1452,6 +1513,7 @@
self.assertTimingAlmostEqual(poll.elapsed, TIMEOUT1)
conn.send(None)
+ time.sleep(.1)
self.assertEqual(poll(TIMEOUT1), True)
self.assertTimingAlmostEqual(poll.elapsed, 0)
@@ -1651,6 +1713,23 @@
self.assertEqual(conn.recv(), 'hello')
p.join()
l.close()
+
+ def test_issue14725(self):
+ l = self.connection.Listener()
+ p = self.Process(target=self._test, args=(l.address,))
+ p.daemon = True
+ p.start()
+ time.sleep(1)
+ # On Windows the client process should by now have connected,
+ # written data and closed the pipe handle by now. This causes
+ # ConnectNamdedPipe() to fail with ERROR_NO_DATA. See Issue
+ # 14725.
+ conn = l.accept()
+ self.assertEqual(conn.recv(), 'hello')
+ conn.close()
+ p.join()
+ l.close()
+
#
# Test of sending connection and socket objects between processes
#
@@ -2026,6 +2105,38 @@
# assert self.__handled
#
+# Check that Process.join() retries if os.waitpid() fails with EINTR
+#
+
+class _TestPollEintr(BaseTestCase):
+
+ ALLOWED_TYPES = ('processes',)
+
+ @classmethod
+ def _killer(cls, pid):
+ time.sleep(0.5)
+ os.kill(pid, signal.SIGUSR1)
+
+ @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1')
+ def test_poll_eintr(self):
+ got_signal = [False]
+ def record(*args):
+ got_signal[0] = True
+ pid = os.getpid()
+ oldhandler = signal.signal(signal.SIGUSR1, record)
+ try:
+ killer = self.Process(target=self._killer, args=(pid,))
+ killer.start()
+ p = self.Process(target=time.sleep, args=(1,))
+ p.start()
+ p.join()
+ self.assertTrue(got_signal[0])
+ self.assertEqual(p.exitcode, 0)
+ killer.join()
+ finally:
+ signal.signal(signal.SIGUSR1, oldhandler)
+
+#
# Test to verify handle verification, see issue 3321
#
@@ -2078,7 +2189,7 @@
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
'Condition', 'Event', 'Value', 'Array', 'RawValue',
'RawArray', 'current_process', 'active_children', 'Pipe',
- 'connection', 'JoinableQueue'
+ 'connection', 'JoinableQueue', 'Pool'
)))
testcases_processes = create_test_cases(ProcessesMixin, type='processes')
@@ -2092,7 +2203,7 @@
locals().update(get_attributes(manager, (
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
'Condition', 'Event', 'Value', 'Array', 'list', 'dict',
- 'Namespace', 'JoinableQueue'
+ 'Namespace', 'JoinableQueue', 'Pool'
)))
testcases_manager = create_test_cases(ManagerMixin, type='manager')
@@ -2106,7 +2217,7 @@
'Queue', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore',
'Condition', 'Event', 'Value', 'Array', 'current_process',
'active_children', 'Pipe', 'connection', 'dict', 'list',
- 'Namespace', 'JoinableQueue'
+ 'Namespace', 'JoinableQueue', 'Pool'
)))
testcases_threads = create_test_cases(ThreadsMixin, type='threads')
@@ -2238,8 +2349,62 @@
flike.flush()
assert sio.getvalue() == 'foo'
+#
+# Test interaction with socket timeouts - see Issue #6056
+#
+
+class TestTimeouts(unittest.TestCase):
+ @classmethod
+ def _test_timeout(cls, child, address):
+ time.sleep(1)
+ child.send(123)
+ child.close()
+ conn = multiprocessing.connection.Client(address)
+ conn.send(456)
+ conn.close()
+
+ def test_timeout(self):
+ old_timeout = socket.getdefaulttimeout()
+ try:
+ socket.setdefaulttimeout(0.1)
+ parent, child = multiprocessing.Pipe(duplex=True)
+ l = multiprocessing.connection.Listener(family='AF_INET')
+ p = multiprocessing.Process(target=self._test_timeout,
+ args=(child, l.address))
+ p.start()
+ child.close()
+ self.assertEqual(parent.recv(), 123)
+ parent.close()
+ conn = l.accept()
+ self.assertEqual(conn.recv(), 456)
+ conn.close()
+ l.close()
+ p.join(10)
+ finally:
+ socket.setdefaulttimeout(old_timeout)
+
+#
+# Test what happens with no "if __name__ == '__main__'"
+#
+
+class TestNoForkBomb(unittest.TestCase):
+ def test_noforkbomb(self):
+ name = os.path.join(os.path.dirname(__file__), 'mp_fork_bomb.py')
+ if WIN32:
+ rc, out, err = test.script_helper.assert_python_failure(name)
+ self.assertEqual('', out.decode('ascii'))
+ self.assertIn('RuntimeError', err.decode('ascii'))
+ else:
+ rc, out, err = test.script_helper.assert_python_ok(name)
+ self.assertEqual('123', out.decode('ascii').rstrip())
+ self.assertEqual('', err.decode('ascii'))
+
+#
+#
+#
+
testcases_other = [OtherTest, TestInvalidHandle, TestInitializers,
- TestStdinBadfiledescriptor]
+ TestStdinBadfiledescriptor, TestTimeouts, TestNoForkBomb]
#
#
diff --git a/lib-python/2.7/test/test_mutex.py b/lib-python/2.7/test/test_mutex.py
--- a/lib-python/2.7/test/test_mutex.py
+++ b/lib-python/2.7/test/test_mutex.py
@@ -14,7 +14,7 @@
m.lock(called_by_mutex2, "eggs")
def called_by_mutex2(some_data):
- self.assertEquals(some_data, "eggs")
+ self.assertEqual(some_data, "eggs")
self.assertTrue(m.test(), "mutex not held")
self.assertTrue(ready_for_2,
"called_by_mutex2 called too soon")
diff --git a/lib-python/2.7/test/test_old_mailbox.py b/lib-python/2.7/test/test_old_mailbox.py
--- a/lib-python/2.7/test/test_old_mailbox.py
+++ b/lib-python/2.7/test/test_old_mailbox.py
@@ -73,7 +73,9 @@
self.createMessage("cur")
self.mbox = mailbox.Maildir(test_support.TESTFN)
self.assertTrue(len(self.mbox) == 1)
- self.assertTrue(self.mbox.next() is not None)
+ msg = self.mbox.next()
+ self.assertTrue(msg is not None)
+ msg.fp.close()
self.assertTrue(self.mbox.next() is None)
self.assertTrue(self.mbox.next() is None)
@@ -81,7 +83,9 @@
self.createMessage("new")
self.mbox = mailbox.Maildir(test_support.TESTFN)
self.assertTrue(len(self.mbox) == 1)
- self.assertTrue(self.mbox.next() is not None)
+ msg = self.mbox.next()
+ self.assertTrue(msg is not None)
+ msg.fp.close()
self.assertTrue(self.mbox.next() is None)
self.assertTrue(self.mbox.next() is None)
@@ -90,8 +94,12 @@
self.createMessage("new")
self.mbox = mailbox.Maildir(test_support.TESTFN)
self.assertTrue(len(self.mbox) == 2)
- self.assertTrue(self.mbox.next() is not None)
- self.assertTrue(self.mbox.next() is not None)
+ msg = self.mbox.next()
+ self.assertTrue(msg is not None)
+ msg.fp.close()
+ msg = self.mbox.next()
+ self.assertTrue(msg is not None)
+ msg.fp.close()
self.assertTrue(self.mbox.next() is None)
self.assertTrue(self.mbox.next() is None)
diff --git a/lib-python/2.7/test/test_optparse.py b/lib-python/2.7/test/test_optparse.py
--- a/lib-python/2.7/test/test_optparse.py
+++ b/lib-python/2.7/test/test_optparse.py
@@ -769,6 +769,13 @@
self.assertParseFail(["-test"],
"no such option: -e")
+ def test_add_option_accepts_unicode(self):
+ self.parser.add_option(u"-u", u"--unicode", action="store_true")
+ self.assertParseOK(["-u"],
+ {'a': None, 'boo': None, 'foo': None, 'unicode': True},
+ [])
+
+
class TestBool(BaseTest):
def setUp(self):
options = [make_option("-v",
diff --git a/lib-python/2.7/test/test_os.py b/lib-python/2.7/test/test_os.py
--- a/lib-python/2.7/test/test_os.py
+++ b/lib-python/2.7/test/test_os.py
@@ -214,33 +214,33 @@
try:
result[200]
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except IndexError:
pass
# Make sure that assignment fails
try:
result.st_mode = 1
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except (AttributeError, TypeError):
pass
try:
result.st_rdev = 1
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except (AttributeError, TypeError):
pass
try:
result.parrot = 1
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except AttributeError:
pass
# Use the stat_result constructor with a too-short tuple.
try:
result2 = os.stat_result((10,))
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except TypeError:
pass
@@ -274,20 +274,20 @@
# Make sure that assignment really fails
try:
result.f_bfree = 1
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except TypeError:
pass
try:
result.parrot = 1
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except AttributeError:
pass
# Use the constructor with a too-short tuple.
try:
result2 = os.statvfs_result((10,))
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except TypeError:
pass
diff --git a/lib-python/2.7/test/test_parser.py b/lib-python/2.7/test/test_parser.py
--- a/lib-python/2.7/test/test_parser.py
+++ b/lib-python/2.7/test/test_parser.py
@@ -1,7 +1,8 @@
import parser
import unittest
import sys
-from test import test_support
+import struct
+from test import test_support as support
#
# First, we test that we can generate trees from valid source fragments,
@@ -566,6 +567,17 @@
st = parser.suite('a = u"\u1"')
self.assertRaises(SyntaxError, parser.compilest, st)
+ def test_issue_9011(self):
+ # Issue 9011: compilation of an unary minus expression changed
+ # the meaning of the ST, so that a second compilation produced
+ # incorrect results.
+ st = parser.expr('-3')
+ code1 = parser.compilest(st)
+ self.assertEqual(eval(code1), -3)
+ code2 = parser.compilest(st)
+ self.assertEqual(eval(code2), -3)
+
+
class ParserStackLimitTestCase(unittest.TestCase):
"""try to push the parser to/over it's limits.
see http://bugs.python.org/issue1881 for a discussion
@@ -583,12 +595,57 @@
print >>sys.stderr, "Expecting 's_push: parser stack overflow' in next line"
self.assertRaises(MemoryError, parser.expr, e)
+class STObjectTestCase(unittest.TestCase):
+ """Test operations on ST objects themselves"""
+
+ check_sizeof = support.check_sizeof
+
+ @support.cpython_only
+ def test_sizeof(self):
+ def XXXROUNDUP(n):
+ if n <= 1:
+ return n
+ if n <= 128:
+ return (n + 3) & ~3
+ return 1 << (n - 1).bit_length()
+
+ basesize = support.calcobjsize('Pii')
+ nodesize = struct.calcsize('hP3iP0h')
+ def sizeofchildren(node):
+ if node is None:
+ return 0
+ res = 0
+ hasstr = len(node) > 1 and isinstance(node[-1], str)
+ if hasstr:
+ res += len(node[-1]) + 1
+ children = node[1:-1] if hasstr else node[1:]
+ if children:
+ res += XXXROUNDUP(len(children)) * nodesize
+ for child in children:
+ res += sizeofchildren(child)
+ return res
+
+ def check_st_sizeof(st):
+ self.check_sizeof(st, basesize + nodesize +
+ sizeofchildren(st.totuple()))
+
+ check_st_sizeof(parser.expr('2 + 3'))
+ check_st_sizeof(parser.expr('2 + 3 + 4'))
+ check_st_sizeof(parser.suite('x = 2 + 3'))
+ check_st_sizeof(parser.suite(''))
+ check_st_sizeof(parser.suite('# -*- coding: utf-8 -*-'))
+ check_st_sizeof(parser.expr('[' + '2,' * 1000 + ']'))
+
+
+ # XXX tests for pickling and unpickling of ST objects should go here
+
def test_main():
- test_support.run_unittest(
+ support.run_unittest(
RoundtripLegalSyntaxTestCase,
IllegalSyntaxTestCase,
CompileTestCase,
ParserStackLimitTestCase,
+ STObjectTestCase,
)
diff --git a/lib-python/2.7/test/test_pdb.py b/lib-python/2.7/test/test_pdb.py
--- a/lib-python/2.7/test/test_pdb.py
+++ b/lib-python/2.7/test/test_pdb.py
@@ -6,12 +6,69 @@
import os
import unittest
import subprocess
+import textwrap
from test import test_support
# This little helper class is essential for testing pdb under doctest.
from test_doctest import _FakeInput
+class PdbTestCase(unittest.TestCase):
+
+ def run_pdb(self, script, commands):
+ """Run 'script' lines with pdb and the pdb 'commands'."""
+ filename = 'main.py'
+ with open(filename, 'w') as f:
+ f.write(textwrap.dedent(script))
+ self.addCleanup(test_support.unlink, filename)
+ cmd = [sys.executable, '-m', 'pdb', filename]
+ stdout = stderr = None
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ )
+ stdout, stderr = proc.communicate(commands)
+ proc.stdout.close()
+ proc.stdin.close()
+ return stdout, stderr
+
+ def test_issue13183(self):
+ script = """
+ from bar import bar
+
+ def foo():
+ bar()
+
+ def nope():
+ pass
+
+ def foobar():
+ foo()
+ nope()
+
+ foobar()
+ """
+ commands = """
+ from bar import bar
+ break bar
+ continue
+ step
+ step
+ quit
+ """
+ bar = """
+ def bar():
+ pass
+ """
+ with open('bar.py', 'w') as f:
+ f.write(textwrap.dedent(bar))
+ self.addCleanup(test_support.unlink, 'bar.py')
+ stdout, stderr = self.run_pdb(script, commands)
+ self.assertTrue(
+ any('main.py(5)foo()->None' in l for l in stdout.splitlines()),
+ 'Fail to step into the caller after a return')
+
+
class PdbTestInput(object):
"""Context manager that makes testing Pdb in doctests easier."""
@@ -309,7 +366,9 @@
def test_main():
from test import test_pdb
test_support.run_doctest(test_pdb, verbosity=True)
- test_support.run_unittest(ModuleInitTester)
+ test_support.run_unittest(
+ PdbTestCase,
+ ModuleInitTester)
if __name__ == '__main__':
test_main()
diff --git a/lib-python/2.7/test/test_peepholer.py b/lib-python/2.7/test/test_peepholer.py
--- a/lib-python/2.7/test/test_peepholer.py
+++ b/lib-python/2.7/test/test_peepholer.py
@@ -138,21 +138,22 @@
self.assertIn('(1000)', asm)
def test_binary_subscr_on_unicode(self):
- # valid code get optimized
+ # unicode strings don't get optimized
asm = dis_single('u"foo"[0]')
- self.assertIn("(u'f')", asm)
- self.assertNotIn('BINARY_SUBSCR', asm)
+ self.assertNotIn("(u'f')", asm)
+ self.assertIn('BINARY_SUBSCR', asm)
asm = dis_single('u"\u0061\uffff"[1]')
- self.assertIn("(u'\\uffff')", asm)
- self.assertNotIn('BINARY_SUBSCR', asm)
+ self.assertNotIn("(u'\\uffff')", asm)
+ self.assertIn('BINARY_SUBSCR', asm)
- # invalid code doesn't get optimized
# out of range
asm = dis_single('u"fuu"[10]')
self.assertIn('BINARY_SUBSCR', asm)
# non-BMP char (see #5057)
asm = dis_single('u"\U00012345"[0]')
self.assertIn('BINARY_SUBSCR', asm)
+ asm = dis_single('u"\U00012345abcdef"[3]')
+ self.assertIn('BINARY_SUBSCR', asm)
def test_folding_of_unaryops_on_constants(self):
diff --git a/lib-python/2.7/test/test_pickle.py b/lib-python/2.7/test/test_pickle.py
--- a/lib-python/2.7/test/test_pickle.py
+++ b/lib-python/2.7/test/test_pickle.py
@@ -3,10 +3,11 @@
from test import test_support
-from test.pickletester import AbstractPickleTests
-from test.pickletester import AbstractPickleModuleTests
-from test.pickletester import AbstractPersistentPicklerTests
-from test.pickletester import AbstractPicklerUnpicklerObjectTests
+from test.pickletester import (AbstractPickleTests,
+ AbstractPickleModuleTests,
+ AbstractPersistentPicklerTests,
+ AbstractPicklerUnpicklerObjectTests,
+ BigmemPickleTests)
class PickleTests(AbstractPickleTests, AbstractPickleModuleTests):
@@ -66,6 +67,16 @@
pickler_class = pickle.Pickler
unpickler_class = pickle.Unpickler
+class PickleBigmemPickleTests(BigmemPickleTests):
+
+ def dumps(self, arg, proto=0, fast=0):
+ # Ignore fast
+ return pickle.dumps(arg, proto)
+
+ def loads(self, buf):
+ # Ignore fast
+ return pickle.loads(buf)
+
def test_main():
test_support.run_unittest(
@@ -73,6 +84,7 @@
PicklerTests,
PersPicklerTests,
PicklerUnpicklerObjectTests,
+ PickleBigmemPickleTests,
)
test_support.run_doctest(pickle)
diff --git a/lib-python/2.7/test/test_poll.py b/lib-python/2.7/test/test_poll.py
--- a/lib-python/2.7/test/test_poll.py
+++ b/lib-python/2.7/test/test_poll.py
@@ -1,6 +1,7 @@
# Test case for the os.poll() function
import os, select, random, unittest
+import _testcapi
from test.test_support import TESTFN, run_unittest
try:
@@ -150,6 +151,15 @@
if x != 5:
self.fail('Overflow must have occurred')
+ pollster = select.poll()
+ # Issue 15989
+ self.assertRaises(OverflowError, pollster.register, 0,
+ _testcapi.SHRT_MAX + 1)
+ self.assertRaises(OverflowError, pollster.register, 0,
+ _testcapi.USHRT_MAX + 1)
+ self.assertRaises(OverflowError, pollster.poll, _testcapi.INT_MAX + 1)
+ self.assertRaises(OverflowError, pollster.poll, _testcapi.UINT_MAX + 1)
+
def test_main():
run_unittest(PollTests)
diff --git a/lib-python/2.7/test/test_posix.py b/lib-python/2.7/test/test_posix.py
--- a/lib-python/2.7/test/test_posix.py
+++ b/lib-python/2.7/test/test_posix.py
@@ -9,6 +9,7 @@
import sys
import time
import os
+import platform
import pwd
import shutil
import stat
@@ -107,7 +108,11 @@
# If a non-privileged user invokes it, it should fail with OSError
# EPERM.
if os.getuid() != 0:
- name = pwd.getpwuid(posix.getuid()).pw_name
+ try:
+ name = pwd.getpwuid(posix.getuid()).pw_name
+ except KeyError:
+ # the current UID may not have a pwd entry
+ raise unittest.SkipTest("need a pwd entry")
try:
posix.initgroups(name, 13)
except OSError as e:
@@ -217,26 +222,64 @@
if hasattr(posix, 'stat'):
self.assertTrue(posix.stat(test_support.TESTFN))
- def _test_all_chown_common(self, chown_func, first_param):
+ def _test_all_chown_common(self, chown_func, first_param, stat_func):
"""Common code for chown, fchown and lchown tests."""
- if os.getuid() == 0:
- try:
- # Many linux distros have a nfsnobody user as MAX_UID-2
- # that makes a good test case for signedness issues.
- # http://bugs.python.org/issue1747858
- # This part of the test only runs when run as root.
- # Only scary people run their tests as root.
- ent = pwd.getpwnam('nfsnobody')
- chown_func(first_param, ent.pw_uid, ent.pw_gid)
- except KeyError:
- pass
+ def check_stat(uid, gid):
+ if stat_func is not None:
+ stat = stat_func(first_param)
+ self.assertEqual(stat.st_uid, uid)
+ self.assertEqual(stat.st_gid, gid)
+ uid = os.getuid()
+ gid = os.getgid()
+ # test a successful chown call
+ chown_func(first_param, uid, gid)
+ check_stat(uid, gid)
+ chown_func(first_param, -1, gid)
+ check_stat(uid, gid)
+ chown_func(first_param, uid, -1)
+ check_stat(uid, gid)
+
+ if uid == 0:
+ # Try an amusingly large uid/gid to make sure we handle
+ # large unsigned values. (chown lets you use any
+ # uid/gid you like, even if they aren't defined.)
+ #
+ # This problem keeps coming up:
+ # http://bugs.python.org/issue1747858
+ # http://bugs.python.org/issue4591
+ # http://bugs.python.org/issue15301
+ # Hopefully the fix in 4591 fixes it for good!
+ #
+ # This part of the test only runs when run as root.
+ # Only scary people run their tests as root.
+
+ big_value = 2**31
+ chown_func(first_param, big_value, big_value)
+ check_stat(big_value, big_value)
+ chown_func(first_param, -1, -1)
+ check_stat(big_value, big_value)
+ chown_func(first_param, uid, gid)
+ check_stat(uid, gid)
+ elif platform.system() in ('HP-UX', 'SunOS'):
+ # HP-UX and Solaris can allow a non-root user to chown() to root
+ # (issue #5113)
+ raise unittest.SkipTest("Skipping because of non-standard chown() "
+ "behavior")
else:
# non-root cannot chown to root, raises OSError
- self.assertRaises(OSError, chown_func,
- first_param, 0, 0)
-
- # test a successful chown call
- chown_func(first_param, os.getuid(), os.getgid())
+ self.assertRaises(OSError, chown_func, first_param, 0, 0)
+ check_stat(uid, gid)
+ self.assertRaises(OSError, chown_func, first_param, 0, -1)
+ check_stat(uid, gid)
+ if 0 not in os.getgroups():
+ self.assertRaises(OSError, chown_func, first_param, -1, 0)
+ check_stat(uid, gid)
+ # test illegal types
+ for t in str, float:
+ self.assertRaises(TypeError, chown_func, first_param, t(uid), gid)
+ check_stat(uid, gid)
+ self.assertRaises(TypeError, chown_func, first_param, uid, t(gid))
+ check_stat(uid, gid)
@unittest.skipUnless(hasattr(posix, 'chown'), "test needs os.chown()")
def test_chown(self):
@@ -246,7 +289,8 @@
# re-create the file
open(test_support.TESTFN, 'w').close()
- self._test_all_chown_common(posix.chown, test_support.TESTFN)
+ self._test_all_chown_common(posix.chown, test_support.TESTFN,
+ getattr(posix, 'stat', None))
@unittest.skipUnless(hasattr(posix, 'fchown'), "test needs os.fchown()")
def test_fchown(self):
@@ -256,7 +300,8 @@
test_file = open(test_support.TESTFN, 'w')
try:
fd = test_file.fileno()
- self._test_all_chown_common(posix.fchown, fd)
+ self._test_all_chown_common(posix.fchown, fd,
+ getattr(posix, 'fstat', None))
finally:
test_file.close()
@@ -265,7 +310,8 @@
os.unlink(test_support.TESTFN)
# create a symlink
os.symlink(_DUMMY_SYMLINK, test_support.TESTFN)
- self._test_all_chown_common(posix.lchown, test_support.TESTFN)
+ self._test_all_chown_common(posix.lchown, test_support.TESTFN,
+ getattr(posix, 'lstat', None))
def test_chdir(self):
if hasattr(posix, 'chdir'):
@@ -324,7 +370,16 @@
def _test_chflags_regular_file(self, chflags_func, target_file):
st = os.stat(target_file)
self.assertTrue(hasattr(st, 'st_flags'))
- chflags_func(target_file, st.st_flags | stat.UF_IMMUTABLE)
+
+ # ZFS returns EOPNOTSUPP when attempting to set flag UF_IMMUTABLE.
+ try:
+ chflags_func(target_file, st.st_flags | stat.UF_IMMUTABLE)
+ except OSError as err:
+ if err.errno != errno.EOPNOTSUPP:
+ raise
+ msg = 'chflag UF_IMMUTABLE not supported by underlying fs'
+ self.skipTest(msg)
+
try:
new_st = os.stat(target_file)
self.assertEqual(st.st_flags | stat.UF_IMMUTABLE, new_st.st_flags)
@@ -353,8 +408,16 @@
self.teardown_files.append(_DUMMY_SYMLINK)
dummy_symlink_st = os.lstat(_DUMMY_SYMLINK)
- posix.lchflags(_DUMMY_SYMLINK,
- dummy_symlink_st.st_flags | stat.UF_IMMUTABLE)
+ # ZFS returns EOPNOTSUPP when attempting to set flag UF_IMMUTABLE.
+ try:
+ posix.lchflags(_DUMMY_SYMLINK,
+ dummy_symlink_st.st_flags | stat.UF_IMMUTABLE)
+ except OSError as err:
+ if err.errno != errno.EOPNOTSUPP:
+ raise
+ msg = 'chflag UF_IMMUTABLE not supported by underlying fs'
+ self.skipTest(msg)
+
try:
new_testfn_st = os.stat(test_support.TESTFN)
new_dummy_symlink_st = os.lstat(_DUMMY_SYMLINK)
@@ -395,8 +458,16 @@
_create_and_do_getcwd(dirname, current_path_length + len(dirname) + 1)
except OSError as e:
expected_errno = errno.ENAMETOOLONG
- if 'sunos' in sys.platform or 'openbsd' in sys.platform:
- expected_errno = errno.ERANGE # Issue 9185
+ # The following platforms have quirky getcwd()
+ # behaviour -- see issue 9185 and 15765 for
+ # more information.
+ quirky_platform = (
+ 'sunos' in sys.platform or
+ 'netbsd' in sys.platform or
+ 'openbsd' in sys.platform
+ )
+ if quirky_platform:
+ expected_errno = errno.ERANGE
self.assertEqual(e.errno, expected_errno)
finally:
os.chdir('..')
@@ -412,10 +483,18 @@
def test_getgroups(self):
with os.popen('id -G') as idg:
groups = idg.read().strip()
+ ret = idg.close()
- if not groups:
+ if ret != None or not groups:
raise unittest.SkipTest("need working 'id -G'")
+ # Issues 16698: OS X ABIs prior to 10.6 have limits on getgroups()
+ if sys.platform == 'darwin':
+ import sysconfig
+ dt = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') or '10.0'
+ if float(dt) < 10.6:
+ raise unittest.SkipTest("getgroups(2) is broken prior to 10.6")
+
# 'id -G' and 'os.getgroups()' should return the same
# groups, ignoring order and duplicates.
# #10822 - it is implementation defined whether posix.getgroups()
diff --git a/lib-python/2.7/test/test_posixpath.py b/lib-python/2.7/test/test_posixpath.py
--- a/lib-python/2.7/test/test_posixpath.py
+++ b/lib-python/2.7/test/test_posixpath.py
@@ -9,6 +9,16 @@
ABSTFN = abspath(test_support.TESTFN)
+def skip_if_ABSTFN_contains_backslash(test):
+ """
+ On Windows, posixpath.abspath still returns paths with backslashes
+ instead of posix forward slashes. If this is the case, several tests
+ fail, so skip them.
+ """
+ found_backslash = '\\' in ABSTFN
+ msg = "ABSTFN is not a posix path - tests fail"
+ return [test, unittest.skip(msg)(test)][found_backslash]
+
def safe_rmdir(dirname):
try:
os.rmdir(dirname)
@@ -110,8 +120,10 @@
),
True
)
- # If we don't have links, assume that os.stat doesn't return resonable
- # inode information and thus, that samefile() doesn't work
+
+ # If we don't have links, assume that os.stat doesn't return
+ # reasonable inode information and thus, that samefile() doesn't
+ # work.
if hasattr(os, "symlink"):
os.symlink(
test_support.TESTFN + "1",
@@ -151,19 +163,19 @@
),
True
)
- # If we don't have links, assume that os.stat() doesn't return resonable
- # inode information and thus, that samefile() doesn't work
+ # If we don't have links, assume that os.stat() doesn't return
+ # reasonable inode information and thus, that samestat() doesn't
+ # work.
if hasattr(os, "symlink"):
- if hasattr(os, "symlink"):
- os.symlink(test_support.TESTFN + "1", test_support.TESTFN + "2")
- self.assertIs(
- posixpath.samestat(
- os.stat(test_support.TESTFN + "1"),
- os.stat(test_support.TESTFN + "2")
- ),
- True
- )
- os.remove(test_support.TESTFN + "2")
+ os.symlink(test_support.TESTFN + "1", test_support.TESTFN + "2")
+ self.assertIs(
+ posixpath.samestat(
+ os.stat(test_support.TESTFN + "1"),
+ os.stat(test_support.TESTFN + "2")
+ ),
+ True
+ )
+ os.remove(test_support.TESTFN + "2")
f = open(test_support.TESTFN + "2", "wb")
f.write("bar")
f.close()
@@ -201,6 +213,7 @@
with test_support.EnvironmentVarGuard() as env:
env['HOME'] = '/'
self.assertEqual(posixpath.expanduser("~"), "/")
+ self.assertEqual(posixpath.expanduser("~/foo"), "/foo")
def test_normpath(self):
self.assertEqual(posixpath.normpath(""), ".")
@@ -211,6 +224,18 @@
self.assertEqual(posixpath.normpath("///foo/.//bar//.//..//.//baz"), "/foo/baz")
self.assertEqual(posixpath.normpath("///..//./foo/.//bar"), "/foo/bar")
+ @skip_if_ABSTFN_contains_backslash
+ def test_realpath_curdir(self):
+ self.assertEqual(realpath('.'), os.getcwd())
+ self.assertEqual(realpath('./.'), os.getcwd())
+ self.assertEqual(realpath('/'.join(['.'] * 100)), os.getcwd())
+
+ @skip_if_ABSTFN_contains_backslash
+ def test_realpath_pardir(self):
+ self.assertEqual(realpath('..'), dirname(os.getcwd()))
+ self.assertEqual(realpath('../..'), dirname(dirname(os.getcwd())))
+ self.assertEqual(realpath('/'.join(['..'] * 100)), '/')
+
if hasattr(os, "symlink"):
def test_realpath_basic(self):
# Basic operation.
@@ -233,6 +258,22 @@
self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1")
self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2")
+ self.assertEqual(realpath(ABSTFN+"1/x"), ABSTFN+"1/x")
+ self.assertEqual(realpath(ABSTFN+"1/.."), dirname(ABSTFN))
+ self.assertEqual(realpath(ABSTFN+"1/../x"), dirname(ABSTFN) + "/x")
+ os.symlink(ABSTFN+"x", ABSTFN+"y")
+ self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "y"),
+ ABSTFN + "y")
+ self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "1"),
+ ABSTFN + "1")
+
+ os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a")
+ self.assertEqual(realpath(ABSTFN+"a"), ABSTFN+"a/b")
+
+ os.symlink("../" + basename(dirname(ABSTFN)) + "/" +
+ basename(ABSTFN) + "c", ABSTFN+"c")
+ self.assertEqual(realpath(ABSTFN+"c"), ABSTFN+"c")
+
# Test using relative path as well.
os.chdir(dirname(ABSTFN))
self.assertEqual(realpath(basename(ABSTFN)), ABSTFN)
@@ -241,6 +282,40 @@
test_support.unlink(ABSTFN)
test_support.unlink(ABSTFN+"1")
test_support.unlink(ABSTFN+"2")
+ test_support.unlink(ABSTFN+"y")
+ test_support.unlink(ABSTFN+"c")
+ test_support.unlink(ABSTFN+"a")
+
+ def test_realpath_repeated_indirect_symlinks(self):
+ # Issue #6975.
+ try:
+ os.mkdir(ABSTFN)
+ os.symlink('../' + basename(ABSTFN), ABSTFN + '/self')
+ os.symlink('self/self/self', ABSTFN + '/link')
+ self.assertEqual(realpath(ABSTFN + '/link'), ABSTFN)
+ finally:
+ test_support.unlink(ABSTFN + '/self')
+ test_support.unlink(ABSTFN + '/link')
+ safe_rmdir(ABSTFN)
+
+ def test_realpath_deep_recursion(self):
+ depth = 10
+ old_path = abspath('.')
+ try:
+ os.mkdir(ABSTFN)
+ for i in range(depth):
+ os.symlink('/'.join(['%d' % i] * 10), ABSTFN + '/%d' % (i + 1))
+ os.symlink('.', ABSTFN + '/0')
+ self.assertEqual(realpath(ABSTFN + '/%d' % depth), ABSTFN)
+
+ # Test using relative path as well.
+ os.chdir(ABSTFN)
+ self.assertEqual(realpath('%d' % depth), ABSTFN)
+ finally:
+ os.chdir(old_path)
+ for i in range(depth + 1):
+ test_support.unlink(ABSTFN + '/%d' % i)
+ safe_rmdir(ABSTFN)
def test_realpath_resolve_parents(self):
# We also need to resolve any symlinks in the parents of a relative
diff --git a/lib-python/2.7/test/test_property.py b/lib-python/2.7/test/test_property.py
--- a/lib-python/2.7/test/test_property.py
+++ b/lib-python/2.7/test/test_property.py
@@ -163,7 +163,7 @@
Foo.spam.__doc__,
"spam wrapped in property subclass")
- @unittest.skipIf(sys.flags.optimize <= 2,
+ @unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
def test_property_setter_copies_getter_docstring(self):
class Foo(object):
@@ -196,7 +196,7 @@
FooSub.spam.__doc__,
"spam wrapped in property subclass")
- @unittest.skipIf(sys.flags.optimize <= 2,
+ @unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
def test_property_new_getter_new_docstring(self):
diff --git a/lib-python/2.7/test/test_pty.py b/lib-python/2.7/test/test_pty.py
--- a/lib-python/2.7/test/test_pty.py
+++ b/lib-python/2.7/test/test_pty.py
@@ -152,7 +152,7 @@
# platform-dependent amount of data is written to its fd. On
# Linux 2.6, it's 4000 bytes and the child won't block, but on OS
# X even the small writes in the child above will block it. Also
- # on Linux, the read() will throw an OSError (input/output error)
+ # on Linux, the read() will raise an OSError (input/output error)
# when it tries to read past the end of the buffer but the child's
# already exited, so catch and discard those exceptions. It's not
# worth checking for EIO.
diff --git a/lib-python/2.7/test/test_pwd.py b/lib-python/2.7/test/test_pwd.py
--- a/lib-python/2.7/test/test_pwd.py
+++ b/lib-python/2.7/test/test_pwd.py
@@ -49,7 +49,9 @@
def test_errors(self):
self.assertRaises(TypeError, pwd.getpwuid)
+ self.assertRaises(TypeError, pwd.getpwuid, 3.14)
self.assertRaises(TypeError, pwd.getpwnam)
+ self.assertRaises(TypeError, pwd.getpwnam, 42)
self.assertRaises(TypeError, pwd.getpwall, 42)
# try to get some errors
@@ -93,6 +95,13 @@
self.assertNotIn(fakeuid, byuids)
self.assertRaises(KeyError, pwd.getpwuid, fakeuid)
+ # -1 shouldn't be a valid uid because it has a special meaning in many
+ # uid-related functions
+ self.assertRaises(KeyError, pwd.getpwuid, -1)
+ # should be out of uid_t range
+ self.assertRaises(KeyError, pwd.getpwuid, 2**128)
+ self.assertRaises(KeyError, pwd.getpwuid, -2**128)
+
def test_main():
test_support.run_unittest(PwdTest)
diff --git a/lib-python/2.7/test/test_pyclbr.py b/lib-python/2.7/test/test_pyclbr.py
--- a/lib-python/2.7/test/test_pyclbr.py
+++ b/lib-python/2.7/test/test_pyclbr.py
@@ -188,6 +188,11 @@
cm('email.parser')
cm('test.test_pyclbr')
+ def test_issue_14798(self):
+ # test ImportError is raised when the first part of a dotted name is
+ # not a package
+ self.assertRaises(ImportError, pyclbr.readmodule_ex, 'asyncore.foo')
+
def test_main():
run_unittest(PyclbrTest)
diff --git a/lib-python/2.7/test/test_pydoc.py b/lib-python/2.7/test/test_pydoc.py
--- a/lib-python/2.7/test/test_pydoc.py
+++ b/lib-python/2.7/test/test_pydoc.py
@@ -16,6 +16,14 @@
from test import pydoc_mod
+if test.test_support.HAVE_DOCSTRINGS:
+ expected_data_docstrings = (
+ 'dictionary for instance variables (if defined)',
+ 'list of weak references to the object (if defined)',
+ )
+else:
+ expected_data_docstrings = ('', '')
+
expected_text_pattern = \
"""
NAME
@@ -40,11 +48,9 @@
class B(__builtin__.object)
| Data descriptors defined here:
|\x20\x20
- | __dict__
- | dictionary for instance variables (if defined)
+ | __dict__%s
|\x20\x20
- | __weakref__
- | list of weak references to the object (if defined)
+ | __weakref__%s
|\x20\x20
| ----------------------------------------------------------------------
| Data and other attributes defined here:
@@ -75,6 +81,9 @@
Nobody
""".strip()
+expected_text_data_docstrings = tuple('\n | ' + s if s else ''
+ for s in expected_data_docstrings)
+
expected_html_pattern = \
"""
<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
@@ -121,10 +130,10 @@
<tr><td bgcolor="#ffc8d8"><tt> </tt></td><td> </td>
<td width="100%%">Data descriptors defined here:<br>
<dl><dt><strong>__dict__</strong></dt>
-<dd><tt>dictionary for instance variables (if defined)</tt></dd>
+<dd><tt>%s</tt></dd>
</dl>
<dl><dt><strong>__weakref__</strong></dt>
-<dd><tt>list of weak references to the object (if defined)</tt></dd>
+<dd><tt>%s</tt></dd>
</dl>
<hr>
Data and other attributes defined here:<br>
@@ -168,6 +177,8 @@
<td width="100%%">Nobody</td></tr></table>
""".strip()
+expected_html_data_docstrings = tuple(s.replace(' ', ' ')
+ for s in expected_data_docstrings)
# output pattern for missing module
missing_pattern = "no Python documentation found for '%s'"
@@ -229,7 +240,9 @@
mod_url = nturl2path.pathname2url(mod_file)
else:
mod_url = mod_file
- expected_html = expected_html_pattern % (mod_url, mod_file, doc_loc)
+ expected_html = expected_html_pattern % (
+ (mod_url, mod_file, doc_loc) +
+ expected_html_data_docstrings)
if result != expected_html:
print_diffs(expected_html, result)
self.fail("outputs are not equal, see diff above")
@@ -238,8 +251,9 @@
"Docstrings are omitted with -O2 and above")
def test_text_doc(self):
result, doc_loc = get_pydoc_text(pydoc_mod)
- expected_text = expected_text_pattern % \
- (inspect.getabsfile(pydoc_mod), doc_loc)
+ expected_text = expected_text_pattern % (
+ (inspect.getabsfile(pydoc_mod), doc_loc) +
+ expected_text_data_docstrings)
if result != expected_text:
print_diffs(expected_text, result)
self.fail("outputs are not equal, see diff above")
@@ -249,6 +263,17 @@
result, doc_loc = get_pydoc_text(xml.etree)
self.assertEqual(doc_loc, "", "MODULE DOCS incorrectly includes a link")
+ def test_non_str_name(self):
+ # issue14638
+ # Treat illegal (non-str) name like no name
+ class A:
+ __name__ = 42
+ class B:
+ pass
+ adoc = pydoc.render_doc(A())
+ bdoc = pydoc.render_doc(B())
+ self.assertEqual(adoc.replace("A", "B"), bdoc)
+
def test_not_here(self):
missing_module = "test.i_am_not_here"
result = run_pydoc(missing_module)
diff --git a/lib-python/2.7/test/test_pyexpat.py b/lib-python/2.7/test/test_pyexpat.py
--- a/lib-python/2.7/test/test_pyexpat.py
+++ b/lib-python/2.7/test/test_pyexpat.py
@@ -588,6 +588,58 @@
except expat.ExpatError as e:
self.assertEqual(str(e), 'XML declaration not well-formed: line 1, column 14')
+class ForeignDTDTests(unittest.TestCase):
+ """
+ Tests for the UseForeignDTD method of expat parser objects.
+ """
+ def test_use_foreign_dtd(self):
+ """
+ If UseForeignDTD is passed True and a document without an external
+ entity reference is parsed, ExternalEntityRefHandler is first called
+ with None for the public and system ids.
+ """
+ handler_call_args = []
+ def resolve_entity(context, base, system_id, public_id):
+ handler_call_args.append((public_id, system_id))
+ return 1
+
+ parser = expat.ParserCreate()
+ parser.UseForeignDTD(True)
+ parser.SetParamEntityParsing(expat.XML_PARAM_ENTITY_PARSING_ALWAYS)
+ parser.ExternalEntityRefHandler = resolve_entity
+ parser.Parse("<?xml version='1.0'?><element/>")
+ self.assertEqual(handler_call_args, [(None, None)])
+
+ # test UseForeignDTD() is equal to UseForeignDTD(True)
+ handler_call_args[:] = []
+
+ parser = expat.ParserCreate()
+ parser.UseForeignDTD()
+ parser.SetParamEntityParsing(expat.XML_PARAM_ENTITY_PARSING_ALWAYS)
+ parser.ExternalEntityRefHandler = resolve_entity
+ parser.Parse("<?xml version='1.0'?><element/>")
+ self.assertEqual(handler_call_args, [(None, None)])
+
+ def test_ignore_use_foreign_dtd(self):
+ """
+ If UseForeignDTD is passed True and a document with an external
+ entity reference is parsed, ExternalEntityRefHandler is called with
+ the public and system ids from the document.
+ """
+ handler_call_args = []
+ def resolve_entity(context, base, system_id, public_id):
+ handler_call_args.append((public_id, system_id))
+ return 1
+
+ parser = expat.ParserCreate()
+ parser.UseForeignDTD(True)
+ parser.SetParamEntityParsing(expat.XML_PARAM_ENTITY_PARSING_ALWAYS)
+ parser.ExternalEntityRefHandler = resolve_entity
+ parser.Parse(
+ "<?xml version='1.0'?><!DOCTYPE foo PUBLIC 'bar' 'baz'><element/>")
+ self.assertEqual(handler_call_args, [("bar", "baz")])
+
+
def test_main():
run_unittest(SetAttributeTest,
ParseTest,
@@ -598,7 +650,8 @@
PositionTest,
sf1296433Test,
ChardataBufferTest,
- MalformedInputText)
+ MalformedInputText,
+ ForeignDTDTests)
if __name__ == "__main__":
test_main()
diff --git a/lib-python/2.7/test/test_random.py b/lib-python/2.7/test/test_random.py
--- a/lib-python/2.7/test/test_random.py
+++ b/lib-python/2.7/test/test_random.py
@@ -57,6 +57,14 @@
self.assertRaises(TypeError, self.gen.jumpahead) # needs an arg
self.assertRaises(TypeError, self.gen.jumpahead, 2, 3) # too many
+ def test_jumpahead_produces_valid_state(self):
+ # From http://bugs.python.org/issue14591.
+ self.gen.seed(199210368)
+ self.gen.jumpahead(13550674232554645900)
+ for i in range(500):
+ val = self.gen.random()
+ self.assertLess(val, 1.0)
+
def test_sample(self):
# For the entire allowable range of 0 <= k <= N, validate that
# the sample is of the correct length and contains only unique items
@@ -486,6 +494,7 @@
g.random = x[:].pop; g.paretovariate(1.0)
g.random = x[:].pop; g.expovariate(1.0)
g.random = x[:].pop; g.weibullvariate(1.0, 1.0)
+ g.random = x[:].pop; g.vonmisesvariate(1.0, 1.0)
g.random = x[:].pop; g.normalvariate(0.0, 1.0)
g.random = x[:].pop; g.gauss(0.0, 1.0)
g.random = x[:].pop; g.lognormvariate(0.0, 1.0)
@@ -506,6 +515,7 @@
(g.uniform, (1.0,10.0), (10.0+1.0)/2, (10.0-1.0)**2/12),
(g.triangular, (0.0, 1.0, 1.0/3.0), 4.0/9.0, 7.0/9.0/18.0),
(g.expovariate, (1.5,), 1/1.5, 1/1.5**2),
+ (g.vonmisesvariate, (1.23, 0), pi, pi**2/3),
(g.paretovariate, (5.0,), 5.0/(5.0-1),
5.0/((5.0-1)**2*(5.0-2))),
(g.weibullvariate, (1.0, 3.0), gamma(1+1/3.0),
@@ -522,8 +532,50 @@
s1 += e
s2 += (e - mu) ** 2
N = len(y)
- self.assertAlmostEqual(s1/N, mu, 2)
- self.assertAlmostEqual(s2/(N-1), sigmasqrd, 2)
+ self.assertAlmostEqual(s1/N, mu, places=2,
+ msg='%s%r' % (variate.__name__, args))
+ self.assertAlmostEqual(s2/(N-1), sigmasqrd, places=2,
+ msg='%s%r' % (variate.__name__, args))
+
+ def test_constant(self):
+ g = random.Random()
+ N = 100
+ for variate, args, expected in [
+ (g.uniform, (10.0, 10.0), 10.0),
+ (g.triangular, (10.0, 10.0), 10.0),
+ #(g.triangular, (10.0, 10.0, 10.0), 10.0),
+ (g.expovariate, (float('inf'),), 0.0),
+ (g.vonmisesvariate, (3.0, float('inf')), 3.0),
+ (g.gauss, (10.0, 0.0), 10.0),
+ (g.lognormvariate, (0.0, 0.0), 1.0),
+ (g.lognormvariate, (-float('inf'), 0.0), 0.0),
+ (g.normalvariate, (10.0, 0.0), 10.0),
+ (g.paretovariate, (float('inf'),), 1.0),
+ (g.weibullvariate, (10.0, float('inf')), 10.0),
+ (g.weibullvariate, (0.0, 10.0), 0.0),
+ ]:
+ for i in range(N):
+ self.assertEqual(variate(*args), expected)
+
+ def test_von_mises_range(self):
+ # Issue 17149: von mises variates were not consistently in the
+ # range [0, 2*PI].
+ g = random.Random()
+ N = 100
+ for mu in 0.0, 0.1, 3.1, 6.2:
+ for kappa in 0.0, 2.3, 500.0:
+ for _ in range(N):
+ sample = g.vonmisesvariate(mu, kappa)
+ self.assertTrue(
+ 0 <= sample <= random.TWOPI,
+ msg=("vonmisesvariate({}, {}) produced a result {} out"
+ " of range [0, 2*pi]").format(mu, kappa, sample))
+
+ def test_von_mises_large_kappa(self):
+ # Issue #17141: vonmisesvariate() was hang for large kappas
+ random.vonmisesvariate(0, 1e15)
+ random.vonmisesvariate(0, 1e100)
+
class TestModule(unittest.TestCase):
def testMagicConstants(self):
diff --git a/lib-python/2.7/test/test_re.py b/lib-python/2.7/test/test_re.py
--- a/lib-python/2.7/test/test_re.py
+++ b/lib-python/2.7/test/test_re.py
@@ -1,4 +1,5 @@
from test.test_support import verbose, run_unittest, import_module
+from test.test_support import precisionbigmemtest, _2G, cpython_only
import re
from re import Scanner
import sys
@@ -6,6 +7,7 @@
import traceback
from weakref import proxy
+
# Misc tests from Tim Peters' re.doc
# WARNING: Don't change details in these tests if you don't know
@@ -174,11 +176,31 @@
self.assertEqual(re.sub('x*', '-', 'abxd'), '-a-b-d-')
self.assertEqual(re.sub('x+', '-', 'abxd'), 'ab-d')
+ def test_symbolic_groups(self):
+ re.compile('(?P<a>x)(?P=a)(?(a)y)')
+ re.compile('(?P<a1>x)(?P=a1)(?(a1)y)')
+ self.assertRaises(re.error, re.compile, '(?P<a>)(?P<a>)')
+ self.assertRaises(re.error, re.compile, '(?Px)')
+ self.assertRaises(re.error, re.compile, '(?P=)')
+ self.assertRaises(re.error, re.compile, '(?P=1)')
+ self.assertRaises(re.error, re.compile, '(?P=a)')
+ self.assertRaises(re.error, re.compile, '(?P=a1)')
+ self.assertRaises(re.error, re.compile, '(?P=a.)')
+ self.assertRaises(re.error, re.compile, '(?P<)')
+ self.assertRaises(re.error, re.compile, '(?P<>)')
+ self.assertRaises(re.error, re.compile, '(?P<1>)')
+ self.assertRaises(re.error, re.compile, '(?P<a.>)')
+ self.assertRaises(re.error, re.compile, '(?())')
+ self.assertRaises(re.error, re.compile, '(?(a))')
+ self.assertRaises(re.error, re.compile, '(?(1a))')
+ self.assertRaises(re.error, re.compile, '(?(a.))')
+
def test_symbolic_refs(self):
self.assertRaises(re.error, re.sub, '(?P<a>x)', '\g<a', 'xx')
self.assertRaises(re.error, re.sub, '(?P<a>x)', '\g<', 'xx')
self.assertRaises(re.error, re.sub, '(?P<a>x)', '\g', 'xx')
self.assertRaises(re.error, re.sub, '(?P<a>x)', '\g<a a>', 'xx')
+ self.assertRaises(re.error, re.sub, '(?P<a>x)', '\g<>', 'xx')
self.assertRaises(re.error, re.sub, '(?P<a>x)', '\g<1a1>', 'xx')
self.assertRaises(IndexError, re.sub, '(?P<a>x)', '\g<ab>', 'xx')
self.assertRaises(re.error, re.sub, '(?P<a>x)|(?P<b>y)', '\g<b>', 'xx')
@@ -405,6 +427,12 @@
self.assertEqual(re.match(u"([\u2222\u2223])",
u"\u2222", re.UNICODE).group(1), u"\u2222")
+ def test_big_codesize(self):
+ # Issue #1160
+ r = re.compile('|'.join(('%d'%x for x in range(10000))))
+ self.assertIsNotNone(r.match('1000'))
+ self.assertIsNotNone(r.match('9999'))
+
def test_anyall(self):
self.assertEqual(re.match("a.b", "a\nb", re.DOTALL).group(0),
"a\nb")
@@ -600,6 +628,15 @@
self.assertEqual(re.match('(x)*y', 50000*'x'+'y').group(1), 'x')
self.assertEqual(re.match('(x)*?y', 50000*'x'+'y').group(1), 'x')
+ def test_unlimited_zero_width_repeat(self):
+ # Issue #9669
+ self.assertIsNone(re.match(r'(?:a?)*y', 'z'))
+ self.assertIsNone(re.match(r'(?:a?)+y', 'z'))
+ self.assertIsNone(re.match(r'(?:a?){2,}y', 'z'))
+ self.assertIsNone(re.match(r'(?:a?)*?y', 'z'))
+ self.assertIsNone(re.match(r'(?:a?)+?y', 'z'))
+ self.assertIsNone(re.match(r'(?:a?){2,}?y', 'z'))
+
def test_scanner(self):
def s_ident(scanner, token): return token
def s_operator(scanner, token): return "op%s" % token
@@ -793,6 +830,63 @@
# Test behaviour when not given a string or pattern as parameter
self.assertRaises(TypeError, re.compile, 0)
+ def test_bug_13899(self):
+ # Issue #13899: re pattern r"[\A]" should work like "A" but matches
+ # nothing. Ditto B and Z.
+ self.assertEqual(re.findall(r'[\A\B\b\C\Z]', 'AB\bCZ'),
+ ['A', 'B', '\b', 'C', 'Z'])
+
+ @precisionbigmemtest(size=_2G, memuse=1)
+ def test_large_search(self, size):
+ # Issue #10182: indices were 32-bit-truncated.
+ s = 'a' * size
+ m = re.search('$', s)
+ self.assertIsNotNone(m)
+ self.assertEqual(m.start(), size)
+ self.assertEqual(m.end(), size)
+
+ # The huge memuse is because of re.sub() using a list and a join()
+ # to create the replacement result.
+ @precisionbigmemtest(size=_2G, memuse=16 + 2)
+ def test_large_subn(self, size):
+ # Issue #10182: indices were 32-bit-truncated.
+ s = 'a' * size
+ r, n = re.subn('', '', s)
+ self.assertEqual(r, s)
+ self.assertEqual(n, size + 1)
+
+
+ def test_repeat_minmax_overflow(self):
+ # Issue #13169
+ string = "x" * 100000
+ self.assertEqual(re.match(r".{65535}", string).span(), (0, 65535))
+ self.assertEqual(re.match(r".{,65535}", string).span(), (0, 65535))
+ self.assertEqual(re.match(r".{65535,}?", string).span(), (0, 65535))
+ self.assertEqual(re.match(r".{65536}", string).span(), (0, 65536))
+ self.assertEqual(re.match(r".{,65536}", string).span(), (0, 65536))
+ self.assertEqual(re.match(r".{65536,}?", string).span(), (0, 65536))
+ # 2**128 should be big enough to overflow both SRE_CODE and Py_ssize_t.
+ self.assertRaises(OverflowError, re.compile, r".{%d}" % 2**128)
+ self.assertRaises(OverflowError, re.compile, r".{,%d}" % 2**128)
+ self.assertRaises(OverflowError, re.compile, r".{%d,}?" % 2**128)
+ self.assertRaises(OverflowError, re.compile, r".{%d,%d}" % (2**129, 2**128))
+
+ @cpython_only
+ def test_repeat_minmax_overflow_maxrepeat(self):
+ try:
+ from _sre import MAXREPEAT
+ except ImportError:
+ self.skipTest('requires _sre.MAXREPEAT constant')
+ string = "x" * 100000
+ self.assertIsNone(re.match(r".{%d}" % (MAXREPEAT - 1), string))
+ self.assertEqual(re.match(r".{,%d}" % (MAXREPEAT - 1), string).span(),
+ (0, 100000))
+ self.assertIsNone(re.match(r".{%d,}?" % (MAXREPEAT - 1), string))
+ self.assertRaises(OverflowError, re.compile, r".{%d}" % MAXREPEAT)
+ self.assertRaises(OverflowError, re.compile, r".{,%d}" % MAXREPEAT)
+ self.assertRaises(OverflowError, re.compile, r".{%d,}?" % MAXREPEAT)
+
+
def run_re_tests():
from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR
if verbose:
diff --git a/lib-python/2.7/test/test_readline.py b/lib-python/2.7/test/test_readline.py
--- a/lib-python/2.7/test/test_readline.py
+++ b/lib-python/2.7/test/test_readline.py
@@ -12,6 +12,10 @@
readline = import_module('readline')
class TestHistoryManipulation (unittest.TestCase):
+
+ @unittest.skipIf(not hasattr(readline, 'clear_history'),
+ "The history update test cannot be run because the "
+ "clear_history method is not available.")
def testHistoryUpdates(self):
readline.clear_history()
diff --git a/lib-python/2.7/test/test_resource.py b/lib-python/2.7/test/test_resource.py
--- a/lib-python/2.7/test/test_resource.py
+++ b/lib-python/2.7/test/test_resource.py
@@ -103,6 +103,23 @@
except (ValueError, AttributeError):
pass
+ # Issue 6083: Reference counting bug
+ def test_setrusage_refcount(self):
+ try:
+ limits = resource.getrlimit(resource.RLIMIT_CPU)
+ except AttributeError:
+ pass
+ else:
+ class BadSequence:
+ def __len__(self):
+ return 2
+ def __getitem__(self, key):
+ if key in (0, 1):
+ return len(tuple(range(1000000)))
+ raise IndexError
+
+ resource.setrlimit(resource.RLIMIT_CPU, BadSequence())
+
def test_main(verbose=None):
test_support.run_unittest(ResourceTest)
diff --git a/lib-python/2.7/test/test_sax.py b/lib-python/2.7/test/test_sax.py
--- a/lib-python/2.7/test/test_sax.py
+++ b/lib-python/2.7/test/test_sax.py
@@ -14,12 +14,28 @@
from xml.sax.handler import feature_namespaces
from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
from cStringIO import StringIO
+import io
+import os.path
+import shutil
+import test.test_support as support
from test.test_support import findfile, run_unittest
import unittest
TEST_XMLFILE = findfile("test.xml", subdir="xmltestdata")
TEST_XMLFILE_OUT = findfile("test.xml.out", subdir="xmltestdata")
+supports_unicode_filenames = True
+if not os.path.supports_unicode_filenames:
+ try:
+ support.TESTFN_UNICODE.encode(support.TESTFN_ENCODING)
+ except (AttributeError, UnicodeError, TypeError):
+ # Either the file system encoding is None, or the file name
+ # cannot be encoded in the file system encoding.
+ supports_unicode_filenames = False
+requires_unicode_filenames = unittest.skipUnless(
+ supports_unicode_filenames,
+ 'Requires unicode filenames support')
+
ns_uri = "http://www.python.org/xml-ns/saxtest/"
class XmlTestBase(unittest.TestCase):
@@ -155,9 +171,9 @@
start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
-class XmlgenTest(unittest.TestCase):
+class XmlgenTest:
def test_xmlgen_basic(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
gen.startElement("doc", {})
@@ -167,7 +183,7 @@
self.assertEqual(result.getvalue(), start + "<doc></doc>")
def test_xmlgen_content(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -179,7 +195,7 @@
self.assertEqual(result.getvalue(), start + "<doc>huhei</doc>")
def test_xmlgen_pi(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -191,7 +207,7 @@
self.assertEqual(result.getvalue(), start + "<?test data?><doc></doc>")
def test_xmlgen_content_escape(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -204,7 +220,7 @@
start + "<doc><huhei&</doc>")
def test_xmlgen_attr_escape(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -223,8 +239,41 @@
"<e a=\"'"\"></e>"
"<e a=\"
\"></e></doc>"))
+ def test_xmlgen_encoding(self):
+ encodings = ('iso-8859-15', 'utf-8',
+ 'utf-16be', 'utf-16le',
+ 'utf-32be', 'utf-32le')
+ for encoding in encodings:
+ result = self.ioclass()
+ gen = XMLGenerator(result, encoding=encoding)
+
+ gen.startDocument()
+ gen.startElement("doc", {"a": u'\u20ac'})
+ gen.characters(u"\u20ac")
+ gen.endElement("doc")
+ gen.endDocument()
+
+ self.assertEqual(result.getvalue(), (
+ u'<?xml version="1.0" encoding="%s"?>\n'
+ u'<doc a="\u20ac">\u20ac</doc>' % encoding
+ ).encode(encoding, 'xmlcharrefreplace'))
+
+ def test_xmlgen_unencodable(self):
+ result = self.ioclass()
+ gen = XMLGenerator(result, encoding='ascii')
+
+ gen.startDocument()
+ gen.startElement("doc", {"a": u'\u20ac'})
+ gen.characters(u"\u20ac")
+ gen.endElement("doc")
+ gen.endDocument()
+
+ self.assertEqual(result.getvalue(),
+ '<?xml version="1.0" encoding="ascii"?>\n'
+ '<doc a="€">€</doc>')
+
def test_xmlgen_ignorable(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -236,7 +285,7 @@
self.assertEqual(result.getvalue(), start + "<doc> </doc>")
def test_xmlgen_ns(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -254,7 +303,7 @@
ns_uri))
def test_1463026_1(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -265,7 +314,7 @@
self.assertEqual(result.getvalue(), start+'<a b="c"></a>')
def test_1463026_2(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -278,7 +327,7 @@
self.assertEqual(result.getvalue(), start+'<a xmlns="qux"></a>')
def test_1463026_3(self):
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -294,7 +343,7 @@
def test_5027_1(self):
# The xml prefix (as in xml:lang below) is reserved and bound by
# definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
- # a bug whereby a KeyError is thrown because this namespace is missing
+ # a bug whereby a KeyError is raised because this namespace is missing
# from a dictionary.
#
# This test demonstrates the bug by parsing a document.
@@ -306,7 +355,7 @@
parser = make_parser()
parser.setFeature(feature_namespaces, True)
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
parser.setContentHandler(gen)
parser.parse(test_xml)
@@ -320,12 +369,12 @@
def test_5027_2(self):
# The xml prefix (as in xml:lang below) is reserved and bound by
# definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
- # a bug whereby a KeyError is thrown because this namespace is missing
+ # a bug whereby a KeyError is raised because this namespace is missing
# from a dictionary.
#
# This test demonstrates the bug by direct manipulation of the
# XMLGenerator.
- result = StringIO()
+ result = self.ioclass()
gen = XMLGenerator(result)
gen.startDocument()
@@ -345,6 +394,44 @@
'<a:g2 xml:lang="en">Hello</a:g2>'
'</a:g1>'))
+ def test_no_close_file(self):
+ result = self.ioclass()
+ def func(out):
+ gen = XMLGenerator(out)
+ gen.startDocument()
+ gen.startElement("doc", {})
+ func(result)
+ self.assertFalse(result.closed)
+
+ def test_xmlgen_fragment(self):
+ result = self.ioclass()
+ gen = XMLGenerator(result)
+
+ # Don't call gen.startDocument()
+ gen.startElement("foo", {"a": "1.0"})
+ gen.characters("Hello")
+ gen.endElement("foo")
+ gen.startElement("bar", {"b": "2.0"})
+ gen.endElement("bar")
+ # Don't call gen.endDocument()
+
+ self.assertEqual(result.getvalue(),
+ '<foo a="1.0">Hello</foo><bar b="2.0"></bar>')
+
+class StringXmlgenTest(XmlgenTest, unittest.TestCase):
+ ioclass = StringIO
+
+class BytesIOXmlgenTest(XmlgenTest, unittest.TestCase):
+ ioclass = io.BytesIO
+
+class WriterXmlgenTest(XmlgenTest, unittest.TestCase):
+ class ioclass(list):
+ write = list.append
+ closed = False
+
+ def getvalue(self):
+ return b''.join(self)
+
class XMLFilterBaseTest(unittest.TestCase):
def test_filter_basic(self):
@@ -384,6 +471,21 @@
self.assertEqual(result.getvalue(), xml_test_out)
+ @requires_unicode_filenames
+ def test_expat_file_unicode(self):
+ fname = support.TESTFN_UNICODE
+ shutil.copyfile(TEST_XMLFILE, fname)
+ self.addCleanup(support.unlink, fname)
+
+ parser = create_parser()
+ result = StringIO()
+ xmlgen = XMLGenerator(result)
+
+ parser.setContentHandler(xmlgen)
+ parser.parse(open(fname))
+
+ self.assertEqual(result.getvalue(), xml_test_out)
+
# ===== DTDHandler support
class TestDTDHandler:
@@ -523,6 +625,21 @@
self.assertEqual(result.getvalue(), xml_test_out)
+ @requires_unicode_filenames
+ def test_expat_inpsource_sysid_unicode(self):
+ fname = support.TESTFN_UNICODE
+ shutil.copyfile(TEST_XMLFILE, fname)
+ self.addCleanup(support.unlink, fname)
+
+ parser = create_parser()
+ result = StringIO()
+ xmlgen = XMLGenerator(result)
+
+ parser.setContentHandler(xmlgen)
+ parser.parse(InputSource(fname))
+
+ self.assertEqual(result.getvalue(), xml_test_out)
+
def test_expat_inpsource_stream(self):
parser = create_parser()
result = StringIO()
@@ -596,6 +713,21 @@
self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
self.assertEqual(parser.getPublicId(), None)
+ @requires_unicode_filenames
+ def test_expat_locator_withinfo_unicode(self):
+ fname = support.TESTFN_UNICODE
+ shutil.copyfile(TEST_XMLFILE, fname)
+ self.addCleanup(support.unlink, fname)
+
+ result = StringIO()
+ xmlgen = XMLGenerator(result)
+ parser = create_parser()
+ parser.setContentHandler(xmlgen)
+ parser.parse(fname)
+
+ self.assertEqual(parser.getSystemId(), fname)
+ self.assertEqual(parser.getPublicId(), None)
+
# ===========================================================================
#
@@ -744,7 +876,9 @@
def test_main():
run_unittest(MakeParserTest,
SaxutilsTest,
- XmlgenTest,
+ StringXmlgenTest,
+ BytesIOXmlgenTest,
+ WriterXmlgenTest,
ExpatReaderTest,
ErrorReportingTest,
XmlReaderTest)
diff --git a/lib-python/2.7/test/test_select.py b/lib-python/2.7/test/test_select.py
--- a/lib-python/2.7/test/test_select.py
+++ b/lib-python/2.7/test/test_select.py
@@ -49,6 +49,15 @@
self.fail('Unexpected return values from select():', rfd, wfd, xfd)
p.close()
+ # Issue 16230: Crash on select resized list
+ def test_select_mutated(self):
+ a = []
+ class F:
+ def fileno(self):
+ del a[-1]
+ return sys.__stdout__.fileno()
+ a[:] = [F()] * 10
+ self.assertEqual(select.select([], a, []), ([], a[:5], []))
def test_main():
test_support.run_unittest(SelectTestCase)
diff --git a/lib-python/2.7/test/test_shutil.py b/lib-python/2.7/test/test_shutil.py
--- a/lib-python/2.7/test/test_shutil.py
+++ b/lib-python/2.7/test/test_shutil.py
@@ -7,6 +7,7 @@
import stat
import os
import os.path
+import errno
from os.path import splitdrive
from distutils.spawn import find_executable, spawn
from shutil import (_make_tarball, _make_zipfile, make_archive,
@@ -339,6 +340,35 @@
shutil.rmtree(TESTFN, ignore_errors=True)
shutil.rmtree(TESTFN2, ignore_errors=True)
+ @unittest.skipUnless(hasattr(os, 'chflags') and
+ hasattr(errno, 'EOPNOTSUPP') and
+ hasattr(errno, 'ENOTSUP'),
+ "requires os.chflags, EOPNOTSUPP & ENOTSUP")
+ def test_copystat_handles_harmless_chflags_errors(self):
+ tmpdir = self.mkdtemp()
+ file1 = os.path.join(tmpdir, 'file1')
+ file2 = os.path.join(tmpdir, 'file2')
+ self.write_file(file1, 'xxx')
+ self.write_file(file2, 'xxx')
+
+ def make_chflags_raiser(err):
+ ex = OSError()
+
+ def _chflags_raiser(path, flags):
+ ex.errno = err
+ raise ex
+ return _chflags_raiser
+ old_chflags = os.chflags
+ try:
+ for err in errno.EOPNOTSUPP, errno.ENOTSUP:
+ os.chflags = make_chflags_raiser(err)
+ shutil.copystat(file1, file2)
+ # assert others errors break it
+ os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
+ self.assertRaises(OSError, shutil.copystat, file1, file2)
+ finally:
+ os.chflags = old_chflags
+
@unittest.skipUnless(zlib, "requires zlib")
def test_make_tarball(self):
# creating something to tar
diff --git a/lib-python/2.7/test/test_signal.py b/lib-python/2.7/test/test_signal.py
--- a/lib-python/2.7/test/test_signal.py
+++ b/lib-python/2.7/test/test_signal.py
@@ -109,7 +109,7 @@
# This wait should be interrupted by the signal's exception.
self.wait(child)
time.sleep(1) # Give the signal time to be delivered.
- self.fail('HandlerBCalled exception not thrown')
+ self.fail('HandlerBCalled exception not raised')
except HandlerBCalled:
self.assertTrue(self.b_called)
self.assertFalse(self.a_called)
@@ -148,7 +148,7 @@
# test-running process from all the signals. It then
# communicates with that child process over a pipe and
# re-raises information about any exceptions the child
- # throws. The real work happens in self.run_test().
+ # raises. The real work happens in self.run_test().
os_done_r, os_done_w = os.pipe()
with closing(os.fdopen(os_done_r)) as done_r, \
closing(os.fdopen(os_done_w, 'w')) as done_w:
@@ -227,6 +227,13 @@
signal.signal(7, handler)
+class WakeupFDTests(unittest.TestCase):
+
+ def test_invalid_fd(self):
+ fd = test_support.make_bad_fd()
+ self.assertRaises(ValueError, signal.set_wakeup_fd, fd)
+
+
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
class WakeupSignalTests(unittest.TestCase):
TIMEOUT_FULL = 10
@@ -485,8 +492,9 @@
def test_main():
test_support.run_unittest(BasicSignalTests, InterProcessSignalTests,
- WakeupSignalTests, SiginterruptTest,
- ItimerTest, WindowsSignalTests)
+ WakeupFDTests, WakeupSignalTests,
+ SiginterruptTest, ItimerTest,
+ WindowsSignalTests)
if __name__ == "__main__":
diff --git a/lib-python/2.7/test/test_socket.py b/lib-python/2.7/test/test_socket.py
--- a/lib-python/2.7/test/test_socket.py
+++ b/lib-python/2.7/test/test_socket.py
@@ -6,6 +6,7 @@
import errno
import socket
import select
+import _testcapi
import time
import traceback
import Queue
@@ -644,9 +645,10 @@
if SUPPORTS_IPV6:
socket.getaddrinfo('::1', 80)
# port can be a string service name such as "http", a numeric
- # port number or None
+ # port number (int or long), or None
socket.getaddrinfo(HOST, "http")
socket.getaddrinfo(HOST, 80)
+ socket.getaddrinfo(HOST, 80L)
socket.getaddrinfo(HOST, None)
# test family and socktype filters
infos = socket.getaddrinfo(HOST, None, socket.AF_INET)
@@ -699,11 +701,17 @@
def test_sendall_interrupted_with_timeout(self):
self.check_sendall_interrupted(True)
- def testListenBacklog0(self):
+ def test_listen_backlog(self):
+ for backlog in 0, -1:
+ srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ srv.bind((HOST, 0))
+ srv.listen(backlog)
+ srv.close()
+
+ # Issue 15989
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.bind((HOST, 0))
- # backlog = 0
- srv.listen(0)
+ self.assertRaises(OverflowError, srv.listen, _testcapi.INT_MAX + 1)
srv.close()
@unittest.skipUnless(SUPPORTS_IPV6, 'IPv6 required for this test.')
@@ -807,6 +815,11 @@
def _testShutdown(self):
self.serv_conn.send(MSG)
+ # Issue 15989
+ self.assertRaises(OverflowError, self.serv_conn.shutdown,
+ _testcapi.INT_MAX + 1)
+ self.assertRaises(OverflowError, self.serv_conn.shutdown,
+ 2 + (_testcapi.UINT_MAX + 1))
self.serv_conn.shutdown(2)
@unittest.skipUnless(thread, 'Threading required for this test.')
@@ -882,7 +895,10 @@
def testSetBlocking(self):
# Testing whether set blocking works
- self.serv.setblocking(0)
+ self.serv.setblocking(True)
+ self.assertIsNone(self.serv.gettimeout())
+ self.serv.setblocking(False)
+ self.assertEqual(self.serv.gettimeout(), 0.0)
start = time.time()
try:
self.serv.accept()
@@ -890,6 +906,10 @@
pass
end = time.time()
self.assertTrue((end - start) < 1.0, "Error setting non-blocking mode.")
+ # Issue 15989
+ if _testcapi.UINT_MAX < _testcapi.ULONG_MAX:
+ self.serv.setblocking(_testcapi.UINT_MAX + 1)
+ self.assertIsNone(self.serv.gettimeout())
def _testSetBlocking(self):
pass
@@ -961,8 +981,8 @@
def tearDown(self):
self.serv_file.close()
self.assertTrue(self.serv_file.closed)
+ SocketConnectedTest.tearDown(self)
self.serv_file = None
- SocketConnectedTest.tearDown(self)
def clientSetUp(self):
SocketConnectedTest.clientSetUp(self)
@@ -1150,6 +1170,64 @@
bufsize = 1 # Default-buffered for reading; line-buffered for writing
+ class SocketMemo(object):
+ """A wrapper to keep track of sent data, needed to examine write behaviour"""
+ def __init__(self, sock):
+ self._sock = sock
+ self.sent = []
+
+ def send(self, data, flags=0):
+ n = self._sock.send(data, flags)
+ self.sent.append(data[:n])
+ return n
+
+ def sendall(self, data, flags=0):
+ self._sock.sendall(data, flags)
+ self.sent.append(data)
+
+ def __getattr__(self, attr):
+ return getattr(self._sock, attr)
+
+ def getsent(self):
+ return [e.tobytes() if isinstance(e, memoryview) else e for e in self.sent]
+
+ def setUp(self):
+ FileObjectClassTestCase.setUp(self)
+ self.serv_file._sock = self.SocketMemo(self.serv_file._sock)
+
+ def testLinebufferedWrite(self):
+ # Write two lines, in small chunks
+ msg = MSG.strip()
+ print >> self.serv_file, msg,
+ print >> self.serv_file, msg
+
+ # second line:
+ print >> self.serv_file, msg,
+ print >> self.serv_file, msg,
+ print >> self.serv_file, msg
+
+ # third line
+ print >> self.serv_file, ''
+
+ self.serv_file.flush()
+
+ msg1 = "%s %s\n"%(msg, msg)
+ msg2 = "%s %s %s\n"%(msg, msg, msg)
+ msg3 = "\n"
+ self.assertEqual(self.serv_file._sock.getsent(), [msg1, msg2, msg3])
+
+ def _testLinebufferedWrite(self):
+ msg = MSG.strip()
+ msg1 = "%s %s\n"%(msg, msg)
+ msg2 = "%s %s %s\n"%(msg, msg, msg)
+ msg3 = "\n"
+ l1 = self.cli_file.readline()
+ self.assertEqual(l1, msg1)
+ l2 = self.cli_file.readline()
+ self.assertEqual(l2, msg2)
+ l3 = self.cli_file.readline()
+ self.assertEqual(l3, msg3)
+
class SmallBufferedFileObjectClassTestCase(FileObjectClassTestCase):
@@ -1197,7 +1275,26 @@
port = test_support.find_unused_port()
with self.assertRaises(socket.error) as cm:
socket.create_connection((HOST, port))
- self.assertEqual(cm.exception.errno, errno.ECONNREFUSED)
+
+ # Issue #16257: create_connection() calls getaddrinfo() against
+ # 'localhost'. This may result in an IPV6 addr being returned
+ # as well as an IPV4 one:
+ # >>> socket.getaddrinfo('localhost', port, 0, SOCK_STREAM)
+ # >>> [(2, 2, 0, '', ('127.0.0.1', 41230)),
+ # (26, 2, 0, '', ('::1', 41230, 0, 0))]
+ #
+ # create_connection() enumerates through all the addresses returned
+ # and if it doesn't successfully bind to any of them, it propagates
+ # the last exception it encountered.
+ #
+ # On Solaris, ENETUNREACH is returned in this circumstance instead
+ # of ECONNREFUSED. So, if that errno exists, add it to our list of
+ # expected errnos.
+ expected_errnos = [ errno.ECONNREFUSED, ]
+ if hasattr(errno, 'ENETUNREACH'):
+ expected_errnos.append(errno.ENETUNREACH)
+
+ self.assertIn(cm.exception.errno, expected_errnos)
def test_create_connection_timeout(self):
# Issue #9792: create_connection() should not recast timeout errors
diff --git a/lib-python/2.7/test/test_socketserver.py b/lib-python/2.7/test/test_socketserver.py
--- a/lib-python/2.7/test/test_socketserver.py
+++ b/lib-python/2.7/test/test_socketserver.py
@@ -8,6 +8,8 @@
import select
import signal
import socket
+import select
+import errno
import tempfile
import unittest
import SocketServer
@@ -32,8 +34,11 @@
if hasattr(signal, 'alarm'):
signal.alarm(n)
+# Remember real select() to avoid interferences with mocking
+_real_select = select.select
+
def receive(sock, n, timeout=20):
- r, w, x = select.select([sock], [], [], timeout)
+ r, w, x = _real_select([sock], [], [], timeout)
if sock in r:
return sock.recv(n)
else:
@@ -53,7 +58,7 @@
def simple_subprocess(testcase):
pid = os.fork()
if pid == 0:
- # Don't throw an exception; it would be caught by the test harness.
+ # Don't raise an exception; it would be caught by the test harness.
os._exit(72)
yield None
pid2, status = os.waitpid(pid, 0)
@@ -225,6 +230,38 @@
SocketServer.DatagramRequestHandler,
self.dgram_examine)
+ @contextlib.contextmanager
+ def mocked_select_module(self):
+ """Mocks the select.select() call to raise EINTR for first call"""
+ old_select = select.select
+
+ class MockSelect:
+ def __init__(self):
+ self.called = 0
+
+ def __call__(self, *args):
+ self.called += 1
+ if self.called == 1:
+ # raise the exception on first call
+ raise select.error(errno.EINTR, os.strerror(errno.EINTR))
+ else:
+ # Return real select value for consecutive calls
+ return old_select(*args)
+
+ select.select = MockSelect()
+ try:
+ yield select.select
+ finally:
+ select.select = old_select
+
+ def test_InterruptServerSelectCall(self):
+ with self.mocked_select_module() as mock_select:
+ pid = self.run_server(SocketServer.TCPServer,
+ SocketServer.StreamRequestHandler,
+ self.stream_examine)
+ # Make sure select was called again:
+ self.assertGreater(mock_select.called, 1)
+
# Alas, on Linux (at least) recvfrom() doesn't return a meaningful
# client address so this cannot work:
diff --git a/lib-python/2.7/test/test_ssl.py b/lib-python/2.7/test/test_ssl.py
--- a/lib-python/2.7/test/test_ssl.py
+++ b/lib-python/2.7/test/test_ssl.py
@@ -95,12 +95,8 @@
sys.stdout.write("\n RAND_status is %d (%s)\n"
% (v, (v and "sufficient randomness") or
"insufficient randomness"))
- try:
- ssl.RAND_egd(1)
- except TypeError:
- pass
- else:
- print "didn't raise TypeError"
+ self.assertRaises(TypeError, ssl.RAND_egd, 1)
+ self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1)
ssl.RAND_add("this is a random string", 75.0)
def test_parse_cert(self):
@@ -111,13 +107,12 @@
if test_support.verbose:
sys.stdout.write("\n" + pprint.pformat(p) + "\n")
self.assertEqual(p['subject'],
- ((('countryName', u'US'),),
- (('stateOrProvinceName', u'Delaware'),),
- (('localityName', u'Wilmington'),),
- (('organizationName', u'Python Software Foundation'),),
- (('organizationalUnitName', u'SSL'),),
- (('commonName', u'somemachine.python.org'),)),
+ ((('countryName', 'XY'),),
+ (('localityName', 'Castle Anthrax'),),
+ (('organizationName', 'Python Software Foundation'),),
+ (('commonName', 'localhost'),))
)
+ self.assertEqual(p['subjectAltName'], (('DNS', 'localhost'),))
# Issue #13034: the subjectAltName in some certificates
# (notably projects.developer.nokia.com:443) wasn't parsed
p = ssl._ssl._test_decode_cert(NOKIACERT)
@@ -284,6 +279,34 @@
finally:
s.close()
+ def test_timeout_connect_ex(self):
+ # Issue #12065: on a timeout, connect_ex() should return the original
+ # errno (mimicking the behaviour of non-SSL sockets).
+ with test_support.transient_internet("svn.python.org"):
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=SVN_PYTHON_ORG_ROOT_CERT,
+ do_handshake_on_connect=False)
+ try:
+ s.settimeout(0.0000001)
+ rc = s.connect_ex(('svn.python.org', 443))
+ if rc == 0:
+ self.skipTest("svn.python.org responded too quickly")
+ self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
+ finally:
+ s.close()
+
+ def test_connect_ex_error(self):
+ with test_support.transient_internet("svn.python.org"):
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
+ try:
+ self.assertEqual(errno.ECONNREFUSED,
+ s.connect_ex(("svn.python.org", 444)))
+ finally:
+ s.close()
+
@unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
def test_makefile_close(self):
# Issue #5238: creating a file-like object with makefile() shouldn't
@@ -355,7 +378,8 @@
# SHA256 was added in OpenSSL 0.9.8
if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
- # NOTE: https://sha256.tbs-internet.com is another possible test host
+ self.skipTest("remote host needs SNI, only available on Python 3.2+")
+ # NOTE: https://sha2.hboeck.de is another possible test host
remote = ("sha256.tbs-internet.com", 443)
sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
with test_support.transient_internet("sha256.tbs-internet.com"):
diff --git a/lib-python/2.7/test/test_str.py b/lib-python/2.7/test/test_str.py
--- a/lib-python/2.7/test/test_str.py
+++ b/lib-python/2.7/test/test_str.py
@@ -35,6 +35,18 @@
string_tests.MixinStrUnicodeUserStringTest.test_formatting(self)
self.assertRaises(OverflowError, '%c'.__mod__, 0x1234)
+ @test_support.cpython_only
+ def test_formatting_huge_precision(self):
+ from _testcapi import INT_MAX
+ format_string = "%.{}f".format(INT_MAX + 1)
+ with self.assertRaises(ValueError):
+ result = format_string % 2.34
+
+ def test_formatting_huge_width(self):
+ format_string = "%{}f".format(sys.maxsize + 1)
+ with self.assertRaises(ValueError):
+ result = format_string % 2.34
+
def test_conversion(self):
# Make sure __str__() behaves properly
class Foo0:
@@ -371,6 +383,21 @@
self.assertRaises(ValueError, format, "", "-")
self.assertRaises(ValueError, "{0:=s}".format, '')
+ def test_format_huge_precision(self):
+ format_string = ".{}f".format(sys.maxsize + 1)
+ with self.assertRaises(ValueError):
+ result = format(2.34, format_string)
+
+ def test_format_huge_width(self):
+ format_string = "{}f".format(sys.maxsize + 1)
+ with self.assertRaises(ValueError):
+ result = format(2.34, format_string)
+
+ def test_format_huge_item_number(self):
+ format_string = "{{{}:.6f}}".format(sys.maxsize + 1)
+ with self.assertRaises(ValueError):
+ result = format_string.format(2.34)
+
def test_format_auto_numbering(self):
class C:
def __init__(self, x=100):
diff --git a/lib-python/2.7/test/test_strptime.py b/lib-python/2.7/test/test_strptime.py
--- a/lib-python/2.7/test/test_strptime.py
+++ b/lib-python/2.7/test/test_strptime.py
@@ -378,6 +378,14 @@
need_escaping = ".^$*+?{}\[]|)("
self.assertTrue(_strptime._strptime_time(need_escaping, need_escaping))
+ def test_feb29_on_leap_year_without_year(self):
+ time.strptime("Feb 29", "%b %d")
+
+ def test_mar1_comes_after_feb29_even_when_omitting_the_year(self):
+ self.assertLess(
+ time.strptime("Feb 29", "%b %d"),
+ time.strptime("Mar 1", "%b %d"))
+
class Strptime12AMPMTests(unittest.TestCase):
"""Test a _strptime regression in '%I %p' at 12 noon (12 PM)"""
diff --git a/lib-python/2.7/test/test_struct.py b/lib-python/2.7/test/test_struct.py
--- a/lib-python/2.7/test/test_struct.py
+++ b/lib-python/2.7/test/test_struct.py
@@ -3,7 +3,8 @@
import unittest
import struct
import inspect
-from test.test_support import run_unittest, check_warnings, check_py3k_warnings
+from test import test_support as support
+from test.test_support import (check_warnings, check_py3k_warnings)
import sys
ISBIGENDIAN = sys.byteorder == "big"
@@ -544,8 +545,29 @@
hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
self.assertRaises(struct.error, struct.calcsize, hugecount2)
+ def check_sizeof(self, format_str, number_of_codes):
+ # The size of 'PyStructObject'
+ totalsize = support.calcobjsize('5P')
+ # The size taken up by the 'formatcode' dynamic array
+ totalsize += struct.calcsize('3P') * (number_of_codes + 1)
+ support.check_sizeof(self, struct.Struct(format_str), totalsize)
+
+ @support.cpython_only
+ def test__sizeof__(self):
+ for code in integer_codes:
+ self.check_sizeof(code, 1)
+ self.check_sizeof('BHILfdspP', 9)
+ self.check_sizeof('B' * 1234, 1234)
+ self.check_sizeof('fd', 2)
+ self.check_sizeof('xxxxxxxxxxxxxx', 0)
+ self.check_sizeof('100H', 100)
+ self.check_sizeof('187s', 1)
+ self.check_sizeof('20p', 1)
+ self.check_sizeof('0s', 1)
+ self.check_sizeof('0c', 0)
+
def test_main():
- run_unittest(StructTest)
+ support.run_unittest(StructTest)
if __name__ == '__main__':
test_main()
diff --git a/lib-python/2.7/test/test_subprocess.py b/lib-python/2.7/test/test_subprocess.py
--- a/lib-python/2.7/test/test_subprocess.py
+++ b/lib-python/2.7/test/test_subprocess.py
@@ -58,6 +58,18 @@
self.assertEqual(actual, expected, msg)
+class PopenTestException(Exception):
+ pass
+
+
+class PopenExecuteChildRaises(subprocess.Popen):
+ """Popen subclass for testing cleanup of subprocess.PIPE filehandles when
+ _execute_child fails.
+ """
+ def _execute_child(self, *args, **kwargs):
+ raise PopenTestException("Forced Exception for Test")
+
+
class ProcessTestCase(BaseTestCase):
def test_call_seq(self):
@@ -526,6 +538,7 @@
finally:
for h in handles:
os.close(h)
+ test_support.unlink(test_support.TESTFN)
def test_list2cmdline(self):
self.assertEqual(subprocess.list2cmdline(['a b c', 'd', 'e']),
@@ -631,6 +644,27 @@
time.sleep(2)
p.communicate("x" * 2**20)
+ # This test is Linux-ish specific for simplicity to at least have
+ # some coverage. It is not a platform specific bug.
+ @unittest.skipUnless(os.path.isdir('/proc/%d/fd' % os.getpid()),
+ "Linux specific")
+ def test_failed_child_execute_fd_leak(self):
+ """Test for the fork() failure fd leak reported in issue16327."""
+ fd_directory = '/proc/%d/fd' % os.getpid()
+ fds_before_popen = os.listdir(fd_directory)
+ with self.assertRaises(PopenTestException):
+ PopenExecuteChildRaises(
+ [sys.executable, '-c', 'pass'], stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ # NOTE: This test doesn't verify that the real _execute_child
+ # does not close the file descriptors itself on the way out
+ # during an exception. Code inspection has confirmed that.
+
+ fds_after_exception = os.listdir(fd_directory)
+ self.assertEqual(fds_before_popen, fds_after_exception)
+
+
# context manager
class _SuppressCoreFiles(object):
"""Try to prevent core files from being created."""
@@ -717,6 +751,52 @@
self.addCleanup(p.stdout.close)
self.assertEqual(p.stdout.read(), "apple")
+ class _TestExecuteChildPopen(subprocess.Popen):
+ """Used to test behavior at the end of _execute_child."""
+ def __init__(self, testcase, *args, **kwargs):
+ self._testcase = testcase
+ subprocess.Popen.__init__(self, *args, **kwargs)
+
+ def _execute_child(
+ self, args, executable, preexec_fn, close_fds, cwd, env,
+ universal_newlines, startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+ try:
+ subprocess.Popen._execute_child(
+ self, args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+ finally:
+ # Open a bunch of file descriptors and verify that
+ # none of them are the same as the ones the Popen
+ # instance is using for stdin/stdout/stderr.
+ devzero_fds = [os.open("/dev/zero", os.O_RDONLY)
+ for _ in range(8)]
+ try:
+ for fd in devzero_fds:
+ self._testcase.assertNotIn(
+ fd, (p2cwrite, c2pread, errread))
+ finally:
+ map(os.close, devzero_fds)
+
+ @unittest.skipIf(not os.path.exists("/dev/zero"), "/dev/zero required.")
+ def test_preexec_errpipe_does_not_double_close_pipes(self):
+ """Issue16140: Don't double close pipes on preexec error."""
+
+ def raise_it():
+ raise RuntimeError("force the _execute_child() errpipe_data path.")
+
+ with self.assertRaises(RuntimeError):
+ self._TestExecuteChildPopen(
+ self, [sys.executable, "-c", "pass"],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, preexec_fn=raise_it)
+
def test_args_string(self):
# args is a string
f, fname = mkstemp()
@@ -812,6 +892,8 @@
getattr(p, method)(*args)
return p
+ @unittest.skipIf(sys.platform.startswith(('netbsd', 'openbsd')),
+ "Due to known OS bug (issue #16762)")
def _kill_dead_process(self, method, *args):
# Do not inherit file handles from the parent.
# It should fix failures on some platforms.
diff --git a/lib-python/2.7/test/test_support.py b/lib-python/2.7/test/test_support.py
--- a/lib-python/2.7/test/test_support.py
+++ b/lib-python/2.7/test/test_support.py
@@ -18,6 +18,9 @@
import UserDict
import re
import time
+import struct
+import _testcapi
+import sysconfig
try:
import thread
except ImportError:
@@ -179,15 +182,79 @@
except KeyError:
pass
+if sys.platform.startswith("win"):
+ def _waitfor(func, pathname, waitall=False):
+ # Peform the operation
+ func(pathname)
+ # Now setup the wait loop
+ if waitall:
+ dirname = pathname
+ else:
+ dirname, name = os.path.split(pathname)
+ dirname = dirname or '.'
+ # Check for `pathname` to be removed from the filesystem.
+ # The exponential backoff of the timeout amounts to a total
+ # of ~1 second after which the deletion is probably an error
+ # anyway.
+ # Testing on a i7 at 4.3GHz shows that usually only 1 iteration is
+ # required when contention occurs.
+ timeout = 0.001
+ while timeout < 1.0:
+ # Note we are only testing for the existance of the file(s) in
+ # the contents of the directory regardless of any security or
+ # access rights. If we have made it this far, we have sufficient
+ # permissions to do that much using Python's equivalent of the
+ # Windows API FindFirstFile.
+ # Other Windows APIs can fail or give incorrect results when
+ # dealing with files that are pending deletion.
+ L = os.listdir(dirname)
+ if not (L if waitall else name in L):
+ return
+ # Increase the timeout and try again
+ time.sleep(timeout)
+ timeout *= 2
+ warnings.warn('tests may fail, delete still pending for ' + pathname,
+ RuntimeWarning, stacklevel=4)
+
+ def _unlink(filename):
+ _waitfor(os.unlink, filename)
+
+ def _rmdir(dirname):
+ _waitfor(os.rmdir, dirname)
+
+ def _rmtree(path):
+ def _rmtree_inner(path):
+ for name in os.listdir(path):
+ fullname = os.path.join(path, name)
+ if os.path.isdir(fullname):
+ _waitfor(_rmtree_inner, fullname, waitall=True)
+ os.rmdir(fullname)
+ else:
+ os.unlink(fullname)
+ _waitfor(_rmtree_inner, path, waitall=True)
+ _waitfor(os.rmdir, path)
+else:
+ _unlink = os.unlink
+ _rmdir = os.rmdir
+ _rmtree = shutil.rmtree
+
def unlink(filename):
try:
- os.unlink(filename)
+ _unlink(filename)
except OSError:
pass
+def rmdir(dirname):
+ try:
+ _rmdir(dirname)
+ except OSError as error:
+ # The directory need not exist.
+ if error.errno != errno.ENOENT:
+ raise
+
def rmtree(path):
try:
- shutil.rmtree(path)
+ _rmtree(path)
except OSError, e:
# Unix returns ENOENT, Windows returns ESRCH.
if e.errno not in (errno.ENOENT, errno.ESRCH):
@@ -405,7 +472,7 @@
the CWD, an error is raised. If it's True, only a warning is raised
and the original CWD is used.
"""
- if isinstance(name, unicode):
+ if have_unicode and isinstance(name, unicode):
try:
name = name.encode(sys.getfilesystemencoding() or 'ascii')
except UnicodeEncodeError:
@@ -767,6 +834,9 @@
('EAI_FAIL', -4),
('EAI_NONAME', -2),
('EAI_NODATA', -5),
+ # Windows defines EAI_NODATA as 11001 but idiotic getaddrinfo()
+ # implementation actually returns WSANO_DATA i.e. 11004.
+ ('WSANO_DATA', 11004),
]
denied = ResourceDenied("Resource '%s' is not available" % resource_name)
@@ -858,6 +928,32 @@
gc.collect()
+_header = '2P'
+if hasattr(sys, "gettotalrefcount"):
+ _header = '2P' + _header
+_vheader = _header + 'P'
+
+def calcobjsize(fmt):
+ return struct.calcsize(_header + fmt + '0P')
+
+def calcvobjsize(fmt):
+ return struct.calcsize(_vheader + fmt + '0P')
+
+
+_TPFLAGS_HAVE_GC = 1<<14
+_TPFLAGS_HEAPTYPE = 1<<9
+
+def check_sizeof(test, o, size):
+ result = sys.getsizeof(o)
+ # add GC header size
+ if ((type(o) == type) and (o.__flags__ & _TPFLAGS_HEAPTYPE) or\
+ ((type(o) != type) and (type(o).__flags__ & _TPFLAGS_HAVE_GC))):
+ size += _testcapi.SIZEOF_PYGC_HEAD
+ msg = 'wrong size for %s: got %d, expected %d' \
+ % (type(o), result, size)
+ test.assertEqual(result, size, msg)
+
+
#=======================================================================
# Decorator for running a function in a different locale, correctly resetting
# it afterwards.
@@ -966,7 +1062,7 @@
return wrapper
return decorator
-def precisionbigmemtest(size, memuse, overhead=5*_1M):
+def precisionbigmemtest(size, memuse, overhead=5*_1M, dry_run=True):
def decorator(f):
def wrapper(self):
if not real_max_memuse:
@@ -974,11 +1070,12 @@
else:
maxsize = size
- if real_max_memuse and real_max_memuse < maxsize * memuse:
- if verbose:
- sys.stderr.write("Skipping %s because of memory "
- "constraint\n" % (f.__name__,))
- return
+ if ((real_max_memuse or not dry_run)
+ and real_max_memuse < maxsize * memuse):
+ if verbose:
+ sys.stderr.write("Skipping %s because of memory "
+ "constraint\n" % (f.__name__,))
+ return
return f(self, maxsize)
wrapper.size = size
@@ -1093,6 +1190,16 @@
suite.addTest(unittest.makeSuite(cls))
_run_suite(suite)
+#=======================================================================
+# Check for the presence of docstrings.
+
+HAVE_DOCSTRINGS = (check_impl_detail(cpython=False) or
+ sys.platform == 'win32' or
+ sysconfig.get_config_var('WITH_DOC_STRINGS'))
+
+requires_docstrings = unittest.skipUnless(HAVE_DOCSTRINGS,
+ "test requires docstrings")
+
#=======================================================================
# doctest driver.
@@ -1192,6 +1299,33 @@
except:
break
+ at contextlib.contextmanager
+def swap_attr(obj, attr, new_val):
+ """Temporary swap out an attribute with a new object.
+
+ Usage:
+ with swap_attr(obj, "attr", 5):
+ ...
+
+ This will set obj.attr to 5 for the duration of the with: block,
+ restoring the old value at the end of the block. If `attr` doesn't
+ exist on `obj`, it will be created and then deleted at the end of the
+ block.
+ """
+ if hasattr(obj, attr):
+ real_val = getattr(obj, attr)
+ setattr(obj, attr, new_val)
+ try:
+ yield
+ finally:
+ setattr(obj, attr, real_val)
+ else:
+ setattr(obj, attr, new_val)
+ try:
+ yield
+ finally:
+ delattr(obj, attr)
+
def py3k_bytes(b):
"""Emulate the py3k bytes() constructor.
diff --git a/lib-python/2.7/test/test_sys.py b/lib-python/2.7/test/test_sys.py
--- a/lib-python/2.7/test/test_sys.py
+++ b/lib-python/2.7/test/test_sys.py
@@ -490,22 +490,8 @@
class SizeofTest(unittest.TestCase):
- TPFLAGS_HAVE_GC = 1<<14
- TPFLAGS_HEAPTYPE = 1L<<9
-
def setUp(self):
- self.c = len(struct.pack('c', ' '))
- self.H = len(struct.pack('H', 0))
- self.i = len(struct.pack('i', 0))
- self.l = len(struct.pack('l', 0))
- self.P = len(struct.pack('P', 0))
- # due to missing size_t information from struct, it is assumed that
- # sizeof(Py_ssize_t) = sizeof(void*)
- self.header = 'PP'
- self.vheader = self.header + 'P'
- if hasattr(sys, "gettotalrefcount"):
- self.header += '2P'
- self.vheader += '2P'
+ self.P = struct.calcsize('P')
self.longdigit = sys.long_info.sizeof_digit
import _testcapi
self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD
@@ -515,128 +501,109 @@
self.file.close()
test.test_support.unlink(test.test_support.TESTFN)
- def check_sizeof(self, o, size):
- result = sys.getsizeof(o)
- if ((type(o) == type) and (o.__flags__ & self.TPFLAGS_HEAPTYPE) or\
- ((type(o) != type) and (type(o).__flags__ & self.TPFLAGS_HAVE_GC))):
- size += self.gc_headsize
- msg = 'wrong size for %s: got %d, expected %d' \
- % (type(o), result, size)
- self.assertEqual(result, size, msg)
-
- def calcsize(self, fmt):
- """Wrapper around struct.calcsize which enforces the alignment of the
- end of a structure to the alignment requirement of pointer.
-
- Note: This wrapper should only be used if a pointer member is included
- and no member with a size larger than a pointer exists.
- """
- return struct.calcsize(fmt + '0P')
+ check_sizeof = test.test_support.check_sizeof
def test_gc_head_size(self):
# Check that the gc header size is added to objects tracked by the gc.
- h = self.header
- size = self.calcsize
+ size = test.test_support.calcobjsize
gc_header_size = self.gc_headsize
# bool objects are not gc tracked
- self.assertEqual(sys.getsizeof(True), size(h + 'l'))
+ self.assertEqual(sys.getsizeof(True), size('l'))
# but lists are
- self.assertEqual(sys.getsizeof([]), size(h + 'P PP') + gc_header_size)
+ self.assertEqual(sys.getsizeof([]), size('P PP') + gc_header_size)
def test_default(self):
- h = self.header
- size = self.calcsize
- self.assertEqual(sys.getsizeof(True, -1), size(h + 'l'))
+ size = test.test_support.calcobjsize
+ self.assertEqual(sys.getsizeof(True, -1), size('l'))
def test_objecttypes(self):
# check all types defined in Objects/
- h = self.header
- vh = self.vheader
- size = self.calcsize
+ size = test.test_support.calcobjsize
+ vsize = test.test_support.calcvobjsize
check = self.check_sizeof
# bool
- check(True, size(h + 'l'))
+ check(True, size('l'))
# buffer
with test.test_support.check_py3k_warnings():
- check(buffer(''), size(h + '2P2Pil'))
+ check(buffer(''), size('2P2Pil'))
# builtin_function_or_method
- check(len, size(h + '3P'))
+ check(len, size('3P'))
# bytearray
samples = ['', 'u'*100000]
for sample in samples:
x = bytearray(sample)
- check(x, size(vh + 'iPP') + x.__alloc__() * self.c)
+ check(x, vsize('iPP') + x.__alloc__())
# bytearray_iterator
- check(iter(bytearray()), size(h + 'PP'))
+ check(iter(bytearray()), size('PP'))
# cell
def get_cell():
x = 42
def inner():
return x
return inner
- check(get_cell().func_closure[0], size(h + 'P'))
+ check(get_cell().func_closure[0], size('P'))
# classobj (old-style class)
class class_oldstyle():
def method():
pass
- check(class_oldstyle, size(h + '7P'))
+ check(class_oldstyle, size('7P'))
# instance (old-style class)
- check(class_oldstyle(), size(h + '3P'))
+ check(class_oldstyle(), size('3P'))
# instancemethod (old-style class)
- check(class_oldstyle().method, size(h + '4P'))
+ check(class_oldstyle().method, size('4P'))
# complex
- check(complex(0,1), size(h + '2d'))
+ check(complex(0,1), size('2d'))
# code
- check(get_cell().func_code, size(h + '4i8Pi3P'))
+ check(get_cell().func_code, size('4i8Pi3P'))
# BaseException
- check(BaseException(), size(h + '3P'))
+ check(BaseException(), size('3P'))
# UnicodeEncodeError
- check(UnicodeEncodeError("", u"", 0, 0, ""), size(h + '5P2PP'))
+ check(UnicodeEncodeError("", u"", 0, 0, ""), size('5P2PP'))
# UnicodeDecodeError
- check(UnicodeDecodeError("", "", 0, 0, ""), size(h + '5P2PP'))
+ check(UnicodeDecodeError("", "", 0, 0, ""), size('5P2PP'))
# UnicodeTranslateError
- check(UnicodeTranslateError(u"", 0, 1, ""), size(h + '5P2PP'))
+ check(UnicodeTranslateError(u"", 0, 1, ""), size('5P2PP'))
# method_descriptor (descriptor object)
- check(str.lower, size(h + '2PP'))
+ check(str.lower, size('2PP'))
# classmethod_descriptor (descriptor object)
# XXX
# member_descriptor (descriptor object)
import datetime
- check(datetime.timedelta.days, size(h + '2PP'))
+ check(datetime.timedelta.days, size('2PP'))
# getset_descriptor (descriptor object)
import __builtin__
- check(__builtin__.file.closed, size(h + '2PP'))
+ check(__builtin__.file.closed, size('2PP'))
# wrapper_descriptor (descriptor object)
- check(int.__add__, size(h + '2P2P'))
+ check(int.__add__, size('2P2P'))
# dictproxy
class C(object): pass
- check(C.__dict__, size(h + 'P'))
+ check(C.__dict__, size('P'))
# method-wrapper (descriptor object)
- check({}.__iter__, size(h + '2P'))
+ check({}.__iter__, size('2P'))
# dict
- check({}, size(h + '3P2P' + 8*'P2P'))
+ check({}, size('3P2P' + 8*'P2P'))
x = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8}
- check(x, size(h + '3P2P' + 8*'P2P') + 16*size('P2P'))
+ check(x, size('3P2P' + 8*'P2P') + 16*struct.calcsize('P2P'))
# dictionary-keyiterator
- check({}.iterkeys(), size(h + 'P2PPP'))
+ check({}.iterkeys(), size('P2PPP'))
# dictionary-valueiterator
- check({}.itervalues(), size(h + 'P2PPP'))
+ check({}.itervalues(), size('P2PPP'))
# dictionary-itemiterator
- check({}.iteritems(), size(h + 'P2PPP'))
+ check({}.iteritems(), size('P2PPP'))
# ellipses
- check(Ellipsis, size(h + ''))
+ check(Ellipsis, size(''))
# EncodingMap
import codecs, encodings.iso8859_3
x = codecs.charmap_build(encodings.iso8859_3.decoding_table)
- check(x, size(h + '32B2iB'))
+ check(x, size('32B2iB'))
# enumerate
- check(enumerate([]), size(h + 'l3P'))
+ check(enumerate([]), size('l3P'))
# file
- check(self.file, size(h + '4P2i4P3i3P3i'))
+ check(self.file, size('4P2i4P3i3P3i'))
# float
- check(float(0), size(h + 'd'))
+ check(float(0), size('d'))
# sys.floatinfo
- check(sys.float_info, size(vh) + self.P * len(sys.float_info))
+ check(sys.float_info, vsize('') + self.P * len(sys.float_info))
# frame
import inspect
CO_MAXBLOCKS = 20
@@ -645,10 +612,10 @@
nfrees = len(x.f_code.co_freevars)
extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\
ncells + nfrees - 1
- check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
+ check(x, vsize('12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
# function
def func(): pass
- check(func, size(h + '9P'))
+ check(func, size('9P'))
class c():
@staticmethod
def foo():
@@ -657,65 +624,65 @@
def bar(cls):
pass
# staticmethod
- check(foo, size(h + 'P'))
+ check(foo, size('P'))
# classmethod
- check(bar, size(h + 'P'))
+ check(bar, size('P'))
# generator
def get_gen(): yield 1
- check(get_gen(), size(h + 'Pi2P'))
+ check(get_gen(), size('Pi2P'))
# integer
- check(1, size(h + 'l'))
- check(100, size(h + 'l'))
+ check(1, size('l'))
+ check(100, size('l'))
# iterator
- check(iter('abc'), size(h + 'lP'))
+ check(iter('abc'), size('lP'))
# callable-iterator
import re
- check(re.finditer('',''), size(h + '2P'))
+ check(re.finditer('',''), size('2P'))
# list
samples = [[], [1,2,3], ['1', '2', '3']]
for sample in samples:
- check(sample, size(vh + 'PP') + len(sample)*self.P)
+ check(sample, vsize('PP') + len(sample)*self.P)
# sortwrapper (list)
# XXX
# cmpwrapper (list)
# XXX
# listiterator (list)
- check(iter([]), size(h + 'lP'))
+ check(iter([]), size('lP'))
# listreverseiterator (list)
- check(reversed([]), size(h + 'lP'))
+ check(reversed([]), size('lP'))
# long
- check(0L, size(vh))
- check(1L, size(vh) + self.longdigit)
- check(-1L, size(vh) + self.longdigit)
+ check(0L, vsize(''))
+ check(1L, vsize('') + self.longdigit)
+ check(-1L, vsize('') + self.longdigit)
PyLong_BASE = 2**sys.long_info.bits_per_digit
- check(long(PyLong_BASE), size(vh) + 2*self.longdigit)
- check(long(PyLong_BASE**2-1), size(vh) + 2*self.longdigit)
- check(long(PyLong_BASE**2), size(vh) + 3*self.longdigit)
+ check(long(PyLong_BASE), vsize('') + 2*self.longdigit)
+ check(long(PyLong_BASE**2-1), vsize('') + 2*self.longdigit)
+ check(long(PyLong_BASE**2), vsize('') + 3*self.longdigit)
# module
- check(unittest, size(h + 'P'))
+ check(unittest, size('P'))
# None
- check(None, size(h + ''))
+ check(None, size(''))
# object
- check(object(), size(h + ''))
+ check(object(), size(''))
# property (descriptor object)
class C(object):
def getx(self): return self.__x
def setx(self, value): self.__x = value
def delx(self): del self.__x
x = property(getx, setx, delx, "")
- check(x, size(h + '4Pi'))
+ check(x, size('4Pi'))
# PyCObject
# PyCapsule
# XXX
# rangeiterator
- check(iter(xrange(1)), size(h + '4l'))
+ check(iter(xrange(1)), size('4l'))
# reverse
- check(reversed(''), size(h + 'PP'))
+ check(reversed(''), size('PP'))
# set
# frozenset
PySet_MINSIZE = 8
samples = [[], range(10), range(50)]
- s = size(h + '3P2P' + PySet_MINSIZE*'lP' + 'lP')
+ s = size('3P2P' + PySet_MINSIZE*'lP' + 'lP')
for sample in samples:
minused = len(sample)
if minused == 0: tmp = 1
@@ -732,23 +699,24 @@
check(set(sample), s + newsize*struct.calcsize('lP'))
check(frozenset(sample), s + newsize*struct.calcsize('lP'))
# setiterator
- check(iter(set()), size(h + 'P3P'))
+ check(iter(set()), size('P3P'))
# slice
- check(slice(1), size(h + '3P'))
+ check(slice(1), size('3P'))
# str
- check('', struct.calcsize(vh + 'li') + 1)
- check('abc', struct.calcsize(vh + 'li') + 1 + 3*self.c)
+ vh = test.test_support._vheader
+ check('', struct.calcsize(vh + 'lic'))
+ check('abc', struct.calcsize(vh + 'lic') + 3)
# super
- check(super(int), size(h + '3P'))
+ check(super(int), size('3P'))
# tuple
- check((), size(vh))
- check((1,2,3), size(vh) + 3*self.P)
+ check((), vsize(''))
+ check((1,2,3), vsize('') + 3*self.P)
# tupleiterator
- check(iter(()), size(h + 'lP'))
+ check(iter(()), size('lP'))
# type
# (PyTypeObject + PyNumberMethods + PyMappingMethods +
# PySequenceMethods + PyBufferProcs)
- s = size(vh + 'P2P15Pl4PP9PP11PI') + size('41P 10P 3P 6P')
+ s = vsize('P2P15Pl4PP9PP11PI') + struct.calcsize('41P 10P 3P 6P')
class newstyleclass(object):
pass
check(newstyleclass, s)
@@ -763,41 +731,40 @@
# we need to test for both sizes, because we don't know if the string
# has been cached
for s in samples:
- check(s, size(h + 'PPlP') + usize * (len(s) + 1))
+ check(s, size('PPlP') + usize * (len(s) + 1))
# weakref
import weakref
- check(weakref.ref(int), size(h + '2Pl2P'))
+ check(weakref.ref(int), size('2Pl2P'))
# weakproxy
# XXX
# weakcallableproxy
- check(weakref.proxy(int), size(h + '2Pl2P'))
+ check(weakref.proxy(int), size('2Pl2P'))
# xrange
- check(xrange(1), size(h + '3l'))
- check(xrange(66000), size(h + '3l'))
+ check(xrange(1), size('3l'))
+ check(xrange(66000), size('3l'))
def test_pythontypes(self):
# check all types defined in Python/
- h = self.header
- vh = self.vheader
- size = self.calcsize
+ size = test.test_support.calcobjsize
+ vsize = test.test_support.calcvobjsize
check = self.check_sizeof
# _ast.AST
import _ast
- check(_ast.AST(), size(h + ''))
+ check(_ast.AST(), size(''))
# imp.NullImporter
import imp
- check(imp.NullImporter(self.file.name), size(h + ''))
+ check(imp.NullImporter(self.file.name), size(''))
try:
raise TypeError
except TypeError:
tb = sys.exc_info()[2]
# traceback
if tb != None:
- check(tb, size(h + '2P2i'))
+ check(tb, size('2P2i'))
# symtable entry
# XXX
# sys.flags
- check(sys.flags, size(vh) + self.P * len(sys.flags))
+ check(sys.flags, vsize('') + self.P * len(sys.flags))
def test_main():
diff --git a/lib-python/2.7/test/test_sys_settrace.py b/lib-python/2.7/test/test_sys_settrace.py
--- a/lib-python/2.7/test/test_sys_settrace.py
+++ b/lib-python/2.7/test/test_sys_settrace.py
@@ -417,7 +417,7 @@
except ValueError:
pass
else:
- self.fail("exception not thrown!")
+ self.fail("exception not raised!")
except RuntimeError:
self.fail("recursion counter not reset")
@@ -670,6 +670,14 @@
no_jump_to_non_integers.jump = (2, "Spam")
no_jump_to_non_integers.output = [True]
+def jump_across_with(output):
+ with open(test_support.TESTFN, "wb") as fp:
+ pass
+ with open(test_support.TESTFN, "wb") as fp:
+ pass
+jump_across_with.jump = (1, 3)
+jump_across_with.output = []
+
# This verifies that you can't set f_lineno via _getframe or similar
# trickery.
def no_jump_without_trace_function():
@@ -739,6 +747,9 @@
self.run_test(no_jump_to_non_integers)
def test_19_no_jump_without_trace_function(self):
no_jump_without_trace_function()
+ def test_jump_across_with(self):
+ self.addCleanup(test_support.unlink, test_support.TESTFN)
+ self.run_test(jump_across_with)
def test_20_large_function(self):
d = {}
diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py
--- a/lib-python/2.7/test/test_sysconfig.py
+++ b/lib-python/2.7/test/test_sysconfig.py
@@ -14,6 +14,7 @@
get_path, get_path_names, _INSTALL_SCHEMES,
_get_default_scheme, _expand_vars,
get_scheme_names, get_config_var)
+import _osx_support
class TestSysConfig(unittest.TestCase):
@@ -137,6 +138,7 @@
('Darwin Kernel Version 8.11.1: '
'Wed Oct 10 18:23:28 PDT 2007; '
'root:xnu-792.25.20~1/RELEASE_I386'), 'PowerPC'))
+ _osx_support._remove_original_values(get_config_vars())
get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3'
get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g '
@@ -156,6 +158,7 @@
('Darwin Kernel Version 8.11.1: '
'Wed Oct 10 18:23:28 PDT 2007; '
'root:xnu-792.25.20~1/RELEASE_I386'), 'i386'))
+ _osx_support._remove_original_values(get_config_vars())
get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3'
get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g '
@@ -171,6 +174,7 @@
sys.maxint = maxint
# macbook with fat binaries (fat, universal or fat64)
+ _osx_support._remove_original_values(get_config_vars())
get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4'
get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot '
'/Developer/SDKs/MacOSX10.4u.sdk '
@@ -179,6 +183,7 @@
self.assertEqual(get_platform(), 'macosx-10.4-fat')
+ _osx_support._remove_original_values(get_config_vars())
get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot '
'/Developer/SDKs/MacOSX10.4u.sdk '
'-fno-strict-aliasing -fno-common '
@@ -186,18 +191,21 @@
self.assertEqual(get_platform(), 'macosx-10.4-intel')
+ _osx_support._remove_original_values(get_config_vars())
get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc -arch i386 -isysroot '
'/Developer/SDKs/MacOSX10.4u.sdk '
'-fno-strict-aliasing -fno-common '
'-dynamic -DNDEBUG -g -O3')
self.assertEqual(get_platform(), 'macosx-10.4-fat3')
+ _osx_support._remove_original_values(get_config_vars())
get_config_vars()['CFLAGS'] = ('-arch ppc64 -arch x86_64 -arch ppc -arch i386 -isysroot '
'/Developer/SDKs/MacOSX10.4u.sdk '
'-fno-strict-aliasing -fno-common '
'-dynamic -DNDEBUG -g -O3')
self.assertEqual(get_platform(), 'macosx-10.4-universal')
+ _osx_support._remove_original_values(get_config_vars())
get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc64 -isysroot '
'/Developer/SDKs/MacOSX10.4u.sdk '
'-fno-strict-aliasing -fno-common '
@@ -206,6 +214,7 @@
self.assertEqual(get_platform(), 'macosx-10.4-fat64')
for arch in ('ppc', 'i386', 'x86_64', 'ppc64'):
+ _osx_support._remove_original_values(get_config_vars())
get_config_vars()['CFLAGS'] = ('-arch %s -isysroot '
'/Developer/SDKs/MacOSX10.4u.sdk '
'-fno-strict-aliasing -fno-common '
diff --git a/lib-python/2.7/test/test_tarfile.py b/lib-python/2.7/test/test_tarfile.py
--- a/lib-python/2.7/test/test_tarfile.py
+++ b/lib-python/2.7/test/test_tarfile.py
@@ -154,6 +154,9 @@
def test_fileobj_symlink2(self):
self._test_fileobj_link("./ustar/linktest2/symtype", "ustar/linktest1/regtype")
+ def test_issue14160(self):
+ self._test_fileobj_link("symtype2", "ustar/regtype")
+
class CommonReadTest(ReadTest):
@@ -294,26 +297,21 @@
def test_extract_hardlink(self):
# Test hardlink extraction (e.g. bug #857297).
- tar = tarfile.open(tarname, errorlevel=1, encoding="iso8859-1")
+ with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar:
+ tar.extract("ustar/regtype", TEMPDIR)
+ self.addCleanup(os.remove, os.path.join(TEMPDIR, "ustar/regtype"))
- tar.extract("ustar/regtype", TEMPDIR)
- try:
tar.extract("ustar/lnktype", TEMPDIR)
- except EnvironmentError, e:
- if e.errno == errno.ENOENT:
- self.fail("hardlink not extracted properly")
+ self.addCleanup(os.remove, os.path.join(TEMPDIR, "ustar/lnktype"))
+ with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f:
+ data = f.read()
+ self.assertEqual(md5sum(data), md5_regtype)
- data = open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb").read()
- self.assertEqual(md5sum(data), md5_regtype)
-
- try:
tar.extract("ustar/symtype", TEMPDIR)
- except EnvironmentError, e:
- if e.errno == errno.ENOENT:
- self.fail("symlink not extracted properly")
-
- data = open(os.path.join(TEMPDIR, "ustar/symtype"), "rb").read()
- self.assertEqual(md5sum(data), md5_regtype)
+ self.addCleanup(os.remove, os.path.join(TEMPDIR, "ustar/symtype"))
+ with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f:
+ data = f.read()
+ self.assertEqual(md5sum(data), md5_regtype)
def test_extractall(self):
# Test if extractall() correctly restores directory permissions
@@ -855,7 +853,7 @@
tar = tarfile.open(tmpname, "r")
for t in tar:
- self.assert_(t.name == "." or t.name.startswith("./"))
+ self.assertTrue(t.name == "." or t.name.startswith("./"))
tar.close()
finally:
os.chdir(cwd)
diff --git a/lib-python/2.7/test/test_tcl.py b/lib-python/2.7/test/test_tcl.py
--- a/lib-python/2.7/test/test_tcl.py
+++ b/lib-python/2.7/test/test_tcl.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
import unittest
+import sys
import os
from test import test_support
@@ -151,6 +152,27 @@
# exit code must be zero
self.assertEqual(f.close(), None)
+ def test_passing_values(self):
+ def passValue(value):
+ return self.interp.call('set', '_', value)
+ self.assertEqual(passValue(True), True)
+ self.assertEqual(passValue(False), False)
+ self.assertEqual(passValue('string'), 'string')
+ self.assertEqual(passValue('string\u20ac'), 'string\u20ac')
+ self.assertEqual(passValue(u'string'), u'string')
+ self.assertEqual(passValue(u'string\u20ac'), u'string\u20ac')
+ for i in (0, 1, -1, int(2**31-1), int(-2**31)):
+ self.assertEqual(passValue(i), i)
+ for f in (0.0, 1.0, -1.0, 1//3, 1/3.0,
+ sys.float_info.min, sys.float_info.max,
+ -sys.float_info.min, -sys.float_info.max):
+ self.assertEqual(passValue(f), f)
+ for f in float('nan'), float('inf'), -float('inf'):
+ if f != f: # NaN
+ self.assertNotEqual(passValue(f), f)
+ else:
+ self.assertEqual(passValue(f), f)
+ self.assertEqual(passValue((1, '2', (3.4,))), (1, '2', (3.4,)))
def test_main():
diff --git a/lib-python/2.7/test/test_telnetlib.py b/lib-python/2.7/test/test_telnetlib.py
--- a/lib-python/2.7/test/test_telnetlib.py
+++ b/lib-python/2.7/test/test_telnetlib.py
@@ -3,6 +3,7 @@
import time
import Queue
+import unittest
from unittest import TestCase
from test import test_support
threading = test_support.import_module('threading')
@@ -135,6 +136,28 @@
self.assertEqual(data, want[0])
self.assertEqual(telnet.read_all(), 'not seen')
+ def test_read_until_with_poll(self):
+ """Use select.poll() to implement telnet.read_until()."""
+ want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
+ self.dataq.put(want)
+ telnet = telnetlib.Telnet(HOST, self.port)
+ if not telnet._has_poll:
+ raise unittest.SkipTest('select.poll() is required')
+ telnet._has_poll = True
+ self.dataq.join()
+ data = telnet.read_until('match')
+ self.assertEqual(data, ''.join(want[:-2]))
+
+ def test_read_until_with_select(self):
+ """Use select.select() to implement telnet.read_until()."""
+ want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
+ self.dataq.put(want)
+ telnet = telnetlib.Telnet(HOST, self.port)
+ telnet._has_poll = False
+ self.dataq.join()
+ data = telnet.read_until('match')
+ self.assertEqual(data, ''.join(want[:-2]))
+
def test_read_all_A(self):
"""
read_all()
@@ -357,8 +380,75 @@
self.assertEqual('', telnet.read_sb_data())
nego.sb_getter = None # break the nego => telnet cycle
+
+class ExpectTests(TestCase):
+ def setUp(self):
+ self.evt = threading.Event()
+ self.dataq = Queue.Queue()
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.settimeout(10)
+ self.port = test_support.bind_port(self.sock)
+ self.thread = threading.Thread(target=server, args=(self.evt,self.sock,
+ self.dataq))
+ self.thread.start()
+ self.evt.wait()
+
+ def tearDown(self):
+ self.thread.join()
+
+ # use a similar approach to testing timeouts as test_timeout.py
+ # these will never pass 100% but make the fuzz big enough that it is rare
+ block_long = 0.6
+ block_short = 0.3
+ def test_expect_A(self):
+ """
+ expect(expected, [timeout])
+ Read until the expected string has been seen, or a timeout is
+ hit (default is no timeout); may block.
+ """
+ want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
+ self.dataq.put(want)
+ telnet = telnetlib.Telnet(HOST, self.port)
+ self.dataq.join()
+ (_,_,data) = telnet.expect(['match'])
+ self.assertEqual(data, ''.join(want[:-2]))
+
+ def test_expect_B(self):
+ # test the timeout - it does NOT raise socket.timeout
+ want = ['hello', self.block_long, 'not seen', EOF_sigil]
+ self.dataq.put(want)
+ telnet = telnetlib.Telnet(HOST, self.port)
+ self.dataq.join()
+ (_,_,data) = telnet.expect(['not seen'], self.block_short)
+ self.assertEqual(data, want[0])
+ self.assertEqual(telnet.read_all(), 'not seen')
+
+ def test_expect_with_poll(self):
+ """Use select.poll() to implement telnet.expect()."""
+ want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
+ self.dataq.put(want)
+ telnet = telnetlib.Telnet(HOST, self.port)
+ if not telnet._has_poll:
+ raise unittest.SkipTest('select.poll() is required')
+ telnet._has_poll = True
+ self.dataq.join()
+ (_,_,data) = telnet.expect(['match'])
+ self.assertEqual(data, ''.join(want[:-2]))
+
+ def test_expect_with_select(self):
+ """Use select.select() to implement telnet.expect()."""
+ want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
+ self.dataq.put(want)
+ telnet = telnetlib.Telnet(HOST, self.port)
+ telnet._has_poll = False
+ self.dataq.join()
+ (_,_,data) = telnet.expect(['match'])
+ self.assertEqual(data, ''.join(want[:-2]))
+
+
def test_main(verbose=None):
- test_support.run_unittest(GeneralTests, ReadTests, OptionTests)
+ test_support.run_unittest(GeneralTests, ReadTests, OptionTests,
+ ExpectTests)
if __name__ == '__main__':
test_main()
diff --git a/lib-python/2.7/test/test_tempfile.py b/lib-python/2.7/test/test_tempfile.py
--- a/lib-python/2.7/test/test_tempfile.py
+++ b/lib-python/2.7/test/test_tempfile.py
@@ -1,13 +1,16 @@
# tempfile.py unit tests.
import tempfile
+import errno
+import io
import os
import signal
+import shutil
import sys
import re
import warnings
import unittest
-from test import test_support
+from test import test_support as support
warnings.filterwarnings("ignore",
category=RuntimeWarning,
@@ -177,7 +180,7 @@
# _candidate_tempdir_list contains the expected directories
# Make sure the interesting environment variables are all set.
- with test_support.EnvironmentVarGuard() as env:
+ with support.EnvironmentVarGuard() as env:
for envname in 'TMPDIR', 'TEMP', 'TMP':
dirname = os.getenv(envname)
if not dirname:
@@ -202,8 +205,51 @@
test_classes.append(test__candidate_tempdir_list)
+# We test _get_default_tempdir some more by testing gettempdir.
-# We test _get_default_tempdir by testing gettempdir.
+class TestGetDefaultTempdir(TC):
+ """Test _get_default_tempdir()."""
+
+ def test_no_files_left_behind(self):
+ # use a private empty directory
+ our_temp_directory = tempfile.mkdtemp()
+ try:
+ # force _get_default_tempdir() to consider our empty directory
+ def our_candidate_list():
+ return [our_temp_directory]
+
+ with support.swap_attr(tempfile, "_candidate_tempdir_list",
+ our_candidate_list):
+ # verify our directory is empty after _get_default_tempdir()
+ tempfile._get_default_tempdir()
+ self.assertEqual(os.listdir(our_temp_directory), [])
+
+ def raise_OSError(*args, **kwargs):
+ raise OSError(-1)
+
+ with support.swap_attr(io, "open", raise_OSError):
+ # test again with failing io.open()
+ with self.assertRaises(IOError) as cm:
+ tempfile._get_default_tempdir()
+ self.assertEqual(cm.exception.errno, errno.ENOENT)
+ self.assertEqual(os.listdir(our_temp_directory), [])
+
+ open = io.open
+ def bad_writer(*args, **kwargs):
+ fp = open(*args, **kwargs)
+ fp.write = raise_OSError
+ return fp
+
+ with support.swap_attr(io, "open", bad_writer):
+ # test again with failing write()
+ with self.assertRaises(IOError) as cm:
+ tempfile._get_default_tempdir()
+ self.assertEqual(cm.exception.errno, errno.ENOENT)
+ self.assertEqual(os.listdir(our_temp_directory), [])
+ finally:
+ shutil.rmtree(our_temp_directory)
+
+test_classes.append(TestGetDefaultTempdir)
class test__get_candidate_names(TC):
@@ -299,7 +345,7 @@
if not has_spawnl:
return # ugh, can't use SkipTest.
- if test_support.verbose:
+ if support.verbose:
v="v"
else:
v="q"
@@ -738,6 +784,17 @@
f.write(b'x')
self.assertTrue(f._rolled)
+ def test_xreadlines(self):
+ f = self.do_create(max_size=20)
+ f.write(b'abc\n' * 5)
+ f.seek(0)
+ self.assertFalse(f._rolled)
+ self.assertEqual(list(f.xreadlines()), [b'abc\n'] * 5)
+ f.write(b'x\ny')
+ self.assertTrue(f._rolled)
+ f.seek(0)
+ self.assertEqual(list(f.xreadlines()), [b'abc\n'] * 5 + [b'x\n', b'y'])
+
def test_sparse(self):
# A SpooledTemporaryFile that is written late in the file will extend
# when that occurs
@@ -793,6 +850,26 @@
seek(0, 0)
self.assertTrue(read(70) == 'a'*35 + 'b'*35)
+ def test_properties(self):
+ f = tempfile.SpooledTemporaryFile(max_size=10)
+ f.write(b'x' * 10)
+ self.assertFalse(f._rolled)
+ self.assertEqual(f.mode, 'w+b')
+ self.assertIsNone(f.name)
+ with self.assertRaises(AttributeError):
+ f.newlines
+ with self.assertRaises(AttributeError):
+ f.encoding
+
+ f.write(b'x')
+ self.assertTrue(f._rolled)
+ self.assertEqual(f.mode, 'w+b')
+ self.assertIsNotNone(f.name)
+ with self.assertRaises(AttributeError):
+ f.newlines
+ with self.assertRaises(AttributeError):
+ f.encoding
+
def test_context_manager_before_rollover(self):
# A SpooledTemporaryFile can be used as a context manager
with tempfile.SpooledTemporaryFile(max_size=1) as f:
@@ -882,7 +959,7 @@
test_classes.append(test_TemporaryFile)
def test_main():
- test_support.run_unittest(*test_classes)
+ support.run_unittest(*test_classes)
if __name__ == "__main__":
test_main()
diff --git a/lib-python/2.7/test/test_textwrap.py b/lib-python/2.7/test/test_textwrap.py
--- a/lib-python/2.7/test/test_textwrap.py
+++ b/lib-python/2.7/test/test_textwrap.py
@@ -66,6 +66,15 @@
"I'm glad to hear it!"])
self.check_wrap(text, 80, [text])
+ def test_empty_string(self):
+ # Check that wrapping the empty string returns an empty list.
+ self.check_wrap("", 6, [])
+ self.check_wrap("", 6, [], drop_whitespace=False)
+
+ def test_empty_string_with_initial_indent(self):
+ # Check that the empty string is not indented.
+ self.check_wrap("", 6, [], initial_indent="++")
+ self.check_wrap("", 6, [], initial_indent="++", drop_whitespace=False)
def test_whitespace(self):
# Whitespace munging and end-of-sentence detection
@@ -323,7 +332,32 @@
["blah", " ", "(ding", " ", "dong),",
" ", "wubba"])
- def test_initial_whitespace(self):
+ def test_drop_whitespace_false(self):
+ # Check that drop_whitespace=False preserves whitespace.
+ # SF patch #1581073
+ text = " This is a sentence with much whitespace."
+ self.check_wrap(text, 10,
+ [" This is a", " ", "sentence ",
+ "with ", "much white", "space."],
+ drop_whitespace=False)
+
+ def test_drop_whitespace_false_whitespace_only(self):
+ # Check that drop_whitespace=False preserves a whitespace-only string.
+ self.check_wrap(" ", 6, [" "], drop_whitespace=False)
+
+ def test_drop_whitespace_false_whitespace_only_with_indent(self):
+ # Check that a whitespace-only string gets indented (when
+ # drop_whitespace is False).
+ self.check_wrap(" ", 6, [" "], drop_whitespace=False,
+ initial_indent=" ")
+
+ def test_drop_whitespace_whitespace_only(self):
+ # Check drop_whitespace on a whitespace-only string.
+ self.check_wrap(" ", 6, [])
+
+ def test_drop_whitespace_leading_whitespace(self):
+ # Check that drop_whitespace does not drop leading whitespace (if
+ # followed by non-whitespace).
# SF bug #622849 reported inconsistent handling of leading
# whitespace; let's test that a bit, shall we?
text = " This is a sentence with leading whitespace."
@@ -332,13 +366,27 @@
self.check_wrap(text, 30,
[" This is a sentence with", "leading whitespace."])
- def test_no_drop_whitespace(self):
- # SF patch #1581073
- text = " This is a sentence with much whitespace."
- self.check_wrap(text, 10,
- [" This is a", " ", "sentence ",
- "with ", "much white", "space."],
+ def test_drop_whitespace_whitespace_line(self):
+ # Check that drop_whitespace skips the whole line if a non-leading
+ # line consists only of whitespace.
+ text = "abcd efgh"
+ # Include the result for drop_whitespace=False for comparison.
+ self.check_wrap(text, 6, ["abcd", " ", "efgh"],
drop_whitespace=False)
+ self.check_wrap(text, 6, ["abcd", "efgh"])
+
+ def test_drop_whitespace_whitespace_only_with_indent(self):
+ # Check that initial_indent is not applied to a whitespace-only
+ # string. This checks a special case of the fact that dropping
+ # whitespace occurs before indenting.
+ self.check_wrap(" ", 6, [], initial_indent="++")
+
+ def test_drop_whitespace_whitespace_indent(self):
+ # Check that drop_whitespace does not drop whitespace indents.
+ # This checks a special case of the fact that dropping whitespace
+ # occurs before indenting.
+ self.check_wrap("abcd efgh", 6, [" abcd", " efgh"],
+ initial_indent=" ", subsequent_indent=" ")
if test_support.have_unicode:
def test_unicode(self):
diff --git a/lib-python/2.7/test/test_thread.py b/lib-python/2.7/test/test_thread.py
--- a/lib-python/2.7/test/test_thread.py
+++ b/lib-python/2.7/test/test_thread.py
@@ -130,6 +130,29 @@
time.sleep(0.01)
self.assertEqual(thread._count(), orig)
+ def test_save_exception_state_on_error(self):
+ # See issue #14474
+ def task():
+ started.release()
+ raise SyntaxError
+ def mywrite(self, *args):
+ try:
+ raise ValueError
+ except ValueError:
+ pass
+ real_write(self, *args)
+ c = thread._count()
+ started = thread.allocate_lock()
+ with test_support.captured_output("stderr") as stderr:
+ real_write = stderr.write
+ stderr.write = mywrite
+ started.acquire()
+ thread.start_new_thread(task, ())
+ started.acquire()
+ while thread._count() > c:
+ time.sleep(0.01)
+ self.assertIn("Traceback", stderr.getvalue())
+
class Barrier:
def __init__(self, num_threads):
diff --git a/lib-python/2.7/test/test_threading.py b/lib-python/2.7/test/test_threading.py
--- a/lib-python/2.7/test/test_threading.py
+++ b/lib-python/2.7/test/test_threading.py
@@ -2,6 +2,8 @@
import test.test_support
from test.test_support import verbose
+from test.script_helper import assert_python_ok
+
import random
import re
import sys
@@ -414,6 +416,33 @@
msg=('%d references still around' %
sys.getrefcount(weak_raising_cyclic_object())))
+ @unittest.skipUnless(hasattr(os, 'fork'), 'test needs fork()')
+ def test_dummy_thread_after_fork(self):
+ # Issue #14308: a dummy thread in the active list doesn't mess up
+ # the after-fork mechanism.
+ code = """if 1:
+ import thread, threading, os, time
+
+ def background_thread(evt):
+ # Creates and registers the _DummyThread instance
+ threading.current_thread()
+ evt.set()
+ time.sleep(10)
+
+ evt = threading.Event()
+ thread.start_new_thread(background_thread, (evt,))
+ evt.wait()
+ assert threading.active_count() == 2, threading.active_count()
+ if os.fork() == 0:
+ assert threading.active_count() == 1, threading.active_count()
+ os._exit(0)
+ else:
+ os.wait()
+ """
+ _, out, err = assert_python_ok("-c", code)
+ self.assertEqual(out, '')
+ self.assertEqual(err, '')
+
class ThreadJoinOnShutdown(BaseTestCase):
diff --git a/lib-python/2.7/test/test_time.py b/lib-python/2.7/test/test_time.py
--- a/lib-python/2.7/test/test_time.py
+++ b/lib-python/2.7/test/test_time.py
@@ -106,7 +106,7 @@
def test_strptime(self):
# Should be able to go round-trip from strftime to strptime without
- # throwing an exception.
+ # raising an exception.
tt = time.gmtime(self.t)
for directive in ('a', 'A', 'b', 'B', 'c', 'd', 'H', 'I',
'j', 'm', 'M', 'p', 'S',
diff --git a/lib-python/2.7/test/test_tokenize.py b/lib-python/2.7/test/test_tokenize.py
--- a/lib-python/2.7/test/test_tokenize.py
+++ b/lib-python/2.7/test/test_tokenize.py
@@ -278,6 +278,31 @@
OP '+' (1, 32) (1, 33)
STRING 'UR"ABC"' (1, 34) (1, 41)
+ >>> dump_tokens("b'abc' + B'abc'")
+ STRING "b'abc'" (1, 0) (1, 6)
+ OP '+' (1, 7) (1, 8)
+ STRING "B'abc'" (1, 9) (1, 15)
+ >>> dump_tokens('b"abc" + B"abc"')
+ STRING 'b"abc"' (1, 0) (1, 6)
+ OP '+' (1, 7) (1, 8)
+ STRING 'B"abc"' (1, 9) (1, 15)
+ >>> dump_tokens("br'abc' + bR'abc' + Br'abc' + BR'abc'")
+ STRING "br'abc'" (1, 0) (1, 7)
+ OP '+' (1, 8) (1, 9)
+ STRING "bR'abc'" (1, 10) (1, 17)
+ OP '+' (1, 18) (1, 19)
+ STRING "Br'abc'" (1, 20) (1, 27)
+ OP '+' (1, 28) (1, 29)
+ STRING "BR'abc'" (1, 30) (1, 37)
+ >>> dump_tokens('br"abc" + bR"abc" + Br"abc" + BR"abc"')
+ STRING 'br"abc"' (1, 0) (1, 7)
+ OP '+' (1, 8) (1, 9)
+ STRING 'bR"abc"' (1, 10) (1, 17)
+ OP '+' (1, 18) (1, 19)
+ STRING 'Br"abc"' (1, 20) (1, 27)
+ OP '+' (1, 28) (1, 29)
+ STRING 'BR"abc"' (1, 30) (1, 37)
+
Operators
>>> dump_tokens("def d22(a, b, c=2, d=2, *k): pass")
@@ -525,6 +550,10 @@
NAME 'pass' (3, 9) (3, 13)
DEDENT '' (4, 0) (4, 0)
DEDENT '' (4, 0) (4, 0)
+
+Pathological whitespace (http://bugs.python.org/issue16152)
+ >>> dump_tokens("@ ")
+ OP '@' (1, 0) (1, 1)
"""
diff --git a/lib-python/2.7/test/test_tools.py b/lib-python/2.7/test/test_tools.py
--- a/lib-python/2.7/test/test_tools.py
+++ b/lib-python/2.7/test/test_tools.py
@@ -5,22 +5,28 @@
"""
import os
+import sys
import unittest
+import shutil
+import subprocess
import sysconfig
+import tempfile
+import textwrap
from test import test_support
-from test.script_helper import assert_python_ok
+from test.script_helper import assert_python_ok, temp_dir
if not sysconfig.is_python_build():
# XXX some installers do contain the tools, should we detect that
# and run the tests in that case too?
raise unittest.SkipTest('test irrelevant for an installed Python')
-srcdir = sysconfig.get_config_var('projectbase')
-basepath = os.path.join(os.getcwd(), srcdir, 'Tools')
+basepath = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
+ 'Tools')
+scriptsdir = os.path.join(basepath, 'scripts')
class ReindentTests(unittest.TestCase):
- script = os.path.join(basepath, 'scripts', 'reindent.py')
+ script = os.path.join(scriptsdir, 'reindent.py')
def test_noargs(self):
assert_python_ok(self.script)
@@ -31,8 +37,331 @@
self.assertGreater(err, b'')
+class PindentTests(unittest.TestCase):
+ script = os.path.join(scriptsdir, 'pindent.py')
+
+ def assertFileEqual(self, fn1, fn2):
+ with open(fn1) as f1, open(fn2) as f2:
+ self.assertEqual(f1.readlines(), f2.readlines())
+
+ def pindent(self, source, *args):
+ proc = subprocess.Popen(
+ (sys.executable, self.script) + args,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ universal_newlines=True)
+ out, err = proc.communicate(source)
+ self.assertIsNone(err)
+ return out
+
+ def lstriplines(self, data):
+ return '\n'.join(line.lstrip() for line in data.splitlines()) + '\n'
+
+ def test_selftest(self):
+ self.maxDiff = None
+ with temp_dir() as directory:
+ data_path = os.path.join(directory, '_test.py')
+ with open(self.script) as f:
+ closed = f.read()
+ with open(data_path, 'w') as f:
+ f.write(closed)
+
+ rc, out, err = assert_python_ok(self.script, '-d', data_path)
+ self.assertEqual(out, b'')
+ self.assertEqual(err, b'')
+ backup = data_path + '~'
+ self.assertTrue(os.path.exists(backup))
+ with open(backup) as f:
+ self.assertEqual(f.read(), closed)
+ with open(data_path) as f:
+ clean = f.read()
+ compile(clean, '_test.py', 'exec')
+ self.assertEqual(self.pindent(clean, '-c'), closed)
+ self.assertEqual(self.pindent(closed, '-d'), clean)
+
+ rc, out, err = assert_python_ok(self.script, '-c', data_path)
+ self.assertEqual(out, b'')
+ self.assertEqual(err, b'')
+ with open(backup) as f:
+ self.assertEqual(f.read(), clean)
+ with open(data_path) as f:
+ self.assertEqual(f.read(), closed)
+
+ broken = self.lstriplines(closed)
+ with open(data_path, 'w') as f:
+ f.write(broken)
+ rc, out, err = assert_python_ok(self.script, '-r', data_path)
+ self.assertEqual(out, b'')
+ self.assertEqual(err, b'')
+ with open(backup) as f:
+ self.assertEqual(f.read(), broken)
+ with open(data_path) as f:
+ indented = f.read()
+ compile(indented, '_test.py', 'exec')
+ self.assertEqual(self.pindent(broken, '-r'), indented)
+
+ def pindent_test(self, clean, closed):
+ self.assertEqual(self.pindent(clean, '-c'), closed)
+ self.assertEqual(self.pindent(closed, '-d'), clean)
+ broken = self.lstriplines(closed)
+ self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '4'), closed)
+
+ def test_statements(self):
+ clean = textwrap.dedent("""\
+ if a:
+ pass
+
+ if a:
+ pass
+ else:
+ pass
+
+ if a:
+ pass
+ elif:
+ pass
+ else:
+ pass
+
+ while a:
+ break
+
+ while a:
+ break
+ else:
+ pass
+
+ for i in a:
+ break
+
+ for i in a:
+ break
+ else:
+ pass
+
+ try:
+ pass
+ finally:
+ pass
+
+ try:
+ pass
+ except TypeError:
+ pass
+ except ValueError:
+ pass
+ else:
+ pass
+
+ try:
+ pass
+ except TypeError:
+ pass
+ except ValueError:
+ pass
+ finally:
+ pass
+
+ with a:
+ pass
+
+ class A:
+ pass
+
+ def f():
+ pass
+ """)
+
+ closed = textwrap.dedent("""\
+ if a:
+ pass
+ # end if
+
+ if a:
+ pass
+ else:
+ pass
+ # end if
+
+ if a:
+ pass
+ elif:
+ pass
+ else:
+ pass
+ # end if
+
+ while a:
+ break
+ # end while
+
+ while a:
+ break
+ else:
+ pass
+ # end while
+
+ for i in a:
+ break
+ # end for
+
+ for i in a:
+ break
+ else:
+ pass
+ # end for
+
+ try:
+ pass
+ finally:
+ pass
+ # end try
+
+ try:
+ pass
+ except TypeError:
+ pass
+ except ValueError:
+ pass
+ else:
+ pass
+ # end try
+
+ try:
+ pass
+ except TypeError:
+ pass
+ except ValueError:
+ pass
+ finally:
+ pass
+ # end try
+
+ with a:
+ pass
+ # end with
+
+ class A:
+ pass
+ # end class A
+
+ def f():
+ pass
+ # end def f
+ """)
+ self.pindent_test(clean, closed)
+
+ def test_multilevel(self):
+ clean = textwrap.dedent("""\
+ def foobar(a, b):
+ if a == b:
+ a = a+1
+ elif a < b:
+ b = b-1
+ if b > a: a = a-1
+ else:
+ print 'oops!'
+ """)
+ closed = textwrap.dedent("""\
+ def foobar(a, b):
+ if a == b:
+ a = a+1
+ elif a < b:
+ b = b-1
+ if b > a: a = a-1
+ # end if
+ else:
+ print 'oops!'
+ # end if
+ # end def foobar
+ """)
+ self.pindent_test(clean, closed)
+
+ def test_preserve_indents(self):
+ clean = textwrap.dedent("""\
+ if a:
+ if b:
+ pass
+ """)
+ closed = textwrap.dedent("""\
+ if a:
+ if b:
+ pass
+ # end if
+ # end if
+ """)
+ self.assertEqual(self.pindent(clean, '-c'), closed)
+ self.assertEqual(self.pindent(closed, '-d'), clean)
+ broken = self.lstriplines(closed)
+ self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '9'), closed)
+ clean = textwrap.dedent("""\
+ if a:
+ \tif b:
+ \t\tpass
+ """)
+ closed = textwrap.dedent("""\
+ if a:
+ \tif b:
+ \t\tpass
+ \t# end if
+ # end if
+ """)
+ self.assertEqual(self.pindent(clean, '-c'), closed)
+ self.assertEqual(self.pindent(closed, '-d'), clean)
+ broken = self.lstriplines(closed)
+ self.assertEqual(self.pindent(broken, '-r'), closed)
+
+ def test_escaped_newline(self):
+ clean = textwrap.dedent("""\
+ class\\
+ \\
+ A:
+ def\
+ \\
+ f:
+ pass
+ """)
+ closed = textwrap.dedent("""\
+ class\\
+ \\
+ A:
+ def\
+ \\
+ f:
+ pass
+ # end def f
+ # end class A
+ """)
+ self.assertEqual(self.pindent(clean, '-c'), closed)
+ self.assertEqual(self.pindent(closed, '-d'), clean)
+
+ def test_empty_line(self):
+ clean = textwrap.dedent("""\
+ if a:
+
+ pass
+ """)
+ closed = textwrap.dedent("""\
+ if a:
+
+ pass
+ # end if
+ """)
+ self.pindent_test(clean, closed)
+
+ def test_oneline(self):
+ clean = textwrap.dedent("""\
+ if a: pass
+ """)
+ closed = textwrap.dedent("""\
+ if a: pass
+ # end if
+ """)
+ self.pindent_test(clean, closed)
+
+
def test_main():
- test_support.run_unittest(ReindentTests)
+ test_support.run_unittest(*[obj for obj in globals().values()
+ if isinstance(obj, type)])
if __name__ == '__main__':
diff --git a/lib-python/2.7/test/test_ucn.py b/lib-python/2.7/test/test_ucn.py
--- a/lib-python/2.7/test/test_ucn.py
+++ b/lib-python/2.7/test/test_ucn.py
@@ -8,6 +8,8 @@
"""#"
import unittest
+import sys
+import _testcapi
from test import test_support
@@ -137,6 +139,27 @@
unicode, "\\NSPACE", 'unicode-escape', 'strict'
)
+ @unittest.skipUnless(_testcapi.INT_MAX < _testcapi.PY_SSIZE_T_MAX,
+ "needs UINT_MAX < SIZE_MAX")
+ @unittest.skipUnless(_testcapi.UINT_MAX < sys.maxint,
+ "needs UINT_MAX < sys.maxint")
+ @test_support.bigmemtest(minsize=_testcapi.UINT_MAX + 1,
+ memuse=2 + 4 // len(u'\U00010000'))
+ def test_issue16335(self, size):
+ func = self.test_issue16335
+ if size < func.minsize:
+ raise unittest.SkipTest("not enough memory: %.1fG minimum needed" %
+ (func.minsize * func.memuse / float(1024**3),))
+ # very very long bogus character name
+ x = b'\\N{SPACE' + b'x' * int(_testcapi.UINT_MAX + 1) + b'}'
+ self.assertEqual(len(x), len(b'\\N{SPACE}') +
+ (_testcapi.UINT_MAX + 1))
+ self.assertRaisesRegexp(UnicodeError,
+ 'unknown Unicode character name',
+ x.decode, 'unicode-escape'
+ )
+
+
def test_main():
test_support.run_unittest(UnicodeNamesTest)
diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py
--- a/lib-python/2.7/test/test_unicode.py
+++ b/lib-python/2.7/test/test_unicode.py
@@ -644,6 +644,18 @@
return u'\u1234'
self.assertEqual('%s' % Wrapper(), u'\u1234')
+ @test_support.cpython_only
+ def test_formatting_huge_precision(self):
+ from _testcapi import INT_MAX
+ format_string = u"%.{}f".format(INT_MAX + 1)
+ with self.assertRaises(ValueError):
+ result = format_string % 2.34
+
+ def test_formatting_huge_width(self):
+ format_string = u"%{}f".format(sys.maxsize + 1)
+ with self.assertRaises(ValueError):
+ result = format_string % 2.34
+
def test_startswith_endswith_errors(self):
for meth in (u'foo'.startswith, u'foo'.endswith):
with self.assertRaises(UnicodeDecodeError):
@@ -1556,6 +1568,21 @@
# will fail
self.assertRaises(UnicodeEncodeError, "foo{0}".format, u'\u1000bar')
+ def test_format_huge_precision(self):
+ format_string = u".{}f".format(sys.maxsize + 1)
+ with self.assertRaises(ValueError):
+ result = format(2.34, format_string)
+
+ def test_format_huge_width(self):
+ format_string = u"{}f".format(sys.maxsize + 1)
+ with self.assertRaises(ValueError):
+ result = format(2.34, format_string)
+
+ def test_format_huge_item_number(self):
+ format_string = u"{{{}:.6f}}".format(sys.maxsize + 1)
+ with self.assertRaises(ValueError):
+ result = format_string.format(2.34)
+
def test_format_auto_numbering(self):
class C:
def __init__(self, x=100):
diff --git a/lib-python/2.7/test/test_urllib.py b/lib-python/2.7/test/test_urllib.py
--- a/lib-python/2.7/test/test_urllib.py
+++ b/lib-python/2.7/test/test_urllib.py
@@ -222,6 +222,27 @@
finally:
self.unfakehttp()
+ def test_missing_localfile(self):
+ self.assertRaises(IOError, urllib.urlopen,
+ 'file://localhost/a/missing/file.py')
+ fd, tmp_file = tempfile.mkstemp()
+ tmp_fileurl = 'file://localhost/' + tmp_file.replace(os.path.sep, '/')
+ try:
+ self.assertTrue(os.path.exists(tmp_file))
+ fp = urllib.urlopen(tmp_fileurl)
+ finally:
+ os.close(fd)
+ fp.close()
+ os.unlink(tmp_file)
+
+ self.assertFalse(os.path.exists(tmp_file))
+ self.assertRaises(IOError, urllib.urlopen, tmp_fileurl)
+
+ def test_ftp_nonexisting(self):
+ self.assertRaises(IOError, urllib.urlopen,
+ 'ftp://localhost/not/existing/file.py')
+
+
def test_userpass_inurl(self):
self.fakehttp('Hello!')
try:
diff --git a/lib-python/2.7/test/test_urllib2.py b/lib-python/2.7/test/test_urllib2.py
--- a/lib-python/2.7/test/test_urllib2.py
+++ b/lib-python/2.7/test/test_urllib2.py
@@ -1106,12 +1106,30 @@
self._test_basic_auth(opener, auth_handler, "Authorization",
realm, http_handler, password_manager,
"http://acme.example.com/protected",
- "http://acme.example.com/protected",
- )
+ "http://acme.example.com/protected"
+ )
def test_basic_auth_with_single_quoted_realm(self):
self.test_basic_auth(quote_char="'")
+ def test_basic_auth_with_unquoted_realm(self):
+ opener = OpenerDirector()
+ password_manager = MockPasswordManager()
+ auth_handler = urllib2.HTTPBasicAuthHandler(password_manager)
+ realm = "ACME Widget Store"
+ http_handler = MockHTTPHandler(
+ 401, 'WWW-Authenticate: Basic realm=%s\r\n\r\n' % realm)
+ opener.add_handler(auth_handler)
+ opener.add_handler(http_handler)
+ msg = "Basic Auth Realm was unquoted"
+ with test_support.check_warnings((msg, UserWarning)):
+ self._test_basic_auth(opener, auth_handler, "Authorization",
+ realm, http_handler, password_manager,
+ "http://acme.example.com/protected",
+ "http://acme.example.com/protected"
+ )
+
+
def test_proxy_basic_auth(self):
opener = OpenerDirector()
ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128"))
@@ -1130,7 +1148,7 @@
)
def test_basic_and_digest_auth_handlers(self):
- # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
+ # HTTPDigestAuthHandler raised an exception if it couldn't handle a 40*
# response (http://python.org/sf/1479302), where it should instead
# return None to allow another handler (especially
# HTTPBasicAuthHandler) to handle the response.
@@ -1318,16 +1336,32 @@
req = Request(url)
self.assertEqual(req.get_full_url(), url)
-def test_HTTPError_interface():
- """
- Issue 13211 reveals that HTTPError didn't implement the URLError
- interface even though HTTPError is a subclass of URLError.
+ def test_HTTPError_interface(self):
+ """
+ Issue 13211 reveals that HTTPError didn't implement the URLError
+ interface even though HTTPError is a subclass of URLError.
- >>> err = urllib2.HTTPError(msg='something bad happened', url=None, code=None, hdrs=None, fp=None)
- >>> assert hasattr(err, 'reason')
- >>> err.reason
- 'something bad happened'
- """
+ >>> err = urllib2.HTTPError(msg='something bad happened', url=None, code=None, hdrs=None, fp=None)
+ >>> assert hasattr(err, 'reason')
+ >>> err.reason
+ 'something bad happened'
+ """
+
+ def test_HTTPError_interface_call(self):
+ """
+ Issue 15701= - HTTPError interface has info method available from URLError.
+ """
+ err = urllib2.HTTPError(msg='something bad happened', url=None,
+ code=None, hdrs='Content-Length:42', fp=None)
+ self.assertTrue(hasattr(err, 'reason'))
+ assert hasattr(err, 'reason')
+ assert hasattr(err, 'info')
+ assert callable(err.info)
+ try:
+ err.info()
+ except AttributeError:
+ self.fail("err.info() failed")
+ self.assertEqual(err.info(), "Content-Length:42")
def test_main(verbose=None):
from test import test_urllib2
diff --git a/lib-python/2.7/test/test_urllib2_localnet.py b/lib-python/2.7/test/test_urllib2_localnet.py
--- a/lib-python/2.7/test/test_urllib2_localnet.py
+++ b/lib-python/2.7/test/test_urllib2_localnet.py
@@ -5,7 +5,9 @@
import BaseHTTPServer
import unittest
import hashlib
+
from test import test_support
+
mimetools = test_support.import_module('mimetools', deprecated=True)
threading = test_support.import_module('threading')
@@ -346,6 +348,12 @@
for transparent redirection have been written.
"""
+ def setUp(self):
+ proxy_handler = urllib2.ProxyHandler({})
+ opener = urllib2.build_opener(proxy_handler)
+ urllib2.install_opener(opener)
+ super(TestUrlopen, self).setUp()
+
def start_server(self, responses):
handler = GetRequestHandler(responses)
diff --git a/lib-python/2.7/test/test_urllib2net.py b/lib-python/2.7/test/test_urllib2net.py
--- a/lib-python/2.7/test/test_urllib2net.py
+++ b/lib-python/2.7/test/test_urllib2net.py
@@ -157,12 +157,12 @@
## self._test_urls(urls, self._extra_handlers()+[bauth, dauth])
def test_urlwithfrag(self):
- urlwith_frag = "http://docs.python.org/glossary.html#glossary"
+ urlwith_frag = "http://docs.python.org/2/glossary.html#glossary"
with test_support.transient_internet(urlwith_frag):
req = urllib2.Request(urlwith_frag)
res = urllib2.urlopen(req)
self.assertEqual(res.geturl(),
- "http://docs.python.org/glossary.html#glossary")
+ "http://docs.python.org/2/glossary.html#glossary")
def test_fileno(self):
req = urllib2.Request("http://www.python.org")
diff --git a/lib-python/2.7/test/test_urlparse.py b/lib-python/2.7/test/test_urlparse.py
--- a/lib-python/2.7/test/test_urlparse.py
+++ b/lib-python/2.7/test/test_urlparse.py
@@ -437,6 +437,51 @@
self.assertEqual(p.port, 80)
self.assertEqual(p.geturl(), url)
+ # Verify an illegal port of value greater than 65535 is set as None
+ url = "http://www.python.org:65536"
+ p = urlparse.urlsplit(url)
+ self.assertEqual(p.port, None)
+
+ def test_issue14072(self):
+ p1 = urlparse.urlsplit('tel:+31-641044153')
+ self.assertEqual(p1.scheme, 'tel')
+ self.assertEqual(p1.path, '+31-641044153')
+
+ p2 = urlparse.urlsplit('tel:+31641044153')
+ self.assertEqual(p2.scheme, 'tel')
+ self.assertEqual(p2.path, '+31641044153')
+
+ # Assert for urlparse
+ p1 = urlparse.urlparse('tel:+31-641044153')
+ self.assertEqual(p1.scheme, 'tel')
+ self.assertEqual(p1.path, '+31-641044153')
+
+ p2 = urlparse.urlparse('tel:+31641044153')
+ self.assertEqual(p2.scheme, 'tel')
+ self.assertEqual(p2.path, '+31641044153')
+
+
+ def test_telurl_params(self):
+ p1 = urlparse.urlparse('tel:123-4;phone-context=+1-650-516')
+ self.assertEqual(p1.scheme, 'tel')
+ self.assertEqual(p1.path, '123-4')
+ self.assertEqual(p1.params, 'phone-context=+1-650-516')
+
+ p1 = urlparse.urlparse('tel:+1-201-555-0123')
+ self.assertEqual(p1.scheme, 'tel')
+ self.assertEqual(p1.path, '+1-201-555-0123')
+ self.assertEqual(p1.params, '')
+
+ p1 = urlparse.urlparse('tel:7042;phone-context=example.com')
+ self.assertEqual(p1.scheme, 'tel')
+ self.assertEqual(p1.path, '7042')
+ self.assertEqual(p1.params, 'phone-context=example.com')
+
+ p1 = urlparse.urlparse('tel:863-1234;phone-context=+1-914-555')
+ self.assertEqual(p1.scheme, 'tel')
+ self.assertEqual(p1.path, '863-1234')
+ self.assertEqual(p1.params, 'phone-context=+1-914-555')
+
def test_attributes_bad_port(self):
"""Check handling of non-integer ports."""
@@ -493,6 +538,10 @@
('s3','foo.com','/stuff','','',''))
self.assertEqual(urlparse.urlparse("x-newscheme://foo.com/stuff"),
('x-newscheme','foo.com','/stuff','','',''))
+ self.assertEqual(urlparse.urlparse("x-newscheme://foo.com/stuff?query#fragment"),
+ ('x-newscheme','foo.com','/stuff','','query','fragment'))
+ self.assertEqual(urlparse.urlparse("x-newscheme://foo.com/stuff?query"),
+ ('x-newscheme','foo.com','/stuff','','query',''))
def test_withoutscheme(self):
# Test urlparse without scheme
diff --git a/lib-python/2.7/test/test_uu.py b/lib-python/2.7/test/test_uu.py
--- a/lib-python/2.7/test/test_uu.py
+++ b/lib-python/2.7/test/test_uu.py
@@ -48,7 +48,7 @@
out = cStringIO.StringIO()
try:
uu.decode(inp, out)
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except uu.Error, e:
self.assertEqual(str(e), "Truncated input file")
@@ -57,7 +57,7 @@
out = cStringIO.StringIO()
try:
uu.decode(inp, out)
- self.fail("No exception thrown")
+ self.fail("No exception raised")
except uu.Error, e:
self.assertEqual(str(e), "No valid begin line found in input file")
diff --git a/lib-python/2.7/test/test_weakref.py b/lib-python/2.7/test/test_weakref.py
--- a/lib-python/2.7/test/test_weakref.py
+++ b/lib-python/2.7/test/test_weakref.py
@@ -33,6 +33,27 @@
return C.method
+class Object:
+ def __init__(self, arg):
+ self.arg = arg
+ def __repr__(self):
+ return "<Object %r>" % self.arg
+ def __eq__(self, other):
+ if isinstance(other, Object):
+ return self.arg == other.arg
+ return NotImplemented
+ def __ne__(self, other):
+ if isinstance(other, Object):
+ return self.arg != other.arg
+ return NotImplemented
+ def __hash__(self):
+ return hash(self.arg)
+
+class RefCycle:
+ def __init__(self):
+ self.cycle = self
+
+
class TestBase(unittest.TestCase):
def setUp(self):
@@ -705,6 +726,75 @@
self.assertEqual(b(), None)
self.assertEqual(l, [a, b])
+ def test_equality(self):
+ # Alive weakrefs defer equality testing to their underlying object.
+ x = Object(1)
+ y = Object(1)
+ z = Object(2)
+ a = weakref.ref(x)
+ b = weakref.ref(y)
+ c = weakref.ref(z)
+ d = weakref.ref(x)
+ # Note how we directly test the operators here, to stress both
+ # __eq__ and __ne__.
+ self.assertTrue(a == b)
+ self.assertFalse(a != b)
+ self.assertFalse(a == c)
+ self.assertTrue(a != c)
+ self.assertTrue(a == d)
+ self.assertFalse(a != d)
+ del x, y, z
+ gc.collect()
+ for r in a, b, c:
+ # Sanity check
+ self.assertIs(r(), None)
+ # Dead weakrefs compare by identity: whether `a` and `d` are the
+ # same weakref object is an implementation detail, since they pointed
+ # to the same original object and didn't have a callback.
+ # (see issue #16453).
+ self.assertFalse(a == b)
+ self.assertTrue(a != b)
+ self.assertFalse(a == c)
+ self.assertTrue(a != c)
+ self.assertEqual(a == d, a is d)
+ self.assertEqual(a != d, a is not d)
+
+ def test_hashing(self):
+ # Alive weakrefs hash the same as the underlying object
+ x = Object(42)
+ y = Object(42)
+ a = weakref.ref(x)
+ b = weakref.ref(y)
+ self.assertEqual(hash(a), hash(42))
+ del x, y
+ gc.collect()
+ # Dead weakrefs:
+ # - retain their hash is they were hashed when alive;
+ # - otherwise, cannot be hashed.
+ self.assertEqual(hash(a), hash(42))
+ self.assertRaises(TypeError, hash, b)
+
+ def test_trashcan_16602(self):
+ # Issue #16602: when a weakref's target was part of a long
+ # deallocation chain, the trashcan mechanism could delay clearing
+ # of the weakref and make the target object visible from outside
+ # code even though its refcount had dropped to 0. A crash ensued.
+ class C(object):
+ def __init__(self, parent):
+ if not parent:
+ return
+ wself = weakref.ref(self)
+ def cb(wparent):
+ o = wself()
+ self.wparent = weakref.ref(parent, cb)
+
+ d = weakref.WeakKeyDictionary()
+ root = c = C(None)
+ for n in range(100):
+ d[c] = c = C(c)
+ del root
+ gc.collect()
+
class SubclassableWeakrefTestCase(TestBase):
@@ -809,17 +899,6 @@
self.assertEqual(self.cbcalled, 0)
-class Object:
- def __init__(self, arg):
- self.arg = arg
- def __repr__(self):
- return "<Object %r>" % self.arg
-
-class RefCycle:
- def __init__(self):
- self.cycle = self
-
-
class MappingTestCase(TestBase):
COUNT = 10
diff --git a/lib-python/2.7/test/test_winreg.py b/lib-python/2.7/test/test_winreg.py
--- a/lib-python/2.7/test/test_winreg.py
+++ b/lib-python/2.7/test/test_winreg.py
@@ -1,7 +1,7 @@
# Test the windows specific win32reg module.
# Only win32reg functions not hit here: FlushKey, LoadKey and SaveKey
-import os, sys
+import os, sys, errno
import unittest
from test import test_support
threading = test_support.import_module("threading")
@@ -234,7 +234,7 @@
def test_changing_value(self):
# Issue2810: A race condition in 2.6 and 3.1 may cause
- # EnumValue or QueryValue to throw "WindowsError: More data is
+ # EnumValue or QueryValue to raise "WindowsError: More data is
# available"
done = False
@@ -267,7 +267,7 @@
def test_long_key(self):
# Issue2810, in 2.6 and 3.1 when the key name was exactly 256
- # characters, EnumKey threw "WindowsError: More data is
+ # characters, EnumKey raised "WindowsError: More data is
# available"
name = 'x'*256
try:
@@ -282,8 +282,14 @@
def test_dynamic_key(self):
# Issue2810, when the value is dynamically generated, these
- # throw "WindowsError: More data is available" in 2.6 and 3.1
- EnumValue(HKEY_PERFORMANCE_DATA, 0)
+ # raise "WindowsError: More data is available" in 2.6 and 3.1
+ try:
+ EnumValue(HKEY_PERFORMANCE_DATA, 0)
+ except OSError as e:
+ if e.errno in (errno.EPERM, errno.EACCES):
+ self.skipTest("access denied to registry key "
+ "(are you running in a non-interactive session?)")
+ raise
QueryValueEx(HKEY_PERFORMANCE_DATA, None)
# Reflection requires XP x64/Vista at a minimum. XP doesn't have this stuff
@@ -308,6 +314,35 @@
finally:
DeleteKey(HKEY_CURRENT_USER, test_key_name)
+ def test_setvalueex_value_range(self):
+ # Test for Issue #14420, accept proper ranges for SetValueEx.
+ # Py2Reg, which gets called by SetValueEx, was using PyLong_AsLong,
+ # thus raising OverflowError. The implementation now uses
+ # PyLong_AsUnsignedLong to match DWORD's size.
+ try:
+ with CreateKey(HKEY_CURRENT_USER, test_key_name) as ck:
+ self.assertNotEqual(ck.handle, 0)
+ SetValueEx(ck, "test_name", None, REG_DWORD, 0x80000000)
+ finally:
+ DeleteKey(HKEY_CURRENT_USER, test_key_name)
+
+ def test_queryvalueex_return_value(self):
+ # Test for Issue #16759, return unsigned int from QueryValueEx.
+ # Reg2Py, which gets called by QueryValueEx, was returning a value
+ # generated by PyLong_FromLong. The implmentation now uses
+ # PyLong_FromUnsignedLong to match DWORD's size.
+ try:
+ with CreateKey(HKEY_CURRENT_USER, test_key_name) as ck:
+ self.assertNotEqual(ck.handle, 0)
+ test_val = 0x80000000
+ SetValueEx(ck, "test_name", None, REG_DWORD, test_val)
+ ret_val, ret_type = QueryValueEx(ck, "test_name")
+ self.assertEqual(ret_type, REG_DWORD)
+ self.assertEqual(ret_val, test_val)
+ finally:
+ DeleteKey(HKEY_CURRENT_USER, test_key_name)
+
+
@unittest.skipUnless(REMOTE_NAME, "Skipping remote registry tests")
class RemoteWinregTests(BaseWinregTests):
diff --git a/lib-python/2.7/test/test_winsound.py b/lib-python/2.7/test/test_winsound.py
--- a/lib-python/2.7/test/test_winsound.py
+++ b/lib-python/2.7/test/test_winsound.py
@@ -2,6 +2,7 @@
import unittest
from test import test_support
+test_support.requires('audio')
import time
import os
import subprocess
diff --git a/lib-python/2.7/test/test_wsgiref.py b/lib-python/2.7/test/test_wsgiref.py
--- a/lib-python/2.7/test/test_wsgiref.py
+++ b/lib-python/2.7/test/test_wsgiref.py
@@ -39,9 +39,6 @@
pass
-
-
-
def hello_app(environ,start_response):
start_response("200 OK", [
('Content-Type','text/plain'),
@@ -62,27 +59,6 @@
return out.getvalue(), err.getvalue()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
def compare_generic_iter(make_it,match):
"""Utility to compare a generic 2.1/2.2+ iterator with an iterable
@@ -120,10 +96,6 @@
raise AssertionError("Too many items from .next()",it)
-
-
-
-
class IntegrationTests(TestCase):
def check_hello(self, out, has_length=True):
@@ -161,10 +133,6 @@
)
-
-
-
-
class UtilityTests(TestCase):
def checkShift(self,sn_in,pi_in,part,sn_out,pi_out):
@@ -201,11 +169,6 @@
util.setup_testing_defaults(kw)
self.assertEqual(util.request_uri(kw,query),uri)
-
-
-
-
-
def checkFW(self,text,size,match):
def make_it(text=text,size=size):
@@ -224,7 +187,6 @@
it.close()
self.assertTrue(it.filelike.closed)
-
def testSimpleShifts(self):
self.checkShift('','/', '', '/', '')
self.checkShift('','/x', 'x', '/x', '')
@@ -232,7 +194,6 @@
self.checkShift('/a','/x/y', 'x', '/a/x', '/y')
self.checkShift('/a','/x/', 'x', '/a/x', '/')
-
def testNormalizedShifts(self):
self.checkShift('/a/b', '/../y', '..', '/a', '/y')
self.checkShift('', '/../y', '..', '', '/y')
@@ -246,7 +207,6 @@
self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/')
self.checkShift('/a/b', '/.', None, '/a/b', '')
-
def testDefaults(self):
for key, value in [
('SERVER_NAME','127.0.0.1'),
@@ -266,7 +226,6 @@
]:
self.checkDefault(key,value)
-
def testCrossDefaults(self):
self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar")
self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on")
@@ -276,7 +235,6 @@
self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo")
self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on")
-
def testGuessScheme(self):
self.assertEqual(util.guess_scheme({}), "http")
self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http")
@@ -284,10 +242,6 @@
self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https")
self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https")
-
-
-
-
def testAppURIs(self):
self.checkAppURI("http://127.0.0.1/")
self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam")
@@ -411,15 +365,6 @@
raise # for testing, we want to see what's happening
-
-
-
-
-
-
-
-
-
class HandlerTests(TestCase):
def checkEnvironAttrs(self, handler):
@@ -460,7 +405,6 @@
h=TestHandler(); h.setup_environ()
self.assertEqual(h.environ['wsgi.url_scheme'],'http')
-
def testAbstractMethods(self):
h = BaseHandler()
for name in [
@@ -469,7 +413,6 @@
self.assertRaises(NotImplementedError, getattr(h,name))
self.assertRaises(NotImplementedError, h._write, "test")
-
def testContentLength(self):
# Demo one reason iteration is better than write()... ;)
@@ -549,7 +492,6 @@
"\r\n"+MSG)
self.assertNotEqual(h.stderr.getvalue().find("AssertionError"), -1)
-
def testHeaderFormats(self):
def non_error_app(e,s):
@@ -591,40 +533,28 @@
(stdpat%(version,sw), h.stdout.getvalue())
)
-# This epilogue is needed for compatibility with the Python 2.5 regrtest module
+ def testCloseOnError(self):
+ side_effects = {'close_called': False}
+ MSG = b"Some output has been sent"
+ def error_app(e,s):
+ s("200 OK",[])(MSG)
+ class CrashyIterable(object):
+ def __iter__(self):
+ while True:
+ yield b'blah'
+ raise AssertionError("This should be caught by handler")
+
+ def close(self):
+ side_effects['close_called'] = True
+ return CrashyIterable()
+
+ h = ErrorHandler()
+ h.run(error_app)
+ self.assertEqual(side_effects['close_called'], True)
+
def test_main():
test_support.run_unittest(__name__)
if __name__ == "__main__":
test_main()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# the above lines intentionally left blank
diff --git a/lib-python/2.7/test/test_xml_etree.py b/lib-python/2.7/test/test_xml_etree.py
--- a/lib-python/2.7/test/test_xml_etree.py
+++ b/lib-python/2.7/test/test_xml_etree.py
@@ -1822,6 +1822,26 @@
"""
+def check_html_empty_elems_serialization(self):
+ # issue 15970
+ # from http://www.w3.org/TR/html401/index/elements.html
+ """
+
+ >>> empty_elems = ['AREA', 'BASE', 'BASEFONT', 'BR', 'COL', 'FRAME', 'HR',
+ ... 'IMG', 'INPUT', 'ISINDEX', 'LINK', 'META', 'PARAM']
+ >>> elems = ''.join('<%s />' % elem for elem in empty_elems)
+ >>> serialize(ET.XML('<html>%s</html>' % elems), method='html')
+ '<html><AREA><BASE><BASEFONT><BR><COL><FRAME><HR><IMG><INPUT><ISINDEX><LINK><META><PARAM></html>'
+ >>> serialize(ET.XML('<html>%s</html>' % elems.lower()), method='html')
+ '<html><area><base><basefont><br><col><frame><hr><img><input><isindex><link><meta><param></html>'
+ >>> elems = ''.join('<%s></%s>' % (elem, elem) for elem in empty_elems)
+ >>> serialize(ET.XML('<html>%s</html>' % elems), method='html')
+ '<html><AREA><BASE><BASEFONT><BR><COL><FRAME><HR><IMG><INPUT><ISINDEX><LINK><META><PARAM></html>'
+ >>> serialize(ET.XML('<html>%s</html>' % elems.lower()), method='html')
+ '<html><area><base><basefont><br><col><frame><hr><img><input><isindex><link><meta><param></html>'
+
+ """
+
# --------------------------------------------------------------------
diff --git a/lib-python/2.7/test/test_xrange.py b/lib-python/2.7/test/test_xrange.py
--- a/lib-python/2.7/test/test_xrange.py
+++ b/lib-python/2.7/test/test_xrange.py
@@ -46,6 +46,28 @@
self.fail('{}: wrong element at position {};'
'expected {}, got {}'.format(test_id, i, y, x))
+ def assert_xranges_equivalent(self, x, y):
+ # Check that two xrange objects are equivalent, in the sense of the
+ # associated sequences being the same. We want to use this for large
+ # xrange objects, so instead of converting to lists and comparing
+ # directly we do a number of indirect checks.
+ if len(x) != len(y):
+ self.fail('{} and {} have different '
+ 'lengths: {} and {} '.format(x, y, len(x), len(y)))
+ if len(x) >= 1:
+ if x[0] != y[0]:
+ self.fail('{} and {} have different initial '
+ 'elements: {} and {} '.format(x, y, x[0], y[0]))
+ if x[-1] != y[-1]:
+ self.fail('{} and {} have different final '
+ 'elements: {} and {} '.format(x, y, x[-1], y[-1]))
+ if len(x) >= 2:
+ x_step = x[1] - x[0]
+ y_step = y[1] - y[0]
+ if x_step != y_step:
+ self.fail('{} and {} have different step: '
+ '{} and {} '.format(x, y, x_step, y_step))
+
def test_xrange(self):
self.assertEqual(list(xrange(3)), [0, 1, 2])
self.assertEqual(list(xrange(1, 5)), [1, 2, 3, 4])
@@ -104,6 +126,59 @@
self.assertEqual(list(pickle.loads(pickle.dumps(r, proto))),
list(r))
+ M = min(sys.maxint, sys.maxsize)
+ large_testcases = testcases + [
+ (0, M, 1),
+ (M, 0, -1),
+ (0, M, M - 1),
+ (M // 2, M, 1),
+ (0, -M, -1),
+ (0, -M, 1 - M),
+ (-M, M, 2),
+ (-M, M, 1024),
+ (-M, M, 10585),
+ (M, -M, -2),
+ (M, -M, -1024),
+ (M, -M, -10585),
+ ]
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ for t in large_testcases:
+ r = xrange(*t)
+ r_out = pickle.loads(pickle.dumps(r, proto))
+ self.assert_xranges_equivalent(r_out, r)
+
+ def test_repr(self):
+ # Check that repr of an xrange is a valid representation
+ # of that xrange.
+
+ # Valid xranges have at most min(sys.maxint, sys.maxsize) elements.
+ M = min(sys.maxint, sys.maxsize)
+
+ testcases = [
+ (13,),
+ (0, 11),
+ (-22, 10),
+ (20, 3, -1),
+ (13, 21, 3),
+ (-2, 2, 2),
+ (0, M, 1),
+ (M, 0, -1),
+ (0, M, M - 1),
+ (M // 2, M, 1),
+ (0, -M, -1),
+ (0, -M, 1 - M),
+ (-M, M, 2),
+ (-M, M, 1024),
+ (-M, M, 10585),
+ (M, -M, -2),
+ (M, -M, -1024),
+ (M, -M, -10585),
+ ]
+ for t in testcases:
+ r = xrange(*t)
+ r_out = eval(repr(r))
+ self.assert_xranges_equivalent(r, r_out)
+
def test_range_iterators(self):
# see issue 7298
limits = [base + jiggle
diff --git a/lib-python/2.7/test/test_zipfile.py b/lib-python/2.7/test/test_zipfile.py
--- a/lib-python/2.7/test/test_zipfile.py
+++ b/lib-python/2.7/test/test_zipfile.py
@@ -26,7 +26,7 @@
SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'),
('ziptest2dir/_ziptest2', 'qawsedrftg'),
- ('/ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'),
+ ('ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'),
('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3', '6y7u8i9o0p')]
@@ -391,10 +391,7 @@
writtenfile = zipfp.extract(fpath)
# make sure it was written to the right place
- if os.path.isabs(fpath):
- correctfile = os.path.join(os.getcwd(), fpath[1:])
- else:
- correctfile = os.path.join(os.getcwd(), fpath)
+ correctfile = os.path.join(os.getcwd(), fpath)
correctfile = os.path.normpath(correctfile)
self.assertEqual(writtenfile, correctfile)
@@ -414,10 +411,7 @@
with zipfile.ZipFile(TESTFN2, "r") as zipfp:
zipfp.extractall()
for fpath, fdata in SMALL_TEST_DATA:
- if os.path.isabs(fpath):
- outfile = os.path.join(os.getcwd(), fpath[1:])
- else:
- outfile = os.path.join(os.getcwd(), fpath)
+ outfile = os.path.join(os.getcwd(), fpath)
self.assertEqual(fdata, open(outfile, "rb").read())
os.remove(outfile)
@@ -425,6 +419,92 @@
# remove the test file subdirectories
shutil.rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
+ def check_file(self, filename, content):
+ self.assertTrue(os.path.isfile(filename))
+ with open(filename, 'rb') as f:
+ self.assertEqual(f.read(), content)
+
+ def test_extract_hackers_arcnames(self):
+ hacknames = [
+ ('../foo/bar', 'foo/bar'),
+ ('foo/../bar', 'foo/bar'),
+ ('foo/../../bar', 'foo/bar'),
+ ('foo/bar/..', 'foo/bar'),
+ ('./../foo/bar', 'foo/bar'),
+ ('/foo/bar', 'foo/bar'),
+ ('/foo/../bar', 'foo/bar'),
+ ('/foo/../../bar', 'foo/bar'),
+ ]
+ if os.path.sep == '\\':
+ hacknames.extend([
+ (r'..\foo\bar', 'foo/bar'),
+ (r'..\/foo\/bar', 'foo/bar'),
+ (r'foo/\..\/bar', 'foo/bar'),
+ (r'foo\/../\bar', 'foo/bar'),
+ (r'C:foo/bar', 'foo/bar'),
+ (r'C:/foo/bar', 'foo/bar'),
+ (r'C://foo/bar', 'foo/bar'),
+ (r'C:\foo\bar', 'foo/bar'),
+ (r'//conky/mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
+ (r'\\conky\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
+ (r'///conky/mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
+ (r'\\\conky\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
+ (r'//conky//mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
+ (r'\\conky\\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
+ (r'//?/C:/foo/bar', '_/C_/foo/bar'),
+ (r'\\?\C:\foo\bar', '_/C_/foo/bar'),
+ (r'C:/../C:/foo/bar', 'C_/foo/bar'),
+ (r'a:b\c<d>e|f"g?h*i', 'b/c_d_e_f_g_h_i'),
+ ('../../foo../../ba..r', 'foo/ba..r'),
+ ])
+ else: # Unix
+ hacknames.extend([
+ ('//foo/bar', 'foo/bar'),
+ ('../../foo../../ba..r', 'foo../ba..r'),
+ (r'foo/..\bar', r'foo/..\bar'),
+ ])
+
+ for arcname, fixedname in hacknames:
+ content = b'foobar' + arcname.encode()
+ with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipfp:
+ zinfo = zipfile.ZipInfo()
+ # preserve backslashes
+ zinfo.filename = arcname
+ zinfo.external_attr = 0o600 << 16
+ zipfp.writestr(zinfo, content)
+
+ arcname = arcname.replace(os.sep, "/")
+ targetpath = os.path.join('target', 'subdir', 'subsub')
+ correctfile = os.path.join(targetpath, *fixedname.split('/'))
+
+ with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
+ writtenfile = zipfp.extract(arcname, targetpath)
+ self.assertEqual(writtenfile, correctfile,
+ msg="extract %r" % arcname)
+ self.check_file(correctfile, content)
+ shutil.rmtree('target')
+
+ with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
+ zipfp.extractall(targetpath)
+ self.check_file(correctfile, content)
+ shutil.rmtree('target')
+
+ correctfile = os.path.join(os.getcwd(), *fixedname.split('/'))
+
+ with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
+ writtenfile = zipfp.extract(arcname)
+ self.assertEqual(writtenfile, correctfile,
+ msg="extract %r" % arcname)
+ self.check_file(correctfile, content)
+ shutil.rmtree(fixedname.split('/')[0])
+
+ with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
+ zipfp.extractall()
+ self.check_file(correctfile, content)
+ shutil.rmtree(fixedname.split('/')[0])
+
+ os.remove(TESTFN2)
+
def test_writestr_compression(self):
zipfp = zipfile.ZipFile(TESTFN2, "w")
zipfp.writestr("a.txt", "hello world", compress_type=zipfile.ZIP_STORED)
@@ -760,6 +840,20 @@
chk = zipfile.is_zipfile(fp)
self.assertTrue(not chk)
+ def test_damaged_zipfile(self):
+ """Check that zipfiles with missing bytes at the end raise BadZipFile."""
+ # - Create a valid zip file
+ fp = io.BytesIO()
+ with zipfile.ZipFile(fp, mode="w") as zipf:
+ zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
+ zipfiledata = fp.getvalue()
+
+ # - Now create copies of it missing the last N bytes and make sure
+ # a BadZipFile exception is raised when we try to open it
+ for N in range(len(zipfiledata)):
+ fp = io.BytesIO(zipfiledata[:N])
+ self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, fp)
+
def test_is_zip_valid_file(self):
"""Check that is_zipfile() correctly identifies zip files."""
# - passing a filename
@@ -811,7 +905,7 @@
with zipfile.ZipFile(data, mode="w") as zipf:
zipf.writestr("foo.txt", "O, for a Muse of Fire!")
- # This is correct; calling .read on a closed ZipFile should throw
+ # This is correct; calling .read on a closed ZipFile should raise
# a RuntimeError, and so should calling .testzip. An earlier
# version of .testzip would swallow this exception (and any other)
# and report that the first file in the archive was corrupt.
@@ -859,6 +953,17 @@
caught."""
self.assertRaises(RuntimeError, zipfile.ZipFile, TESTFN, "w", -1)
+ def test_unsupported_compression(self):
+ # data is declared as shrunk, but actually deflated
+ data = (b'PK\x03\x04.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00'
+ b'\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00x\x03\x00PK\x01'
+ b'\x02.\x03.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00\x00\x02\x00\x00'
+ b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x80\x01\x00\x00\x00\x00xPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00'
+ b'/\x00\x00\x00!\x00\x00\x00\x00\x00')
+ with zipfile.ZipFile(io.BytesIO(data), 'r') as zipf:
+ self.assertRaises(NotImplementedError, zipf.open, 'x')
+
def test_null_byte_in_filename(self):
"""Check that a filename containing a null byte is properly
terminated."""
@@ -908,6 +1013,22 @@
with zipfile.ZipFile(TESTFN, mode="r") as zipf:
self.assertEqual(zipf.comment, comment2)
+ def test_change_comment_in_empty_archive(self):
+ with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
+ self.assertFalse(zipf.filelist)
+ zipf.comment = b"this is a comment"
+ with zipfile.ZipFile(TESTFN, "r") as zipf:
+ self.assertEqual(zipf.comment, b"this is a comment")
+
+ def test_change_comment_in_nonempty_archive(self):
+ with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
+ zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+ with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
+ self.assertTrue(zipf.filelist)
+ zipf.comment = b"this is a comment"
+ with zipfile.ZipFile(TESTFN, "r") as zipf:
+ self.assertEqual(zipf.comment, b"this is a comment")
+
def check_testzip_with_bad_crc(self, compression):
"""Tests that files with bad CRCs return their name from testzip."""
zipdata = self.zips_with_bad_crc[compression]
diff --git a/lib-python/2.7/test/test_zipimport_support.py b/lib-python/2.7/test/test_zipimport_support.py
--- a/lib-python/2.7/test/test_zipimport_support.py
+++ b/lib-python/2.7/test/test_zipimport_support.py
@@ -29,7 +29,8 @@
# test_cmd_line_script (covers the zipimport support in runpy)
# Retrieve some helpers from other test cases
-from test import test_doctest, sample_doctest
+from test import (test_doctest, sample_doctest, sample_doctest_no_doctests,
+ sample_doctest_no_docstrings)
from test.test_importhooks import ImportHooksBaseTestCase
@@ -99,16 +100,26 @@
"test_zipped_doctest")
test_src = test_src.replace("test.sample_doctest",
"sample_zipped_doctest")
- sample_src = inspect.getsource(sample_doctest)
- sample_src = sample_src.replace("test.test_doctest",
- "test_zipped_doctest")
+ # The sample doctest files rewritten to include in the zipped version.
+ sample_sources = {}
+ for mod in [sample_doctest, sample_doctest_no_doctests,
+ sample_doctest_no_docstrings]:
+ src = inspect.getsource(mod)
+ src = src.replace("test.test_doctest", "test_zipped_doctest")
+ # Rewrite the module name so that, for example,
+ # "test.sample_doctest" becomes "sample_zipped_doctest".
+ mod_name = mod.__name__.split(".")[-1]
+ mod_name = mod_name.replace("sample_", "sample_zipped_")
+ sample_sources[mod_name] = src
+
with temp_dir() as d:
script_name = make_script(d, 'test_zipped_doctest',
test_src)
zip_name, run_name = make_zip_script(d, 'test_zip',
script_name)
z = zipfile.ZipFile(zip_name, 'a')
- z.writestr("sample_zipped_doctest.py", sample_src)
+ for mod_name, src in sample_sources.items():
+ z.writestr(mod_name + ".py", src)
z.close()
if verbose:
zip_file = zipfile.ZipFile(zip_name, 'r')
@@ -168,9 +179,10 @@
test_zipped_doctest.test_unittest_reportflags,
]
# Needed for test_DocTestParser and test_debug
- deprecations = [
+ deprecations = []
+ if __debug__:
# Ignore all warnings about the use of class Tester in this module.
- ("class Tester is deprecated", DeprecationWarning)]
+ deprecations.append(("class Tester is deprecated", DeprecationWarning))
if sys.py3kwarning:
deprecations += [
("backquote not supported", SyntaxWarning),
diff --git a/lib-python/2.7/test/test_zlib.py b/lib-python/2.7/test/test_zlib.py
--- a/lib-python/2.7/test/test_zlib.py
+++ b/lib-python/2.7/test/test_zlib.py
@@ -396,6 +396,18 @@
y += dco.flush()
self.assertEqual(y, 'foo')
+ def test_flush_with_freed_input(self):
+ # Issue #16411: decompressor accesses input to last decompress() call
+ # in flush(), even if this object has been freed in the meanwhile.
+ input1 = 'abcdefghijklmnopqrstuvwxyz'
+ input2 = 'QWERTYUIOPASDFGHJKLZXCVBNM'
+ data = zlib.compress(input1)
+ dco = zlib.decompressobj()
+ dco.decompress(data, 1)
+ del data
+ data = zlib.compress(input2)
+ self.assertEqual(dco.flush(), input1[1:])
+
if hasattr(zlib.compressobj(), "copy"):
def test_compresscopy(self):
# Test copying a compression object
@@ -426,6 +438,31 @@
c.flush()
self.assertRaises(ValueError, c.copy)
+ def test_decompress_unused_data(self):
+ # Repeated calls to decompress() after EOF should accumulate data in
+ # dco.unused_data, instead of just storing the arg to the last call.
+ source = b'abcdefghijklmnopqrstuvwxyz'
+ remainder = b'0123456789'
+ y = zlib.compress(source)
+ x = y + remainder
+ for maxlen in 0, 1000:
+ for step in 1, 2, len(y), len(x):
+ dco = zlib.decompressobj()
+ data = b''
+ for i in range(0, len(x), step):
+ if i < len(y):
+ self.assertEqual(dco.unused_data, b'')
+ if maxlen == 0:
+ data += dco.decompress(x[i : i + step])
+ self.assertEqual(dco.unconsumed_tail, b'')
+ else:
+ data += dco.decompress(
+ dco.unconsumed_tail + x[i : i + step], maxlen)
+ data += dco.flush()
+ self.assertEqual(data, source)
+ self.assertEqual(dco.unconsumed_tail, b'')
+ self.assertEqual(dco.unused_data, remainder)
+
if hasattr(zlib.decompressobj(), "copy"):
def test_decompresscopy(self):
# Test copying a decompression object
diff --git a/lib-python/2.7/test/testtar.tar b/lib-python/2.7/test/testtar.tar
index bac0e2628f35243f236db2fac82737882699b2f0..440182a437da84ef3d61d8cbc0f4209254615b37
GIT binary patch
[stripped]
diff --git a/lib-python/2.7/textwrap.py b/lib-python/2.7/textwrap.py
--- a/lib-python/2.7/textwrap.py
+++ b/lib-python/2.7/textwrap.py
@@ -9,6 +9,14 @@
import string, re
+try:
+ _unicode = unicode
+except NameError:
+ # If Python is built without Unicode support, the unicode type
+ # will not exist. Fake one.
+ class _unicode(object):
+ pass
+
# Do the right thing with boolean values for all known Python versions
# (so this module can be copied to projects that don't depend on Python
# 2.3, e.g. Optik and Docutils) by uncommenting the block of code below.
@@ -147,7 +155,7 @@
if self.replace_whitespace:
if isinstance(text, str):
text = text.translate(self.whitespace_trans)
- elif isinstance(text, unicode):
+ elif isinstance(text, _unicode):
text = text.translate(self.unicode_whitespace_trans)
return text
@@ -167,7 +175,7 @@
'use', ' ', 'the', ' ', '-b', ' ', option!'
otherwise.
"""
- if isinstance(text, unicode):
+ if isinstance(text, _unicode):
if self.break_on_hyphens:
pat = self.wordsep_re_uni
else:
diff --git a/lib-python/2.7/threading.py b/lib-python/2.7/threading.py
--- a/lib-python/2.7/threading.py
+++ b/lib-python/2.7/threading.py
@@ -10,6 +10,7 @@
import warnings
+from collections import deque as _deque
from time import time as _time, sleep as _sleep
from traceback import format_exc as _format_exc
@@ -605,6 +606,10 @@
pass
def __stop(self):
+ # DummyThreads delete self.__block, but they have no waiters to
+ # notify anyway (join() is forbidden on them).
+ if not hasattr(self, '_Thread__block'):
+ return
self.__block.acquire()
self.__stopped = True
self.__block.notify_all()
@@ -909,7 +914,7 @@
self.rc = Condition(self.mon)
self.wc = Condition(self.mon)
self.limit = limit
- self.queue = deque()
+ self.queue = _deque()
def put(self, item):
self.mon.acquire()
diff --git a/lib-python/2.7/tokenize.py b/lib-python/2.7/tokenize.py
--- a/lib-python/2.7/tokenize.py
+++ b/lib-python/2.7/tokenize.py
@@ -70,10 +70,10 @@
Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''"
# Tail end of """ string.
Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""'
-Triple = group("[uU]?[rR]?'''", '[uU]?[rR]?"""')
+Triple = group("[uUbB]?[rR]?'''", '[uUbB]?[rR]?"""')
# Single-line ' or " string.
-String = group(r"[uU]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*'",
- r'[uU]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*"')
+String = group(r"[uUbB]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*'",
+ r'[uUbB]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*"')
# Because of leftmost-then-longest match semantics, be sure to put the
# longest operators first (e.g., if = came before ==, == would get
@@ -91,11 +91,11 @@
Token = Ignore + PlainToken
# First (or only) line of ' or " string.
-ContStr = group(r"[uU]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*" +
+ContStr = group(r"[uUbB]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*" +
group("'", r'\\\r?\n'),
- r'[uU]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*' +
+ r'[uUbB]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*' +
group('"', r'\\\r?\n'))
-PseudoExtras = group(r'\\\r?\n', Comment, Triple)
+PseudoExtras = group(r'\\\r?\n|\Z', Comment, Triple)
PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name)
tokenprog, pseudoprog, single3prog, double3prog = map(
@@ -362,6 +362,8 @@
if pseudomatch: # scan for tokens
start, end = pseudomatch.span(1)
spos, epos, pos = (lnum, start), (lnum, end), end
+ if start == end:
+ continue
token, initial = line[start:end], line[start]
if initial in numchars or \
diff --git a/lib-python/2.7/traceback.py b/lib-python/2.7/traceback.py
--- a/lib-python/2.7/traceback.py
+++ b/lib-python/2.7/traceback.py
@@ -166,7 +166,7 @@
# >>> raise string1, string2 # deprecated
#
# Clear these out first because issubtype(string1, SyntaxError)
- # would throw another exception and mask the original problem.
+ # would raise another exception and mask the original problem.
if (isinstance(etype, BaseException) or
isinstance(etype, types.InstanceType) or
etype is None or type(etype) is str):
diff --git a/lib-python/2.7/unittest/case.py b/lib-python/2.7/unittest/case.py
--- a/lib-python/2.7/unittest/case.py
+++ b/lib-python/2.7/unittest/case.py
@@ -6,6 +6,7 @@
import difflib
import pprint
import re
+import types
import warnings
from . import result
@@ -55,7 +56,7 @@
Unconditionally skip a test.
"""
def decorator(test_item):
- if not (isinstance(test_item, type) and issubclass(test_item, TestCase)):
+ if not isinstance(test_item, (type, types.ClassType)):
@functools.wraps(test_item)
def skip_wrapper(*args, **kwargs):
raise SkipTest(reason)
@@ -201,7 +202,11 @@
self.addTypeEqualityFunc(tuple, 'assertTupleEqual')
self.addTypeEqualityFunc(set, 'assertSetEqual')
self.addTypeEqualityFunc(frozenset, 'assertSetEqual')
- self.addTypeEqualityFunc(unicode, 'assertMultiLineEqual')
+ try:
+ self.addTypeEqualityFunc(unicode, 'assertMultiLineEqual')
+ except NameError:
+ # No unicode support in this build
+ pass
def addTypeEqualityFunc(self, typeobj, function):
"""Add a type specific assertEqual style function to compare a type.
@@ -442,10 +447,10 @@
def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
- """Fail unless an exception of class excClass is thrown
+ """Fail unless an exception of class excClass is raised
by callableObj when invoked with arguments args and keyword
arguments kwargs. If a different type of exception is
- thrown, it will not be caught, and the test case will be
+ raised, it will not be caught, and the test case will be
deemed to have suffered an error, exactly as for an
unexpected exception.
@@ -511,7 +516,7 @@
assertion_func(first, second, msg=msg)
def assertNotEqual(self, first, second, msg=None):
- """Fail if the two objects are equal as determined by the '=='
+ """Fail if the two objects are equal as determined by the '!='
operator.
"""
if not first != second:
@@ -871,7 +876,7 @@
- [0, 1, 1] and [1, 0, 1] compare equal.
- [0, 0, 1] and [0, 1] compare unequal.
"""
- first_seq, second_seq = list(actual_seq), list(expected_seq)
+ first_seq, second_seq = list(expected_seq), list(actual_seq)
with warnings.catch_warnings():
if sys.py3kwarning:
# Silence Py3k warning raised during the sorting
diff --git a/lib-python/2.7/unittest/main.py b/lib-python/2.7/unittest/main.py
--- a/lib-python/2.7/unittest/main.py
+++ b/lib-python/2.7/unittest/main.py
@@ -157,7 +157,10 @@
self.test = self.testLoader.loadTestsFromNames(self.testNames,
self.module)
- def _do_discovery(self, argv, Loader=loader.TestLoader):
+ def _do_discovery(self, argv, Loader=None):
+ if Loader is None:
+ Loader = lambda: self.testLoader
+
# handle command line args for test discovery
self.progName = '%s discover' % self.progName
import optparse
diff --git a/lib-python/2.7/unittest/runner.py b/lib-python/2.7/unittest/runner.py
--- a/lib-python/2.7/unittest/runner.py
+++ b/lib-python/2.7/unittest/runner.py
@@ -34,7 +34,7 @@
separator2 = '-' * 70
def __init__(self, stream, descriptions, verbosity):
- super(TextTestResult, self).__init__()
+ super(TextTestResult, self).__init__(stream, descriptions, verbosity)
self.stream = stream
self.showAll = verbosity > 1
self.dots = verbosity == 1
diff --git a/lib-python/2.7/unittest/signals.py b/lib-python/2.7/unittest/signals.py
--- a/lib-python/2.7/unittest/signals.py
+++ b/lib-python/2.7/unittest/signals.py
@@ -9,6 +9,20 @@
class _InterruptHandler(object):
def __init__(self, default_handler):
self.called = False
+ self.original_handler = default_handler
+ if isinstance(default_handler, int):
+ if default_handler == signal.SIG_DFL:
+ # Pretend it's signal.default_int_handler instead.
+ default_handler = signal.default_int_handler
+ elif default_handler == signal.SIG_IGN:
+ # Not quite the same thing as SIG_IGN, but the closest we
+ # can make it: do nothing.
+ def default_handler(unused_signum, unused_frame):
+ pass
+ else:
+ raise TypeError("expected SIGINT signal handler to be "
+ "signal.SIG_IGN, signal.SIG_DFL, or a "
+ "callable object")
self.default_handler = default_handler
def __call__(self, signum, frame):
@@ -54,4 +68,4 @@
global _interrupt_handler
if _interrupt_handler is not None:
- signal.signal(signal.SIGINT, _interrupt_handler.default_handler)
+ signal.signal(signal.SIGINT, _interrupt_handler.original_handler)
diff --git a/lib-python/2.7/unittest/test/test_break.py b/lib-python/2.7/unittest/test/test_break.py
--- a/lib-python/2.7/unittest/test/test_break.py
+++ b/lib-python/2.7/unittest/test/test_break.py
@@ -15,9 +15,12 @@
@unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 "
"if threads have been used")
class TestBreak(unittest.TestCase):
+ int_handler = None
def setUp(self):
self._default_handler = signal.getsignal(signal.SIGINT)
+ if self.int_handler is not None:
+ signal.signal(signal.SIGINT, self.int_handler)
def tearDown(self):
signal.signal(signal.SIGINT, self._default_handler)
@@ -74,6 +77,10 @@
def testSecondInterrupt(self):
+ # Can't use skipIf decorator because the signal handler may have
+ # been changed after defining this method.
+ if signal.getsignal(signal.SIGINT) == signal.SIG_IGN:
+ self.skipTest("test requires SIGINT to not be ignored")
result = unittest.TestResult()
unittest.installHandler()
unittest.registerResult(result)
@@ -123,6 +130,10 @@
def testHandlerReplacedButCalled(self):
+ # Can't use skipIf decorator because the signal handler may have
+ # been changed after defining this method.
+ if signal.getsignal(signal.SIGINT) == signal.SIG_IGN:
+ self.skipTest("test requires SIGINT to not be ignored")
# If our handler has been replaced (is no longer installed) but is
# called by the *new* handler, then it isn't safe to delay the
# SIGINT and we should immediately delegate to the default handler
@@ -250,3 +261,24 @@
test()
self.assertNotEqual(signal.getsignal(signal.SIGINT), default_handler)
+
+ at unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill")
+ at unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows")
+ at unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 "
+ "if threads have been used")
+class TestBreakDefaultIntHandler(TestBreak):
+ int_handler = signal.default_int_handler
+
+ at unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill")
+ at unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows")
+ at unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 "
+ "if threads have been used")
+class TestBreakSignalIgnored(TestBreak):
+ int_handler = signal.SIG_IGN
+
+ at unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill")
+ at unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows")
+ at unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 "
+ "if threads have been used")
+class TestBreakSignalDefault(TestBreak):
+ int_handler = signal.SIG_DFL
diff --git a/lib-python/2.7/unittest/test/test_discovery.py b/lib-python/2.7/unittest/test/test_discovery.py
--- a/lib-python/2.7/unittest/test/test_discovery.py
+++ b/lib-python/2.7/unittest/test/test_discovery.py
@@ -220,12 +220,26 @@
program = object.__new__(unittest.TestProgram)
program.usageExit = usageExit
+ program.testLoader = None
with self.assertRaises(Stop):
# too many args
program._do_discovery(['one', 'two', 'three', 'four'])
+ def test_command_line_handling_do_discovery_uses_default_loader(self):
+ program = object.__new__(unittest.TestProgram)
+
+ class Loader(object):
+ args = []
+ def discover(self, start_dir, pattern, top_level_dir):
+ self.args.append((start_dir, pattern, top_level_dir))
+ return 'tests'
+
+ program.testLoader = Loader()
+ program._do_discovery(['-v'])
+ self.assertEqual(Loader.args, [('.', 'test*.py', None)])
+
def test_command_line_handling_do_discovery_calls_loader(self):
program = object.__new__(unittest.TestProgram)
diff --git a/lib-python/2.7/unittest/test/test_runner.py b/lib-python/2.7/unittest/test/test_runner.py
--- a/lib-python/2.7/unittest/test/test_runner.py
+++ b/lib-python/2.7/unittest/test/test_runner.py
@@ -149,6 +149,19 @@
self.assertEqual(runner.resultclass, unittest.TextTestResult)
+ def test_multiple_inheritance(self):
+ class AResult(unittest.TestResult):
+ def __init__(self, stream, descriptions, verbosity):
+ super(AResult, self).__init__(stream, descriptions, verbosity)
+
+ class ATextResult(unittest.TextTestResult, AResult):
+ pass
+
+ # This used to raise an exception due to TextTestResult not passing
+ # on arguments in its __init__ super call
+ ATextResult(None, None, None)
+
+
def testBufferAndFailfast(self):
class Test(unittest.TestCase):
def testFoo(self):
diff --git a/lib-python/2.7/unittest/test/test_skipping.py b/lib-python/2.7/unittest/test/test_skipping.py
--- a/lib-python/2.7/unittest/test/test_skipping.py
+++ b/lib-python/2.7/unittest/test/test_skipping.py
@@ -66,6 +66,36 @@
self.assertEqual(result.skipped, [(test, "testing")])
self.assertEqual(record, [])
+ def test_skip_non_unittest_class_old_style(self):
+ @unittest.skip("testing")
+ class Mixin:
+ def test_1(self):
+ record.append(1)
+ class Foo(Mixin, unittest.TestCase):
+ pass
+ record = []
+ result = unittest.TestResult()
+ test = Foo("test_1")
+ suite = unittest.TestSuite([test])
+ suite.run(result)
+ self.assertEqual(result.skipped, [(test, "testing")])
+ self.assertEqual(record, [])
+
+ def test_skip_non_unittest_class_new_style(self):
+ @unittest.skip("testing")
+ class Mixin(object):
+ def test_1(self):
+ record.append(1)
+ class Foo(Mixin, unittest.TestCase):
+ pass
+ record = []
+ result = unittest.TestResult()
+ test = Foo("test_1")
+ suite = unittest.TestSuite([test])
+ suite.run(result)
+ self.assertEqual(result.skipped, [(test, "testing")])
+ self.assertEqual(record, [])
+
def test_expected_failure(self):
class Foo(unittest.TestCase):
@unittest.expectedFailure
diff --git a/lib-python/2.7/urllib2.py b/lib-python/2.7/urllib2.py
--- a/lib-python/2.7/urllib2.py
+++ b/lib-python/2.7/urllib2.py
@@ -102,6 +102,7 @@
import time
import urlparse
import bisect
+import warnings
try:
from cStringIO import StringIO
@@ -109,7 +110,7 @@
from StringIO import StringIO
from urllib import (unwrap, unquote, splittype, splithost, quote,
- addinfourl, splitport, splittag,
+ addinfourl, splitport, splittag, toBytes,
splitattr, ftpwrapper, splituser, splitpasswd, splitvalue)
# support for FileHandler, proxies via environment variables
@@ -172,6 +173,9 @@
def reason(self):
return self.msg
+ def info(self):
+ return self.hdrs
+
# copied from cookielib.py
_cut_port_re = re.compile(r":\d+$")
def request_host(request):
@@ -828,7 +832,7 @@
# allow for double- and single-quoted realm values
# (single quotes are a violation of the RFC, but appear in the wild)
rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+'
- 'realm=(["\'])(.*?)\\2', re.I)
+ 'realm=(["\']?)([^"\']*)\\2', re.I)
# XXX could pre-emptively send auth info already accepted (RFC 2617,
# end of section 2, and section 1.2 immediately after "credentials"
@@ -861,6 +865,9 @@
mo = AbstractBasicAuthHandler.rx.search(authreq)
if mo:
scheme, quote, realm = mo.groups()
+ if quote not in ['"', "'"]:
+ warnings.warn("Basic Auth Realm was unquoted",
+ UserWarning, 2)
if scheme.lower() == 'basic':
response = self.retry_http_basic_auth(host, req, realm)
if response and response.code != 401:
diff --git a/lib-python/2.7/urlparse.py b/lib-python/2.7/urlparse.py
--- a/lib-python/2.7/urlparse.py
+++ b/lib-python/2.7/urlparse.py
@@ -40,11 +40,14 @@
'imap', 'wais', 'file', 'mms', 'https', 'shttp',
'snews', 'prospero', 'rtsp', 'rtspu', 'rsync', '',
'svn', 'svn+ssh', 'sftp','nfs','git', 'git+ssh']
+uses_params = ['ftp', 'hdl', 'prospero', 'http', 'imap',
+ 'https', 'shttp', 'rtsp', 'rtspu', 'sip', 'sips',
+ 'mms', '', 'sftp', 'tel']
+
+# These are not actually used anymore, but should stay for backwards
+# compatibility. (They are undocumented, but have a public-looking name.)
non_hierarchical = ['gopher', 'hdl', 'mailto', 'news',
'telnet', 'wais', 'imap', 'snews', 'sip', 'sips']
-uses_params = ['ftp', 'hdl', 'prospero', 'http', 'imap',
- 'https', 'shttp', 'rtsp', 'rtspu', 'sip', 'sips',
- 'mms', '', 'sftp']
uses_query = ['http', 'wais', 'imap', 'https', 'shttp', 'mms',
'gopher', 'rtsp', 'rtspu', 'sip', 'sips', '']
uses_fragment = ['ftp', 'hdl', 'http', 'gopher', 'news',
@@ -104,9 +107,11 @@
netloc = self.netloc.split('@')[-1].split(']')[-1]
if ':' in netloc:
port = netloc.split(':')[1]
- return int(port, 10)
- else:
- return None
+ port = int(port, 10)
+ # verify legal port
+ if (0 <= port <= 65535):
+ return port
+ return None
from collections import namedtuple
@@ -192,21 +197,21 @@
if c not in scheme_chars:
break
else:
- try:
- # make sure "url" is not actually a port number (in which case
- # "scheme" is really part of the path
- _testportnum = int(url[i+1:])
- except ValueError:
- scheme, url = url[:i].lower(), url[i+1:]
+ # make sure "url" is not actually a port number (in which case
+ # "scheme" is really part of the path)
+ rest = url[i+1:]
+ if not rest or any(c not in '0123456789' for c in rest):
+ # not a port number
+ scheme, url = url[:i].lower(), rest
if url[:2] == '//':
netloc, url = _splitnetloc(url, 2)
if (('[' in netloc and ']' not in netloc) or
(']' in netloc and '[' not in netloc)):
raise ValueError("Invalid IPv6 URL")
- if allow_fragments and scheme in uses_fragment and '#' in url:
+ if allow_fragments and '#' in url:
url, fragment = url.split('#', 1)
- if scheme in uses_query and '?' in url:
+ if '?' in url:
url, query = url.split('?', 1)
v = SplitResult(scheme, netloc, url, query, fragment)
_parse_cache[key] = v
diff --git a/lib-python/2.7/wave.py b/lib-python/2.7/wave.py
--- a/lib-python/2.7/wave.py
+++ b/lib-python/2.7/wave.py
@@ -261,9 +261,9 @@
#
def _read_fmt_chunk(self, chunk):
- wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<hhllh', chunk.read(14))
+ wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<HHLLH', chunk.read(14))
if wFormatTag == WAVE_FORMAT_PCM:
- sampwidth = struct.unpack('<h', chunk.read(2))[0]
+ sampwidth = struct.unpack('<H', chunk.read(2))[0]
self._sampwidth = (sampwidth + 7) // 8
else:
raise Error, 'unknown format: %r' % (wFormatTag,)
@@ -466,14 +466,14 @@
self._nframes = initlength / (self._nchannels * self._sampwidth)
self._datalength = self._nframes * self._nchannels * self._sampwidth
self._form_length_pos = self._file.tell()
- self._file.write(struct.pack('<l4s4slhhllhh4s',
+ self._file.write(struct.pack('<L4s4sLHHLLHH4s',
36 + self._datalength, 'WAVE', 'fmt ', 16,
WAVE_FORMAT_PCM, self._nchannels, self._framerate,
self._nchannels * self._framerate * self._sampwidth,
self._nchannels * self._sampwidth,
self._sampwidth * 8, 'data'))
self._data_length_pos = self._file.tell()
- self._file.write(struct.pack('<l', self._datalength))
+ self._file.write(struct.pack('<L', self._datalength))
self._headerwritten = True
def _patchheader(self):
@@ -482,9 +482,9 @@
return
curpos = self._file.tell()
self._file.seek(self._form_length_pos, 0)
- self._file.write(struct.pack('<l', 36 + self._datawritten))
+ self._file.write(struct.pack('<L', 36 + self._datawritten))
self._file.seek(self._data_length_pos, 0)
- self._file.write(struct.pack('<l', self._datawritten))
+ self._file.write(struct.pack('<L', self._datawritten))
self._file.seek(curpos, 0)
self._datalength = self._datawritten
diff --git a/lib-python/2.7/wsgiref/handlers.py b/lib-python/2.7/wsgiref/handlers.py
--- a/lib-python/2.7/wsgiref/handlers.py
+++ b/lib-python/2.7/wsgiref/handlers.py
@@ -122,11 +122,13 @@
in the event loop to iterate over the data, and to call
'self.close()' once the response is finished.
"""
- if not self.result_is_file() or not self.sendfile():
- for data in self.result:
- self.write(data)
- self.finish_content()
- self.close()
+ try:
+ if not self.result_is_file() or not self.sendfile():
+ for data in self.result:
+ self.write(data)
+ self.finish_content()
+ finally:
+ self.close()
def get_scheme(self):
diff --git a/lib-python/2.7/wsgiref/validate.py b/lib-python/2.7/wsgiref/validate.py
--- a/lib-python/2.7/wsgiref/validate.py
+++ b/lib-python/2.7/wsgiref/validate.py
@@ -134,9 +134,9 @@
When applied between a WSGI server and a WSGI application, this
middleware will check for WSGI compliancy on a number of levels.
This middleware does not modify the request or response in any
- way, but will throw an AssertionError if anything seems off
+ way, but will raise an AssertionError if anything seems off
(except for a failure to close the application iterator, which
- will be printed to stderr -- there's no way to throw an exception
+ will be printed to stderr -- there's no way to raise an exception
at that point).
"""
diff --git a/lib-python/2.7/xml/dom/minidom.py b/lib-python/2.7/xml/dom/minidom.py
--- a/lib-python/2.7/xml/dom/minidom.py
+++ b/lib-python/2.7/xml/dom/minidom.py
@@ -1,5 +1,6 @@
-"""\
-minidom.py -- a lightweight DOM implementation.
+"""Simple implementation of the Level 1 DOM.
+
+Namespaces and other minor Level 2 features are also supported.
parse("foo.xml")
diff --git a/lib-python/2.7/xml/etree/ElementTree.py b/lib-python/2.7/xml/etree/ElementTree.py
--- a/lib-python/2.7/xml/etree/ElementTree.py
+++ b/lib-python/2.7/xml/etree/ElementTree.py
@@ -779,11 +779,12 @@
# @param file A file name, or a file object opened for writing.
# @param **options Options, given as keyword arguments.
# @keyparam encoding Optional output encoding (default is US-ASCII).
- # @keyparam method Optional output method ("xml", "html", "text" or
- # "c14n"; default is "xml").
# @keyparam xml_declaration Controls if an XML declaration should
# be added to the file. Use False for never, True for always,
# None for only if not US-ASCII or UTF-8. None is default.
+ # @keyparam default_namespace Sets the default XML namespace (for "xmlns").
+ # @keyparam method Optional output method ("xml", "html", "text" or
+ # "c14n"; default is "xml").
def write(self, file_or_filename,
# keyword arguments
@@ -945,7 +946,7 @@
write(_escape_cdata(elem.tail, encoding))
HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
- "img", "input", "isindex", "link", "meta" "param")
+ "img", "input", "isindex", "link", "meta", "param")
try:
HTML_EMPTY = set(HTML_EMPTY)
diff --git a/lib-python/2.7/xml/sax/_exceptions.py b/lib-python/2.7/xml/sax/_exceptions.py
--- a/lib-python/2.7/xml/sax/_exceptions.py
+++ b/lib-python/2.7/xml/sax/_exceptions.py
@@ -12,7 +12,7 @@
the application: you can subclass it to provide additional
functionality, or to add localization. Note that although you will
receive a SAXException as the argument to the handlers in the
- ErrorHandler interface, you are not actually required to throw
+ ErrorHandler interface, you are not actually required to raise
the exception; instead, you can simply read the information in
it."""
@@ -50,7 +50,7 @@
the original XML document. Note that although the application will
receive a SAXParseException as the argument to the handlers in the
ErrorHandler interface, the application is not actually required
- to throw the exception; instead, it can simply read the
+ to raise the exception; instead, it can simply read the
information in it and take a different action.
Since this exception is a subclass of SAXException, it inherits
@@ -62,7 +62,7 @@
self._locator = locator
# We need to cache this stuff at construction time.
- # If this exception is thrown, the objects through which we must
+ # If this exception is raised, the objects through which we must
# traverse to get this information may be deleted by the time
# it gets caught.
self._systemId = self._locator.getSystemId()
diff --git a/lib-python/2.7/xml/sax/expatreader.py b/lib-python/2.7/xml/sax/expatreader.py
--- a/lib-python/2.7/xml/sax/expatreader.py
+++ b/lib-python/2.7/xml/sax/expatreader.py
@@ -108,7 +108,10 @@
def prepareParser(self, source):
if source.getSystemId() is not None:
- self._parser.SetBase(source.getSystemId())
+ base = source.getSystemId()
+ if isinstance(base, unicode):
+ base = base.encode('utf-8')
+ self._parser.SetBase(base)
# Redefined setContentHandler to allow changing handlers during parsing
diff --git a/lib-python/2.7/xml/sax/saxutils.py b/lib-python/2.7/xml/sax/saxutils.py
--- a/lib-python/2.7/xml/sax/saxutils.py
+++ b/lib-python/2.7/xml/sax/saxutils.py
@@ -4,6 +4,8 @@
"""
import os, urlparse, urllib, types
+import io
+import sys
import handler
import xmlreader
@@ -12,15 +14,6 @@
except AttributeError:
_StringTypes = [types.StringType]
-# See whether the xmlcharrefreplace error handler is
-# supported
-try:
- from codecs import xmlcharrefreplace_errors
- _error_handling = "xmlcharrefreplace"
- del xmlcharrefreplace_errors
-except ImportError:
- _error_handling = "strict"
-
def __dict_replace(s, d):
"""Replace substrings of a string using a dictionary."""
for key, value in d.items():
@@ -81,25 +74,50 @@
return data
+def _gettextwriter(out, encoding):
+ if out is None:
+ import sys
+ out = sys.stdout
+
+ if isinstance(out, io.RawIOBase):
+ buffer = io.BufferedIOBase(out)
+ # Keep the original file open when the TextIOWrapper is
+ # destroyed
+ buffer.close = lambda: None
+ else:
+ # This is to handle passed objects that aren't in the
+ # IOBase hierarchy, but just have a write method
+ buffer = io.BufferedIOBase()
+ buffer.writable = lambda: True
+ buffer.write = out.write
+ try:
+ # TextIOWrapper uses this methods to determine
+ # if BOM (for UTF-16, etc) should be added
+ buffer.seekable = out.seekable
+ buffer.tell = out.tell
+ except AttributeError:
+ pass
+ # wrap a binary writer with TextIOWrapper
+ class UnbufferedTextIOWrapper(io.TextIOWrapper):
+ def write(self, s):
+ super(UnbufferedTextIOWrapper, self).write(s)
+ self.flush()
+ return UnbufferedTextIOWrapper(buffer, encoding=encoding,
+ errors='xmlcharrefreplace',
+ newline='\n')
+
class XMLGenerator(handler.ContentHandler):
def __init__(self, out=None, encoding="iso-8859-1"):
- if out is None:
- import sys
- out = sys.stdout
handler.ContentHandler.__init__(self)
- self._out = out
+ out = _gettextwriter(out, encoding)
+ self._write = out.write
+ self._flush = out.flush
self._ns_contexts = [{}] # contains uri -> prefix dicts
self._current_context = self._ns_contexts[-1]
self._undeclared_ns_maps = []
self._encoding = encoding
- def _write(self, text):
- if isinstance(text, str):
- self._out.write(text)
- else:
- self._out.write(text.encode(self._encoding, _error_handling))
-
def _qname(self, name):
"""Builds a qualified name from a (ns_url, localname) pair"""
if name[0]:
@@ -120,9 +138,12 @@
# ContentHandler methods
def startDocument(self):
- self._write('<?xml version="1.0" encoding="%s"?>\n' %
+ self._write(u'<?xml version="1.0" encoding="%s"?>\n' %
self._encoding)
+ def endDocument(self):
+ self._flush()
+
def startPrefixMapping(self, prefix, uri):
self._ns_contexts.append(self._current_context.copy())
self._current_context[uri] = prefix
@@ -133,39 +154,39 @@
del self._ns_contexts[-1]
def startElement(self, name, attrs):
- self._write('<' + name)
+ self._write(u'<' + name)
for (name, value) in attrs.items():
- self._write(' %s=%s' % (name, quoteattr(value)))
- self._write('>')
+ self._write(u' %s=%s' % (name, quoteattr(value)))
+ self._write(u'>')
def endElement(self, name):
- self._write('</%s>' % name)
+ self._write(u'</%s>' % name)
def startElementNS(self, name, qname, attrs):
- self._write('<' + self._qname(name))
+ self._write(u'<' + self._qname(name))
for prefix, uri in self._undeclared_ns_maps:
if prefix:
- self._out.write(' xmlns:%s="%s"' % (prefix, uri))
+ self._write(u' xmlns:%s="%s"' % (prefix, uri))
else:
- self._out.write(' xmlns="%s"' % uri)
+ self._write(u' xmlns="%s"' % uri)
self._undeclared_ns_maps = []
for (name, value) in attrs.items():
- self._write(' %s=%s' % (self._qname(name), quoteattr(value)))
- self._write('>')
+ self._write(u' %s=%s' % (self._qname(name), quoteattr(value)))
+ self._write(u'>')
def endElementNS(self, name, qname):
- self._write('</%s>' % self._qname(name))
+ self._write(u'</%s>' % self._qname(name))
def characters(self, content):
- self._write(escape(content))
+ self._write(escape(unicode(content)))
def ignorableWhitespace(self, content):
- self._write(content)
+ self._write(unicode(content))
def processingInstruction(self, target, data):
- self._write('<?%s %s?>' % (target, data))
+ self._write(u'<?%s %s?>' % (target, data))
class XMLFilterBase(xmlreader.XMLReader):
@@ -293,14 +314,31 @@
source.setSystemId(f.name)
if source.getByteStream() is None:
- sysid = source.getSystemId()
- basehead = os.path.dirname(os.path.normpath(base))
- sysidfilename = os.path.join(basehead, sysid)
- if os.path.isfile(sysidfilename):
+ try:
+ sysid = source.getSystemId()
+ basehead = os.path.dirname(os.path.normpath(base))
+ encoding = sys.getfilesystemencoding()
+ if isinstance(sysid, unicode):
+ if not isinstance(basehead, unicode):
+ try:
+ basehead = basehead.decode(encoding)
+ except UnicodeDecodeError:
+ sysid = sysid.encode(encoding)
+ else:
+ if isinstance(basehead, unicode):
+ try:
+ sysid = sysid.decode(encoding)
+ except UnicodeDecodeError:
+ basehead = basehead.encode(encoding)
+ sysidfilename = os.path.join(basehead, sysid)
+ isfile = os.path.isfile(sysidfilename)
+ except UnicodeError:
+ isfile = False
+ if isfile:
source.setSystemId(sysidfilename)
f = open(sysidfilename, "rb")
else:
- source.setSystemId(urlparse.urljoin(base, sysid))
+ source.setSystemId(urlparse.urljoin(base, source.getSystemId()))
f = urllib.urlopen(source.getSystemId())
source.setByteStream(f)
diff --git a/lib-python/2.7/xml/sax/xmlreader.py b/lib-python/2.7/xml/sax/xmlreader.py
--- a/lib-python/2.7/xml/sax/xmlreader.py
+++ b/lib-python/2.7/xml/sax/xmlreader.py
@@ -68,7 +68,7 @@
SAX parsers are not required to provide localization for errors
and warnings; if they cannot support the requested locale,
- however, they must throw a SAX exception. Applications may
+ however, they must raise a SAX exception. Applications may
request a locale change in the middle of a parse."""
raise SAXNotSupportedException("Locale support not implemented")
diff --git a/lib-python/2.7/xmlrpclib.py b/lib-python/2.7/xmlrpclib.py
--- a/lib-python/2.7/xmlrpclib.py
+++ b/lib-python/2.7/xmlrpclib.py
@@ -945,7 +945,7 @@
class MultiCallIterator:
"""Iterates over the results of a multicall. Exceptions are
- thrown in response to xmlrpc faults."""
+ raised in response to xmlrpc faults."""
def __init__(self, results):
self.results = results
diff --git a/lib-python/2.7/zipfile.py b/lib-python/2.7/zipfile.py
--- a/lib-python/2.7/zipfile.py
+++ b/lib-python/2.7/zipfile.py
@@ -5,6 +5,7 @@
import binascii, cStringIO, stat
import io
import re
+import string
try:
import zlib # We may need its compression method
@@ -166,6 +167,8 @@
return endrec
data = fpin.read(sizeEndCentDir64Locator)
+ if len(data) != sizeEndCentDir64Locator:
+ return endrec
sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data)
if sig != stringEndArchive64Locator:
return endrec
@@ -176,6 +179,8 @@
# Assume no 'zip64 extensible data'
fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2)
data = fpin.read(sizeEndCentDir64)
+ if len(data) != sizeEndCentDir64:
+ return endrec
sig, sz, create_version, read_version, disk_num, disk_dir, \
dircount, dircount2, dirsize, diroffset = \
struct.unpack(structEndArchive64, data)
@@ -211,7 +216,9 @@
except IOError:
return None
data = fpin.read()
- if data[0:4] == stringEndArchive and data[-2:] == "\000\000":
+ if (len(data) == sizeEndCentDir and
+ data[0:4] == stringEndArchive and
+ data[-2:] == b"\000\000"):
# the signature is correct and there's no comment, unpack structure
endrec = struct.unpack(structEndArchive, data)
endrec=list(endrec)
@@ -235,6 +242,9 @@
if start >= 0:
# found the magic number; attempt to unpack and interpret
recData = data[start:start+sizeEndCentDir]
+ if len(recData) != sizeEndCentDir:
+ # Zip file is corrupted.
+ return None
endrec = list(struct.unpack(structEndArchive, recData))
commentSize = endrec[_ECD_COMMENT_SIZE] #as claimed by the zip file
comment = data[start+sizeEndCentDir:start+sizeEndCentDir+commentSize]
@@ -246,7 +256,7 @@
endrec)
# Unable to find a valid end of central directory structure
- return
+ return None
class ZipInfo (object):
@@ -316,7 +326,7 @@
# compress_size Size of the compressed file
# file_size Size of the uncompressed file
- def FileHeader(self):
+ def FileHeader(self, zip64=None):
"""Return the per-file header as a string."""
dt = self.date_time
dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
@@ -331,12 +341,17 @@
extra = self.extra
- if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT:
- # File is larger than what fits into a 4 byte integer,
- # fall back to the ZIP64 extension
+ if zip64 is None:
+ zip64 = file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT
+ if zip64:
fmt = '<HHQQ'
extra = extra + struct.pack(fmt,
1, struct.calcsize(fmt)-4, file_size, compress_size)
+ if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT:
+ if not zip64:
+ raise LargeZipFile("Filesize would require ZIP64 extensions")
+ # File is larger than what fits into a 4 byte integer,
+ # fall back to the ZIP64 extension
file_size = 0xffffffff
compress_size = 0xffffffff
self.extract_version = max(45, self.extract_version)
@@ -461,6 +476,28 @@
self._UpdateKeys(c)
return c
+
+compressor_names = {
+ 0: 'store',
+ 1: 'shrink',
+ 2: 'reduce',
+ 3: 'reduce',
+ 4: 'reduce',
+ 5: 'reduce',
+ 6: 'implode',
+ 7: 'tokenize',
+ 8: 'deflate',
+ 9: 'deflate64',
+ 10: 'implode',
+ 12: 'bzip2',
+ 14: 'lzma',
+ 18: 'terse',
+ 19: 'lz77',
+ 97: 'wavpack',
+ 98: 'ppmd',
+}
+
+
class ZipExtFile(io.BufferedIOBase):
"""File-like object for reading an archive member.
Is returned by ZipFile.open().
@@ -475,9 +512,11 @@
# Search for universal newlines or line chunks.
PATTERN = re.compile(r'^(?P<chunk>[^\r\n]+)|(?P<newline>\n|\r\n?)')
- def __init__(self, fileobj, mode, zipinfo, decrypter=None):
+ def __init__(self, fileobj, mode, zipinfo, decrypter=None,
+ close_fileobj=False):
self._fileobj = fileobj
self._decrypter = decrypter
+ self._close_fileobj = close_fileobj
self._compress_type = zipinfo.compress_type
self._compress_size = zipinfo.compress_size
@@ -485,6 +524,12 @@
if self._compress_type == ZIP_DEFLATED:
self._decompressor = zlib.decompressobj(-15)
+ elif self._compress_type != ZIP_STORED:
+ descr = compressor_names.get(self._compress_type)
+ if descr:
+ raise NotImplementedError("compression type %d (%s)" % (self._compress_type, descr))
+ else:
+ raise NotImplementedError("compression type %d" % (self._compress_type,))
self._unconsumed = ''
self._readbuffer = ''
@@ -649,9 +694,15 @@
self._offset += len(data)
return data
+ def close(self):
+ try :
+ if self._close_fileobj:
+ self._fileobj.close()
+ finally:
+ super(ZipExtFile, self).close()
-class ZipFile:
+class ZipFile(object):
""" Class with methods to open, read, write, close, list zip files.
z = ZipFile(file, mode="r", compression=ZIP_STORED, allowZip64=False)
@@ -690,7 +741,7 @@
self.compression = compression # Method of compression
self.mode = key = mode.replace('b', '')[0]
self.pwd = None
- self.comment = ''
+ self._comment = ''
# Check if we were passed a file-like object
if isinstance(file, basestring):
@@ -710,30 +761,34 @@
self.fp = file
self.filename = getattr(file, 'name', None)
- if key == 'r':
- self._GetContents()
- elif key == 'w':
- # set the modified flag so central directory gets written
- # even if no files are added to the archive
- self._didModify = True
- elif key == 'a':
- try:
- # See if file is a zip file
+ try:
+ if key == 'r':
self._RealGetContents()
- # seek to start of directory and overwrite
- self.fp.seek(self.start_dir, 0)
- except BadZipfile:
- # file is not a zip file, just append
- self.fp.seek(0, 2)
-
+ elif key == 'w':
# set the modified flag so central directory gets written
# even if no files are added to the archive
self._didModify = True
- else:
+ elif key == 'a':
+ try:
+ # See if file is a zip file
+ self._RealGetContents()
+ # seek to start of directory and overwrite
+ self.fp.seek(self.start_dir, 0)
+ except BadZipfile:
+ # file is not a zip file, just append
+ self.fp.seek(0, 2)
+
+ # set the modified flag so central directory gets written
+ # even if no files are added to the archive
+ self._didModify = True
+ else:
+ raise RuntimeError('Mode must be "r", "w" or "a"')
+ except:
+ fp = self.fp
+ self.fp = None
if not self._filePassed:
- self.fp.close()
- self.fp = None
- raise RuntimeError, 'Mode must be "r", "w" or "a"'
+ fp.close()
+ raise
def __enter__(self):
return self
@@ -741,17 +796,6 @@
def __exit__(self, type, value, traceback):
self.close()
- def _GetContents(self):
- """Read the directory, making sure we close the file if the format
- is bad."""
- try:
- self._RealGetContents()
- except BadZipfile:
- if not self._filePassed:
- self.fp.close()
- self.fp = None
- raise
-
def _RealGetContents(self):
"""Read in the table of contents for the ZIP file."""
fp = self.fp
@@ -765,7 +809,7 @@
print endrec
size_cd = endrec[_ECD_SIZE] # bytes in central directory
offset_cd = endrec[_ECD_OFFSET] # offset of central directory
- self.comment = endrec[_ECD_COMMENT] # archive comment
+ self._comment = endrec[_ECD_COMMENT] # archive comment
# "concat" is zero, unless zip was concatenated to another file
concat = endrec[_ECD_LOCATION] - size_cd - offset_cd
@@ -784,9 +828,11 @@
total = 0
while total < size_cd:
centdir = fp.read(sizeCentralDir)
- if centdir[0:4] != stringCentralDir:
- raise BadZipfile, "Bad magic number for central directory"
+ if len(centdir) != sizeCentralDir:
+ raise BadZipfile("Truncated central directory")
centdir = struct.unpack(structCentralDir, centdir)
+ if centdir[_CD_SIGNATURE] != stringCentralDir:
+ raise BadZipfile("Bad magic number for central directory")
if self.debug > 2:
print centdir
filename = fp.read(centdir[_CD_FILENAME_LENGTH])
@@ -845,9 +891,9 @@
try:
# Read by chunks, to avoid an OverflowError or a
# MemoryError with very large embedded files.
- f = self.open(zinfo.filename, "r")
- while f.read(chunk_size): # Check CRC-32
- pass
+ with self.open(zinfo.filename, "r") as f:
+ while f.read(chunk_size): # Check CRC-32
+ pass
except BadZipfile:
return zinfo.filename
@@ -864,6 +910,22 @@
"""Set default password for encrypted files."""
self.pwd = pwd
+ @property
+ def comment(self):
+ """The comment text associated with the ZIP file."""
+ return self._comment
+
+ @comment.setter
+ def comment(self, comment):
+ # check for valid comment length
+ if len(comment) >= ZIP_MAX_COMMENT:
+ if self.debug:
+ print('Archive comment is too long; truncating to %d bytes'
+ % ZIP_MAX_COMMENT)
+ comment = comment[:ZIP_MAX_COMMENT]
+ self._comment = comment
+ self._didModify = True
+
def read(self, name, pwd=None):
"""Return file bytes (as a string) for name."""
return self.open(name, "r", pwd).read()
@@ -880,62 +942,72 @@
# given a file object in the constructor
if self._filePassed:
zef_file = self.fp
+ should_close = False
else:
zef_file = open(self.filename, 'rb')
+ should_close = True
- # Make sure we have an info object
- if isinstance(name, ZipInfo):
- # 'name' is already an info object
- zinfo = name
- else:
- # Get info object for name
- zinfo = self.getinfo(name)
+ try:
+ # Make sure we have an info object
+ if isinstance(name, ZipInfo):
+ # 'name' is already an info object
+ zinfo = name
+ else:
+ # Get info object for name
+ zinfo = self.getinfo(name)
- zef_file.seek(zinfo.header_offset, 0)
+ zef_file.seek(zinfo.header_offset, 0)
- # Skip the file header:
- fheader = zef_file.read(sizeFileHeader)
- if fheader[0:4] != stringFileHeader:
- raise BadZipfile, "Bad magic number for file header"
+ # Skip the file header:
+ fheader = zef_file.read(sizeFileHeader)
+ if len(fheader) != sizeFileHeader:
+ raise BadZipfile("Truncated file header")
+ fheader = struct.unpack(structFileHeader, fheader)
+ if fheader[_FH_SIGNATURE] != stringFileHeader:
+ raise BadZipfile("Bad magic number for file header")
- fheader = struct.unpack(structFileHeader, fheader)
- fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
- if fheader[_FH_EXTRA_FIELD_LENGTH]:
- zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
+ fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
+ if fheader[_FH_EXTRA_FIELD_LENGTH]:
+ zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
- if fname != zinfo.orig_filename:
- raise BadZipfile, \
- 'File name in directory "%s" and header "%s" differ.' % (
- zinfo.orig_filename, fname)
+ if fname != zinfo.orig_filename:
+ raise BadZipfile, \
+ 'File name in directory "%s" and header "%s" differ.' % (
+ zinfo.orig_filename, fname)
- # check for encrypted flag & handle password
- is_encrypted = zinfo.flag_bits & 0x1
- zd = None
- if is_encrypted:
- if not pwd:
- pwd = self.pwd
- if not pwd:
- raise RuntimeError, "File %s is encrypted, " \
- "password required for extraction" % name
+ # check for encrypted flag & handle password
+ is_encrypted = zinfo.flag_bits & 0x1
+ zd = None
+ if is_encrypted:
+ if not pwd:
+ pwd = self.pwd
+ if not pwd:
+ raise RuntimeError, "File %s is encrypted, " \
+ "password required for extraction" % name
- zd = _ZipDecrypter(pwd)
- # The first 12 bytes in the cypher stream is an encryption header
- # used to strengthen the algorithm. The first 11 bytes are
- # completely random, while the 12th contains the MSB of the CRC,
- # or the MSB of the file time depending on the header type
- # and is used to check the correctness of the password.
- bytes = zef_file.read(12)
- h = map(zd, bytes[0:12])
- if zinfo.flag_bits & 0x8:
- # compare against the file type from extended local headers
- check_byte = (zinfo._raw_time >> 8) & 0xff
- else:
- # compare against the CRC otherwise
- check_byte = (zinfo.CRC >> 24) & 0xff
- if ord(h[11]) != check_byte:
- raise RuntimeError("Bad password for file", name)
+ zd = _ZipDecrypter(pwd)
+ # The first 12 bytes in the cypher stream is an encryption header
+ # used to strengthen the algorithm. The first 11 bytes are
+ # completely random, while the 12th contains the MSB of the CRC,
+ # or the MSB of the file time depending on the header type
+ # and is used to check the correctness of the password.
+ bytes = zef_file.read(12)
+ h = map(zd, bytes[0:12])
+ if zinfo.flag_bits & 0x8:
+ # compare against the file type from extended local headers
+ check_byte = (zinfo._raw_time >> 8) & 0xff
+ else:
+ # compare against the CRC otherwise
+ check_byte = (zinfo.CRC >> 24) & 0xff
+ if ord(h[11]) != check_byte:
+ raise RuntimeError("Bad password for file", name)
- return ZipExtFile(zef_file, mode, zinfo, zd)
+ return ZipExtFile(zef_file, mode, zinfo, zd,
+ close_fileobj=should_close)
+ except:
+ if should_close:
+ zef_file.close()
+ raise
def extract(self, member, path=None, pwd=None):
"""Extract a member from the archive to the current working directory,
@@ -969,17 +1041,25 @@
"""
# build the destination pathname, replacing
# forward slashes to platform specific separators.
- # Strip trailing path separator, unless it represents the root.
- if (targetpath[-1:] in (os.path.sep, os.path.altsep)
- and len(os.path.splitdrive(targetpath)[1]) > 1):
- targetpath = targetpath[:-1]
+ arcname = member.filename.replace('/', os.path.sep)
- # don't include leading "/" from file name if present
- if member.filename[0] == '/':
- targetpath = os.path.join(targetpath, member.filename[1:])
- else:
- targetpath = os.path.join(targetpath, member.filename)
+ if os.path.altsep:
+ arcname = arcname.replace(os.path.altsep, os.path.sep)
+ # interpret absolute pathname as relative, remove drive letter or
+ # UNC path, redundant separators, "." and ".." components.
+ arcname = os.path.splitdrive(arcname)[1]
+ arcname = os.path.sep.join(x for x in arcname.split(os.path.sep)
+ if x not in ('', os.path.curdir, os.path.pardir))
+ if os.path.sep == '\\':
+ # filter illegal characters on Windows
+ illegal = ':<>|"?*'
+ table = string.maketrans(illegal, '_' * len(illegal))
+ arcname = arcname.translate(table)
+ # remove trailing dots
+ arcname = (x.rstrip('.') for x in arcname.split(os.path.sep))
+ arcname = os.path.sep.join(x for x in arcname if x)
+ targetpath = os.path.join(targetpath, arcname)
targetpath = os.path.normpath(targetpath)
# Create all upper directories if necessary.
@@ -992,11 +1072,9 @@
os.mkdir(targetpath)
return targetpath
- source = self.open(member, pwd=pwd)
- target = file(targetpath, "wb")
- shutil.copyfileobj(source, target)
- source.close()
- target.close()
+ with self.open(member, pwd=pwd) as source, \
+ file(targetpath, "wb") as target:
+ shutil.copyfileobj(source, target)
return targetpath
@@ -1062,20 +1140,23 @@
zinfo.CRC = 0
self.filelist.append(zinfo)
self.NameToInfo[zinfo.filename] = zinfo
- self.fp.write(zinfo.FileHeader())
+ self.fp.write(zinfo.FileHeader(False))
return
with open(filename, "rb") as fp:
# Must overwrite CRC and sizes with correct data later
zinfo.CRC = CRC = 0
zinfo.compress_size = compress_size = 0
- zinfo.file_size = file_size = 0
- self.fp.write(zinfo.FileHeader())
+ # Compressed size can be larger than uncompressed size
+ zip64 = self._allowZip64 and \
+ zinfo.file_size * 1.05 > ZIP64_LIMIT
+ self.fp.write(zinfo.FileHeader(zip64))
if zinfo.compress_type == ZIP_DEFLATED:
cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
zlib.DEFLATED, -15)
else:
cmpr = None
+ file_size = 0
while 1:
buf = fp.read(1024 * 8)
if not buf:
@@ -1095,11 +1176,16 @@
zinfo.compress_size = file_size
zinfo.CRC = CRC
zinfo.file_size = file_size
- # Seek backwards and write CRC and file sizes
+ if not zip64 and self._allowZip64:
+ if file_size > ZIP64_LIMIT:
+ raise RuntimeError('File size has increased during compressing')
+ if compress_size > ZIP64_LIMIT:
+ raise RuntimeError('Compressed size larger than uncompressed size')
+ # Seek backwards and write file header (which will now include
+ # correct CRC and file sizes)
position = self.fp.tell() # Preserve current position in file
- self.fp.seek(zinfo.header_offset + 14, 0)
- self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size,
- zinfo.file_size))
+ self.fp.seek(zinfo.header_offset, 0)
+ self.fp.write(zinfo.FileHeader(zip64))
self.fp.seek(position, 0)
self.filelist.append(zinfo)
self.NameToInfo[zinfo.filename] = zinfo
@@ -1136,14 +1222,18 @@
zinfo.compress_size = len(bytes) # Compressed size
else:
zinfo.compress_size = zinfo.file_size
- zinfo.header_offset = self.fp.tell() # Start of header bytes
- self.fp.write(zinfo.FileHeader())
+ zip64 = zinfo.file_size > ZIP64_LIMIT or \
+ zinfo.compress_size > ZIP64_LIMIT
+ if zip64 and not self._allowZip64:
+ raise LargeZipFile("Filesize would require ZIP64 extensions")
+ self.fp.write(zinfo.FileHeader(zip64))
self.fp.write(bytes)
- self.fp.flush()
if zinfo.flag_bits & 0x08:
# Write CRC and file sizes after the file data
- self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size,
+ fmt = '<LQQ' if zip64 else '<LLL'
+ self.fp.write(struct.pack(fmt, zinfo.CRC, zinfo.compress_size,
zinfo.file_size))
+ self.fp.flush()
self.filelist.append(zinfo)
self.NameToInfo[zinfo.filename] = zinfo
@@ -1157,109 +1247,104 @@
if self.fp is None:
return
- if self.mode in ("w", "a") and self._didModify: # write ending records
- count = 0
- pos1 = self.fp.tell()
- for zinfo in self.filelist: # write central directory
- count = count + 1
- dt = zinfo.date_time
- dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
- dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
- extra = []
- if zinfo.file_size > ZIP64_LIMIT \
- or zinfo.compress_size > ZIP64_LIMIT:
- extra.append(zinfo.file_size)
- extra.append(zinfo.compress_size)
- file_size = 0xffffffff
- compress_size = 0xffffffff
- else:
- file_size = zinfo.file_size
- compress_size = zinfo.compress_size
+ try:
+ if self.mode in ("w", "a") and self._didModify: # write ending records
+ count = 0
+ pos1 = self.fp.tell()
+ for zinfo in self.filelist: # write central directory
+ count = count + 1
+ dt = zinfo.date_time
+ dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
+ dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
+ extra = []
+ if zinfo.file_size > ZIP64_LIMIT \
+ or zinfo.compress_size > ZIP64_LIMIT:
+ extra.append(zinfo.file_size)
+ extra.append(zinfo.compress_size)
+ file_size = 0xffffffff
+ compress_size = 0xffffffff
+ else:
+ file_size = zinfo.file_size
+ compress_size = zinfo.compress_size
- if zinfo.header_offset > ZIP64_LIMIT:
- extra.append(zinfo.header_offset)
- header_offset = 0xffffffffL
- else:
- header_offset = zinfo.header_offset
+ if zinfo.header_offset > ZIP64_LIMIT:
+ extra.append(zinfo.header_offset)
+ header_offset = 0xffffffffL
+ else:
+ header_offset = zinfo.header_offset
- extra_data = zinfo.extra
- if extra:
- # Append a ZIP64 field to the extra's
- extra_data = struct.pack(
- '<HH' + 'Q'*len(extra),
- 1, 8*len(extra), *extra) + extra_data
+ extra_data = zinfo.extra
+ if extra:
+ # Append a ZIP64 field to the extra's
+ extra_data = struct.pack(
+ '<HH' + 'Q'*len(extra),
+ 1, 8*len(extra), *extra) + extra_data
- extract_version = max(45, zinfo.extract_version)
- create_version = max(45, zinfo.create_version)
- else:
- extract_version = zinfo.extract_version
- create_version = zinfo.create_version
+ extract_version = max(45, zinfo.extract_version)
+ create_version = max(45, zinfo.create_version)
+ else:
+ extract_version = zinfo.extract_version
+ create_version = zinfo.create_version
- try:
- filename, flag_bits = zinfo._encodeFilenameFlags()
- centdir = struct.pack(structCentralDir,
- stringCentralDir, create_version,
- zinfo.create_system, extract_version, zinfo.reserved,
- flag_bits, zinfo.compress_type, dostime, dosdate,
- zinfo.CRC, compress_size, file_size,
- len(filename), len(extra_data), len(zinfo.comment),
- 0, zinfo.internal_attr, zinfo.external_attr,
- header_offset)
- except DeprecationWarning:
- print >>sys.stderr, (structCentralDir,
- stringCentralDir, create_version,
- zinfo.create_system, extract_version, zinfo.reserved,
- zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
- zinfo.CRC, compress_size, file_size,
- len(zinfo.filename), len(extra_data), len(zinfo.comment),
- 0, zinfo.internal_attr, zinfo.external_attr,
- header_offset)
- raise
- self.fp.write(centdir)
- self.fp.write(filename)
- self.fp.write(extra_data)
- self.fp.write(zinfo.comment)
+ try:
+ filename, flag_bits = zinfo._encodeFilenameFlags()
+ centdir = struct.pack(structCentralDir,
+ stringCentralDir, create_version,
+ zinfo.create_system, extract_version, zinfo.reserved,
+ flag_bits, zinfo.compress_type, dostime, dosdate,
+ zinfo.CRC, compress_size, file_size,
+ len(filename), len(extra_data), len(zinfo.comment),
+ 0, zinfo.internal_attr, zinfo.external_attr,
+ header_offset)
+ except DeprecationWarning:
+ print >>sys.stderr, (structCentralDir,
+ stringCentralDir, create_version,
+ zinfo.create_system, extract_version, zinfo.reserved,
+ zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
+ zinfo.CRC, compress_size, file_size,
+ len(zinfo.filename), len(extra_data), len(zinfo.comment),
+ 0, zinfo.internal_attr, zinfo.external_attr,
+ header_offset)
+ raise
+ self.fp.write(centdir)
+ self.fp.write(filename)
+ self.fp.write(extra_data)
+ self.fp.write(zinfo.comment)
- pos2 = self.fp.tell()
- # Write end-of-zip-archive record
- centDirCount = count
- centDirSize = pos2 - pos1
- centDirOffset = pos1
- if (centDirCount >= ZIP_FILECOUNT_LIMIT or
- centDirOffset > ZIP64_LIMIT or
- centDirSize > ZIP64_LIMIT):
- # Need to write the ZIP64 end-of-archive records
- zip64endrec = struct.pack(
- structEndArchive64, stringEndArchive64,
- 44, 45, 45, 0, 0, centDirCount, centDirCount,
- centDirSize, centDirOffset)
- self.fp.write(zip64endrec)
+ pos2 = self.fp.tell()
+ # Write end-of-zip-archive record
+ centDirCount = count
+ centDirSize = pos2 - pos1
+ centDirOffset = pos1
+ if (centDirCount >= ZIP_FILECOUNT_LIMIT or
+ centDirOffset > ZIP64_LIMIT or
+ centDirSize > ZIP64_LIMIT):
+ # Need to write the ZIP64 end-of-archive records
+ zip64endrec = struct.pack(
+ structEndArchive64, stringEndArchive64,
+ 44, 45, 45, 0, 0, centDirCount, centDirCount,
+ centDirSize, centDirOffset)
+ self.fp.write(zip64endrec)
- zip64locrec = struct.pack(
- structEndArchive64Locator,
- stringEndArchive64Locator, 0, pos2, 1)
- self.fp.write(zip64locrec)
- centDirCount = min(centDirCount, 0xFFFF)
- centDirSize = min(centDirSize, 0xFFFFFFFF)
- centDirOffset = min(centDirOffset, 0xFFFFFFFF)
+ zip64locrec = struct.pack(
+ structEndArchive64Locator,
+ stringEndArchive64Locator, 0, pos2, 1)
+ self.fp.write(zip64locrec)
+ centDirCount = min(centDirCount, 0xFFFF)
+ centDirSize = min(centDirSize, 0xFFFFFFFF)
+ centDirOffset = min(centDirOffset, 0xFFFFFFFF)
- # check for valid comment length
- if len(self.comment) >= ZIP_MAX_COMMENT:
- if self.debug > 0:
- msg = 'Archive comment is too long; truncating to %d bytes' \
- % ZIP_MAX_COMMENT
- self.comment = self.comment[:ZIP_MAX_COMMENT]
-
- endrec = struct.pack(structEndArchive, stringEndArchive,
- 0, 0, centDirCount, centDirCount,
- centDirSize, centDirOffset, len(self.comment))
- self.fp.write(endrec)
- self.fp.write(self.comment)
- self.fp.flush()
-
- if not self._filePassed:
- self.fp.close()
- self.fp = None
+ endrec = struct.pack(structEndArchive, stringEndArchive,
+ 0, 0, centDirCount, centDirCount,
+ centDirSize, centDirOffset, len(self._comment))
+ self.fp.write(endrec)
+ self.fp.write(self._comment)
+ self.fp.flush()
+ finally:
+ fp = self.fp
+ self.fp = None
+ if not self._filePassed:
+ fp.close()
class PyZipFile(ZipFile):
@@ -1381,16 +1466,15 @@
if len(args) != 2:
print USAGE
sys.exit(1)
- zf = ZipFile(args[1], 'r')
- zf.printdir()
- zf.close()
+ with ZipFile(args[1], 'r') as zf:
+ zf.printdir()
elif args[0] == '-t':
if len(args) != 2:
print USAGE
sys.exit(1)
- zf = ZipFile(args[1], 'r')
- badfile = zf.testzip()
+ with ZipFile(args[1], 'r') as zf:
+ badfile = zf.testzip()
if badfile:
print("The following enclosed file is corrupted: {!r}".format(badfile))
print "Done testing"
@@ -1400,20 +1484,19 @@
print USAGE
sys.exit(1)
- zf = ZipFile(args[1], 'r')
- out = args[2]
- for path in zf.namelist():
- if path.startswith('./'):
- tgt = os.path.join(out, path[2:])
- else:
- tgt = os.path.join(out, path)
+ with ZipFile(args[1], 'r') as zf:
+ out = args[2]
+ for path in zf.namelist():
+ if path.startswith('./'):
+ tgt = os.path.join(out, path[2:])
+ else:
+ tgt = os.path.join(out, path)
- tgtdir = os.path.dirname(tgt)
- if not os.path.exists(tgtdir):
- os.makedirs(tgtdir)
- with open(tgt, 'wb') as fp:
- fp.write(zf.read(path))
- zf.close()
+ tgtdir = os.path.dirname(tgt)
+ if not os.path.exists(tgtdir):
+ os.makedirs(tgtdir)
+ with open(tgt, 'wb') as fp:
+ fp.write(zf.read(path))
elif args[0] == '-c':
if len(args) < 3:
@@ -1429,11 +1512,9 @@
os.path.join(path, nm), os.path.join(zippath, nm))
# else: ignore
- zf = ZipFile(args[1], 'w', allowZip64=True)
- for src in args[2:]:
- addToZip(zf, src, os.path.basename(src))
-
- zf.close()
+ with ZipFile(args[1], 'w', allowZip64=True) as zf:
+ for src in args[2:]:
+ addToZip(zf, src, os.path.basename(src))
if __name__ == "__main__":
main()
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list