[pypy-commit] pypy py3.5-newtext: hg merge py3.5

arigo pypy.commits at gmail.com
Tue Dec 20 07:00:10 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5-newtext
Changeset: r89198:10264e569a8c
Date: 2016-12-20 11:43 +0100
http://bitbucket.org/pypy/pypy/changeset/10264e569a8c/

Log:	hg merge py3.5

diff too long, truncating to 2000 out of 26231 lines

diff --git a/lib-python/2.7/SimpleXMLRPCServer.py b/lib-python/2.7/SimpleXMLRPCServer.py
--- a/lib-python/2.7/SimpleXMLRPCServer.py
+++ b/lib-python/2.7/SimpleXMLRPCServer.py
@@ -188,7 +188,7 @@
         are considered private and will not be called by
         SimpleXMLRPCServer.
 
-        If a registered function matches a XML-RPC request, then it
+        If a registered function matches an XML-RPC request, then it
         will be called instead of the registered instance.
 
         If the optional allow_dotted_names argument is true and the
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
@@ -274,7 +274,7 @@
     Even though IOBase does not declare read, readinto, or write because
     their signatures will vary, implementations and clients should
     consider those methods part of the interface. Also, implementations
-    may raise a IOError when operations they do not support are called.
+    may raise an IOError when operations they do not support are called.
 
     The basic type used for binary data read from or written to a file is
     the bytes type. Method arguments may also be bytearray or memoryview of
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
@@ -174,22 +174,23 @@
         Like itermonthdates(), but will yield (day number, weekday number)
         tuples. For days outside the specified month the day number is 0.
         """
-        for date in self.itermonthdates(year, month):
-            if date.month != month:
-                yield (0, date.weekday())
-            else:
-                yield (date.day, date.weekday())
+        for i, d in enumerate(self.itermonthdays(year, month), self.firstweekday):
+            yield d, i % 7
 
     def itermonthdays(self, year, month):
         """
         Like itermonthdates(), but will yield day numbers. For days outside
         the specified month the day number is 0.
         """
-        for date in self.itermonthdates(year, month):
-            if date.month != month:
-                yield 0
-            else:
-                yield date.day
+        day1, ndays = monthrange(year, month)
+        days_before = (day1 - self.firstweekday) % 7
+        for _ in range(days_before):
+            yield 0
+        for d in range(1, ndays + 1):
+            yield d
+        days_after = (self.firstweekday - day1 - ndays) % 7
+        for _ in range(days_after):
+            yield 0
 
     def monthdatescalendar(self, year, month):
         """
diff --git a/lib-python/2.7/chunk.py b/lib-python/2.7/chunk.py
--- a/lib-python/2.7/chunk.py
+++ b/lib-python/2.7/chunk.py
@@ -21,7 +21,7 @@
 usage of the Chunk class defined here is to instantiate an instance at
 the start of each chunk and read from the instance until it reaches
 the end, after which a new instance can be instantiated.  At the end
-of the file, creating a new instance will fail with a EOFError
+of the file, creating a new instance will fail with an EOFError
 exception.
 
 Usage:
diff --git a/lib-python/2.7/codecs.py b/lib-python/2.7/codecs.py
--- a/lib-python/2.7/codecs.py
+++ b/lib-python/2.7/codecs.py
@@ -252,7 +252,7 @@
     """
     def __init__(self, errors='strict'):
         """
-        Creates a IncrementalDecoder instance.
+        Creates an IncrementalDecoder instance.
 
         The IncrementalDecoder may use different error handling schemes by
         providing the errors keyword argument. See the module docstring
@@ -1012,7 +1012,7 @@
     """
     Encoding iterator.
 
-    Encodes the input strings from the iterator using a IncrementalEncoder.
+    Encodes the input strings from the iterator using an IncrementalEncoder.
 
     errors and kwargs are passed through to the IncrementalEncoder
     constructor.
@@ -1030,7 +1030,7 @@
     """
     Decoding iterator.
 
-    Decodes the input strings from the iterator using a IncrementalDecoder.
+    Decodes the input strings from the iterator using an IncrementalDecoder.
 
     errors and kwargs are passed through to the IncrementalDecoder
     constructor.
diff --git a/lib-python/2.7/cookielib.py b/lib-python/2.7/cookielib.py
--- a/lib-python/2.7/cookielib.py
+++ b/lib-python/2.7/cookielib.py
@@ -113,7 +113,7 @@
     """
     if t is None: t = time.time()
     year, mon, mday, hour, min, sec, wday = time.gmtime(t)[:7]
-    return "%s %02d-%s-%04d %02d:%02d:%02d GMT" % (
+    return "%s, %02d-%s-%04d %02d:%02d:%02d GMT" % (
         DAYS[wday], mday, MONTHS[mon-1], year, hour, min, sec)
 
 
diff --git a/lib-python/2.7/ctypes/test/test_callbacks.py b/lib-python/2.7/ctypes/test/test_callbacks.py
--- a/lib-python/2.7/ctypes/test/test_callbacks.py
+++ b/lib-python/2.7/ctypes/test/test_callbacks.py
@@ -1,3 +1,4 @@
+import functools
 import unittest
 from ctypes import *
 from ctypes.test import need_symbol
@@ -248,6 +249,40 @@
         self.assertEqual(result,
                          callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5))
 
+    def test_callback_large_struct(self):
+        class Check: pass
+
+        class X(Structure):
+            _fields_ = [
+                ('first', c_ulong),
+                ('second', c_ulong),
+                ('third', c_ulong),
+            ]
+
+        def callback(check, s):
+            check.first = s.first
+            check.second = s.second
+            check.third = s.third
+
+        check = Check()
+        s = X()
+        s.first = 0xdeadbeef
+        s.second = 0xcafebabe
+        s.third = 0x0bad1dea
+
+        CALLBACK = CFUNCTYPE(None, X)
+        dll = CDLL(_ctypes_test.__file__)
+        func = dll._testfunc_cbk_large_struct
+        func.argtypes = (X, CALLBACK)
+        func.restype = None
+        # the function just calls the callback with the passed structure
+        func(s, CALLBACK(functools.partial(callback, check)))
+        self.assertEqual(check.first, s.first)
+        self.assertEqual(check.second, s.second)
+        self.assertEqual(check.third, s.third)
+        self.assertEqual(check.first, 0xdeadbeef)
+        self.assertEqual(check.second, 0xcafebabe)
+        self.assertEqual(check.third, 0x0bad1dea)
 
 ################################################################
 
diff --git a/lib-python/2.7/ctypes/test/test_find.py b/lib-python/2.7/ctypes/test/test_find.py
--- a/lib-python/2.7/ctypes/test/test_find.py
+++ b/lib-python/2.7/ctypes/test/test_find.py
@@ -1,6 +1,7 @@
 import unittest
-import os
+import os.path
 import sys
+from test import test_support
 from ctypes import *
 from ctypes.util import find_library
 from ctypes.test import is_resource_enabled
@@ -65,28 +66,10 @@
         if self.gle:
             self.gle.gleGetJoinStyle
 
-# On platforms where the default shared library suffix is '.so',
-# at least some libraries can be loaded as attributes of the cdll
-# object, since ctypes now tries loading the lib again
-# with '.so' appended of the first try fails.
-#
-# Won't work for libc, unfortunately.  OTOH, it isn't
-# needed for libc since this is already mapped into the current
-# process (?)
-#
-# On MAC OSX, it won't work either, because dlopen() needs a full path,
-# and the default suffix is either none or '.dylib'.
- at unittest.skip('test disabled')
- at unittest.skipUnless(os.name=="posix" and sys.platform != "darwin",
-                     'test not suitable for this platform')
-class LoadLibs(unittest.TestCase):
-    def test_libm(self):
-        import math
-        libm = cdll.libm
-        sqrt = libm.sqrt
-        sqrt.argtypes = (c_double,)
-        sqrt.restype = c_double
-        self.assertEqual(sqrt(2), math.sqrt(2))
+    def test_shell_injection(self):
+        result = find_library('; echo Hello shell > ' + test_support.TESTFN)
+        self.assertFalse(os.path.lexists(test_support.TESTFN))
+        self.assertIsNone(result)
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/lib-python/2.7/ctypes/test/test_frombuffer.py b/lib-python/2.7/ctypes/test/test_frombuffer.py
--- a/lib-python/2.7/ctypes/test/test_frombuffer.py
+++ b/lib-python/2.7/ctypes/test/test_frombuffer.py
@@ -77,5 +77,13 @@
         self.assertRaises(ValueError,
                           (c_int * 1).from_buffer_copy, a, 16 * sizeof(c_int))
 
+    def test_abstract(self):
+        self.assertRaises(TypeError, Array.from_buffer, bytearray(10))
+        self.assertRaises(TypeError, Structure.from_buffer, bytearray(10))
+        self.assertRaises(TypeError, Union.from_buffer, bytearray(10))
+        self.assertRaises(TypeError, Array.from_buffer_copy, b"123")
+        self.assertRaises(TypeError, Structure.from_buffer_copy, b"123")
+        self.assertRaises(TypeError, Union.from_buffer_copy, b"123")
+
 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
@@ -77,7 +77,7 @@
             self.assertEqual(t(v).value, truth(v))
 
     def test_typeerror(self):
-        # Only numbers are allowed in the contructor,
+        # Only numbers are allowed in the constructor,
         # otherwise TypeError is raised
         for t in signed_types + unsigned_types + float_types:
             self.assertRaises(TypeError, t, "")
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
@@ -106,7 +106,7 @@
         self.assertEqual(alignment(XX), alignment(X))
         self.assertEqual(sizeof(XX), calcsize("3s 3s 0s"))
 
-    def test_emtpy(self):
+    def test_empty(self):
         # I had problems with these
         #
         # Although these are pathological cases: Empty Structures!
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
@@ -1,4 +1,6 @@
-import sys, os
+import os
+import subprocess
+import sys
 
 # find_library(name) returns the pathname of a library, or None.
 if os.name == "nt":
@@ -87,25 +89,28 @@
 
     def _findLib_gcc(name):
         import tempfile
+        # Run GCC's linker with the -t (aka --trace) option and examine the
+        # library name it prints out. The GCC command will fail because we
+        # haven't supplied a proper program with main(), but that does not
+        # matter.
         expr = r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name)
-        fdout, ccout = tempfile.mkstemp()
-        os.close(fdout)
-        cmd = 'if type gcc >/dev/null 2>&1; then CC=gcc; elif type cc >/dev/null 2>&1; then CC=cc;else exit 10; fi;' \
-              'LANG=C LC_ALL=C $CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name
+        cmd = 'if type gcc >/dev/null 2>&1; then CC=gcc; elif type cc >/dev/null 2>&1; then CC=cc;else exit; fi;' \
+              'LANG=C LC_ALL=C $CC -Wl,-t -o "$2" 2>&1 -l"$1"'
+
+        temp = tempfile.NamedTemporaryFile()
         try:
-            f = os.popen(cmd)
-            try:
-                trace = f.read()
-            finally:
-                rv = f.close()
+            proc = subprocess.Popen((cmd, '_findLib_gcc', name, temp.name),
+                                    shell=True,
+                                    stdout=subprocess.PIPE)
+            [trace, _] = proc.communicate()
         finally:
             try:
-                os.unlink(ccout)
+                temp.close()
             except OSError, e:
+                # ENOENT is raised if the file was already removed, which is
+                # the normal behaviour of GCC if linking fails
                 if e.errno != errno.ENOENT:
                     raise
-        if rv == 10:
-            raise OSError, 'gcc or cc command not found'
         res = re.search(expr, trace)
         if not res:
             return None
@@ -117,13 +122,17 @@
         def _get_soname(f):
             if not f:
                 return None
-            cmd = "/usr/ccs/bin/dump -Lpv 2>/dev/null " + f
-            f = os.popen(cmd)
+
+            null = open(os.devnull, "wb")
             try:
-                data = f.read()
-            finally:
-                f.close()
-            res = re.search(r'\[.*\]\sSONAME\s+([^\s]+)', data)
+                with null:
+                    proc = subprocess.Popen(("/usr/ccs/bin/dump", "-Lpv", f),
+                                            stdout=subprocess.PIPE,
+                                            stderr=null)
+            except OSError:  # E.g. command not found
+                return None
+            [data, _] = proc.communicate()
+            res = re.search(br'\[.*\]\sSONAME\s+([^\s]+)', data)
             if not res:
                 return None
             return res.group(1)
@@ -132,16 +141,12 @@
             # assuming GNU binutils / ELF
             if not f:
                 return None
-            cmd = 'if ! type objdump >/dev/null 2>&1; then exit 10; fi;' \
-                  "objdump -p -j .dynamic 2>/dev/null " + f
-            f = os.popen(cmd)
-            try:
-                dump = f.read()
-            finally:
-                rv = f.close()
-            if rv == 10:
-                raise OSError, 'objdump command not found'
-            res = re.search(r'\sSONAME\s+([^\s]+)', dump)
+            cmd = 'if ! type objdump >/dev/null 2>&1; then exit; fi;' \
+                  'objdump -p -j .dynamic 2>/dev/null "$1"'
+            proc = subprocess.Popen((cmd, '_get_soname', f), shell=True,
+                                    stdout=subprocess.PIPE)
+            [dump, _] = proc.communicate()
+            res = re.search(br'\sSONAME\s+([^\s]+)', dump)
             if not res:
                 return None
             return res.group(1)
@@ -152,23 +157,30 @@
 
         def _num_version(libname):
             # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ]
-            parts = libname.split(".")
+            parts = libname.split(b".")
             nums = []
             try:
                 while parts:
                     nums.insert(0, int(parts.pop()))
             except ValueError:
                 pass
-            return nums or [ sys.maxint ]
+            return nums or [sys.maxint]
 
         def find_library(name):
             ename = re.escape(name)
             expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename)
-            f = os.popen('/sbin/ldconfig -r 2>/dev/null')
+
+            null = open(os.devnull, 'wb')
             try:
-                data = f.read()
-            finally:
-                f.close()
+                with null:
+                    proc = subprocess.Popen(('/sbin/ldconfig', '-r'),
+                                            stdout=subprocess.PIPE,
+                                            stderr=null)
+            except OSError:  # E.g. command not found
+                data = b''
+            else:
+                [data, _] = proc.communicate()
+
             res = re.findall(expr, data)
             if not res:
                 return _get_soname(_findLib_gcc(name))
@@ -181,16 +193,32 @@
             if not os.path.exists('/usr/bin/crle'):
                 return None
 
+            env = dict(os.environ)
+            env['LC_ALL'] = 'C'
+
             if is64:
-                cmd = 'env LC_ALL=C /usr/bin/crle -64 2>/dev/null'
+                args = ('/usr/bin/crle', '-64')
             else:
-                cmd = 'env LC_ALL=C /usr/bin/crle 2>/dev/null'
+                args = ('/usr/bin/crle',)
 
             paths = None
-            for line in os.popen(cmd).readlines():
-                line = line.strip()
-                if line.startswith('Default Library Path (ELF):'):
-                    paths = line.split()[4]
+            null = open(os.devnull, 'wb')
+            try:
+                with null:
+                    proc = subprocess.Popen(args,
+                                            stdout=subprocess.PIPE,
+                                            stderr=null,
+                                            env=env)
+            except OSError:  # E.g. bad executable
+                return None
+            try:
+                for line in proc.stdout:
+                    line = line.strip()
+                    if line.startswith(b'Default Library Path (ELF):'):
+                        paths = line.split()[4]
+            finally:
+                proc.stdout.close()
+                proc.wait()
 
             if not paths:
                 return None
@@ -224,11 +252,20 @@
 
             # XXX assuming GLIBC's ldconfig (with option -p)
             expr = r'\s+(lib%s\.[^\s]+)\s+\(%s' % (re.escape(name), abi_type)
-            f = os.popen('LC_ALL=C LANG=C /sbin/ldconfig -p 2>/dev/null')
+
+            env = dict(os.environ)
+            env['LC_ALL'] = 'C'
+            env['LANG'] = 'C'
+            null = open(os.devnull, 'wb')
             try:
-                data = f.read()
-            finally:
-                f.close()
+                with null:
+                    p = subprocess.Popen(['/sbin/ldconfig', '-p'],
+                                          stderr=null,
+                                          stdout=subprocess.PIPE,
+                                          env=env)
+            except OSError:  # E.g. command not found
+                return None
+            [data, _] = p.communicate()
             res = re.search(expr, data)
             if not res:
                 return None
diff --git a/lib-python/2.7/curses/ascii.py b/lib-python/2.7/curses/ascii.py
--- a/lib-python/2.7/curses/ascii.py
+++ b/lib-python/2.7/curses/ascii.py
@@ -54,13 +54,13 @@
 def isalnum(c): return isalpha(c) or isdigit(c)
 def isalpha(c): return isupper(c) or islower(c)
 def isascii(c): return _ctoi(c) <= 127          # ?
-def isblank(c): return _ctoi(c) in (8,32)
-def iscntrl(c): return _ctoi(c) <= 31
+def isblank(c): return _ctoi(c) in (9, 32)
+def iscntrl(c): return _ctoi(c) <= 31 or _ctoi(c) == 127
 def isdigit(c): return _ctoi(c) >= 48 and _ctoi(c) <= 57
 def isgraph(c): return _ctoi(c) >= 33 and _ctoi(c) <= 126
 def islower(c): return _ctoi(c) >= 97 and _ctoi(c) <= 122
 def isprint(c): return _ctoi(c) >= 32 and _ctoi(c) <= 126
-def ispunct(c): return _ctoi(c) != 32 and not isalnum(c)
+def ispunct(c): return isgraph(c) and not isalnum(c)
 def isspace(c): return _ctoi(c) in (9, 10, 11, 12, 13, 32)
 def isupper(c): return _ctoi(c) >= 65 and _ctoi(c) <= 90
 def isxdigit(c): return isdigit(c) or \
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
@@ -1048,12 +1048,11 @@
         return sign + intpart + fracpart + exp
 
     def to_eng_string(self, context=None):
-        """Convert to engineering-type string.
-
-        Engineering notation has an exponent which is a multiple of 3, so there
-        are up to 3 digits left of the decimal place.
-
-        Same rules for when in exponential and when as a value as in __str__.
+        """Convert to a string, using engineering notation if an exponent is needed.
+
+        Engineering notation has an exponent which is a multiple of 3.  This
+        can leave up to 3 digits to the left of the decimal place and may
+        require the addition of either one or two trailing zeros.
         """
         return self.__str__(eng=True, context=context)
 
@@ -5339,9 +5338,29 @@
             return r
 
     def to_eng_string(self, a):
-        """Converts a number to a string, using scientific notation.
+        """Convert to a string, using engineering notation if an exponent is needed.
+
+        Engineering notation has an exponent which is a multiple of 3.  This
+        can leave up to 3 digits to the left of the decimal place and may
+        require the addition of either one or two trailing zeros.
 
         The operation is not affected by the context.
+
+        >>> ExtendedContext.to_eng_string(Decimal('123E+1'))
+        '1.23E+3'
+        >>> ExtendedContext.to_eng_string(Decimal('123E+3'))
+        '123E+3'
+        >>> ExtendedContext.to_eng_string(Decimal('123E-10'))
+        '12.3E-9'
+        >>> ExtendedContext.to_eng_string(Decimal('-123E-12'))
+        '-123E-12'
+        >>> ExtendedContext.to_eng_string(Decimal('7E-7'))
+        '700E-9'
+        >>> ExtendedContext.to_eng_string(Decimal('7E+1'))
+        '70'
+        >>> ExtendedContext.to_eng_string(Decimal('0E+1'))
+        '0.00E+3'
+
         """
         a = _convert_other(a, raiseit=True)
         return a.to_eng_string(context=self)
diff --git a/lib-python/2.7/distutils/command/build_ext.py b/lib-python/2.7/distutils/command/build_ext.py
--- a/lib-python/2.7/distutils/command/build_ext.py
+++ b/lib-python/2.7/distutils/command/build_ext.py
@@ -166,6 +166,7 @@
             self.include_dirs.append(plat_py_include)
 
         self.ensure_string_list('libraries')
+        self.ensure_string_list('link_objects')
 
         # Life is easier if we're not forever checking for None, so
         # simplify these options to empty lists if unset
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
@@ -21,7 +21,7 @@
 class PyPIRCCommand(Command):
     """Base command that knows how to handle the .pypirc file
     """
-    DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi'
+    DEFAULT_REPOSITORY = 'https://upload.pypi.org/legacy/'
     DEFAULT_REALM = 'pypi'
     repository = None
     realm = None
diff --git a/lib-python/2.7/distutils/cygwinccompiler.py b/lib-python/2.7/distutils/cygwinccompiler.py
--- a/lib-python/2.7/distutils/cygwinccompiler.py
+++ b/lib-python/2.7/distutils/cygwinccompiler.py
@@ -350,7 +350,7 @@
 # class Mingw32CCompiler
 
 # Because these compilers aren't configured in Python's pyconfig.h file by
-# default, we should at least warn the user if he is using a unmodified
+# default, we should at least warn the user if he is using an unmodified
 # version.
 
 CONFIG_H_OK = "ok"
diff --git a/lib-python/2.7/distutils/tests/test_bdist_rpm.py b/lib-python/2.7/distutils/tests/test_bdist_rpm.py
--- a/lib-python/2.7/distutils/tests/test_bdist_rpm.py
+++ b/lib-python/2.7/distutils/tests/test_bdist_rpm.py
@@ -8,6 +8,11 @@
 
 from test.test_support import run_unittest
 
+try:
+    import zlib
+except ImportError:
+    zlib = None
+
 from distutils.core import Distribution
 from distutils.command.bdist_rpm import bdist_rpm
 from distutils.tests import support
@@ -44,6 +49,7 @@
     # spurious sdtout/stderr output under Mac OS X
     @unittest.skipUnless(sys.platform.startswith('linux'),
                          'spurious sdtout/stderr output under Mac OS X')
+    @unittest.skipUnless(zlib, "requires zlib")
     @unittest.skipIf(find_executable('rpm') is None,
                      'the rpm command is not found')
     @unittest.skipIf(find_executable('rpmbuild') is None,
@@ -86,6 +92,7 @@
     # spurious sdtout/stderr output under Mac OS X
     @unittest.skipUnless(sys.platform.startswith('linux'),
                          'spurious sdtout/stderr output under Mac OS X')
+    @unittest.skipUnless(zlib, "requires zlib")
     # http://bugs.python.org/issue1533164
     @unittest.skipIf(find_executable('rpm') is None,
                      'the rpm command is not found')
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
@@ -168,6 +168,13 @@
         cmd.finalize_options()
         self.assertEqual(cmd.rpath, ['one', 'two'])
 
+        # make sure cmd.link_objects is turned into a list
+        # if it's a string
+        cmd = build_ext(dist)
+        cmd.link_objects = 'one two,three'
+        cmd.finalize_options()
+        self.assertEqual(cmd.link_objects, ['one', 'two', 'three'])
+
         # XXX more tests to perform for win32
 
         # make sure define is turned into 2-tuples
@@ -215,7 +222,7 @@
         self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
 
         # second element of each tuple in 'ext_modules'
-        # must be a ary (build info)
+        # must be a dictionary (build info)
         exts = [('foo.bar', '')]
         self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts)
 
diff --git a/lib-python/2.7/distutils/tests/test_config.py b/lib-python/2.7/distutils/tests/test_config.py
--- a/lib-python/2.7/distutils/tests/test_config.py
+++ b/lib-python/2.7/distutils/tests/test_config.py
@@ -89,7 +89,7 @@
         config = config.items()
         config.sort()
         waited = [('password', 'secret'), ('realm', 'pypi'),
-                  ('repository', 'https://pypi.python.org/pypi'),
+                  ('repository', 'https://upload.pypi.org/legacy/'),
                   ('server', 'server1'), ('username', 'me')]
         self.assertEqual(config, waited)
 
@@ -99,7 +99,7 @@
         config = config.items()
         config.sort()
         waited = [('password', 'secret'), ('realm', 'pypi'),
-                  ('repository', 'https://pypi.python.org/pypi'),
+                  ('repository', 'https://upload.pypi.org/legacy/'),
                   ('server', 'server-login'), ('username', 'tarek')]
         self.assertEqual(config, waited)
 
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
@@ -125,7 +125,7 @@
         self.assertRaises(KeyError, Reg.get_value, 'xxx', 'xxx')
 
         # looking for values that should exist on all
-        # windows registeries versions.
+        # windows registry versions.
         path = r'Control Panel\Desktop'
         v = Reg.get_value(path, u'dragfullwindows')
         self.assertIn(v, (u'0', u'1', u'2'))
diff --git a/lib-python/2.7/distutils/tests/test_upload.py b/lib-python/2.7/distutils/tests/test_upload.py
--- a/lib-python/2.7/distutils/tests/test_upload.py
+++ b/lib-python/2.7/distutils/tests/test_upload.py
@@ -82,7 +82,7 @@
         cmd.finalize_options()
         for attr, waited in (('username', 'me'), ('password', 'secret'),
                              ('realm', 'pypi'),
-                             ('repository', 'https://pypi.python.org/pypi')):
+                             ('repository', 'https://upload.pypi.org/legacy/')):
             self.assertEqual(getattr(cmd, attr), waited)
 
     def test_saved_password(self):
@@ -123,7 +123,7 @@
         self.assertTrue(headers['Content-type'].startswith('multipart/form-data'))
         self.assertEqual(self.last_open.req.get_method(), 'POST')
         self.assertEqual(self.last_open.req.get_full_url(),
-                         'https://pypi.python.org/pypi')
+                         'https://upload.pypi.org/legacy/')
         self.assertIn('xxx', self.last_open.req.data)
         auth = self.last_open.req.headers['Authorization']
         self.assertNotIn('\n', auth)
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
@@ -245,6 +245,8 @@
         if sys.platform[:6] == "darwin":
             # MacOSX's linker doesn't understand the -R flag at all
             return "-L" + dir
+        elif sys.platform[:7] == "freebsd":
+            return "-Wl,-rpath=" + dir
         elif sys.platform[:5] == "hp-ux":
             if self._is_gcc(compiler):
                 return ["-Wl,+s", "-L" + dir]
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
@@ -219,7 +219,7 @@
     with open(filename, 'U') as f:
         return f.read(), filename
 
-# Use sys.stdout encoding for ouput.
+# Use sys.stdout encoding for output.
 _encoding = getattr(sys.__stdout__, 'encoding', None) or 'utf-8'
 
 def _indent(s, indent=4):
diff --git a/lib-python/2.7/dumbdbm.py b/lib-python/2.7/dumbdbm.py
--- a/lib-python/2.7/dumbdbm.py
+++ b/lib-python/2.7/dumbdbm.py
@@ -45,8 +45,9 @@
     _os = _os       # for _commit()
     _open = _open   # for _commit()
 
-    def __init__(self, filebasename, mode):
+    def __init__(self, filebasename, mode, flag='c'):
         self._mode = mode
+        self._readonly = (flag == 'r')
 
         # The directory file is a text file.  Each line looks like
         #    "%r, (%d, %d)\n" % (key, pos, siz)
@@ -81,8 +82,9 @@
         try:
             f = _open(self._dirfile)
         except IOError:
-            pass
+            self._modified = not self._readonly
         else:
+            self._modified = False
             with f:
                 for line in f:
                     line = line.rstrip()
@@ -96,7 +98,7 @@
         # CAUTION:  It's vital that _commit() succeed, and _commit() can
         # be called from __del__().  Therefore we must never reference a
         # global in this routine.
-        if self._index is None:
+        if self._index is None or not self._modified:
             return  # nothing to do
 
         try:
@@ -159,6 +161,7 @@
     def __setitem__(self, key, val):
         if not type(key) == type('') == type(val):
             raise TypeError, "keys and values must be strings"
+        self._modified = True
         if key not in self._index:
             self._addkey(key, self._addval(val))
         else:
@@ -184,6 +187,7 @@
             # (so that _commit() never gets called).
 
     def __delitem__(self, key):
+        self._modified = True
         # The blocks used by the associated value are lost.
         del self._index[key]
         # XXX It's unclear why we do a _commit() here (the code always
@@ -246,4 +250,4 @@
         # Turn off any bits that are set in the umask
         mode = mode & (~um)
 
-    return _Database(file, mode)
+    return _Database(file, mode, flag)
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
@@ -166,7 +166,7 @@
     decoding a text attachment.
 
     This function does not parse a full MIME header value encoded with
-    base64 (like =?iso-8895-1?b?bmloISBuaWgh?=) -- please use the high
+    base64 (like =?iso-8859-1?b?bmloISBuaWgh?=) -- please use the high
     level email.header class for that functionality.
     """
     if not s:
diff --git a/lib-python/2.7/email/quoprimime.py b/lib-python/2.7/email/quoprimime.py
--- a/lib-python/2.7/email/quoprimime.py
+++ b/lib-python/2.7/email/quoprimime.py
@@ -329,7 +329,7 @@
     """Decode a string encoded with RFC 2045 MIME header `Q' encoding.
 
     This function does not parse a full MIME header value encoded with
-    quoted-printable (like =?iso-8895-1?q?Hello_World?=) -- please use
+    quoted-printable (like =?iso-8859-1?q?Hello_World?=) -- please use
     the high level email.header class for that functionality.
     """
     s = s.replace('_', ' ')
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
@@ -561,12 +561,12 @@
 
     # Issue 5871: reject an attempt to embed a header inside a header value
     # (header injection attack).
-    def test_embeded_header_via_Header_rejected(self):
+    def test_embedded_header_via_Header_rejected(self):
         msg = Message()
         msg['Dummy'] = Header('dummy\nX-Injected-Header: test')
         self.assertRaises(Errors.HeaderParseError, msg.as_string)
 
-    def test_embeded_header_via_string_rejected(self):
+    def test_embedded_header_via_string_rejected(self):
         msg = Message()
         msg['Dummy'] = 'dummy\nX-Injected-Header: test'
         self.assertRaises(Errors.HeaderParseError, msg.as_string)
@@ -1673,9 +1673,9 @@
 
     def test_rfc2047_Q_invalid_digits(self):
         # issue 10004.
-        s = '=?iso-8659-1?Q?andr=e9=zz?='
+        s = '=?iso-8859-1?Q?andr=e9=zz?='
         self.assertEqual(decode_header(s),
-                        [(b'andr\xe9=zz', 'iso-8659-1')])
+                        [(b'andr\xe9=zz', 'iso-8859-1')])
 
 
 # Test the MIMEMessage class
diff --git a/lib-python/2.7/ensurepip/__init__.py b/lib-python/2.7/ensurepip/__init__.py
--- a/lib-python/2.7/ensurepip/__init__.py
+++ b/lib-python/2.7/ensurepip/__init__.py
@@ -12,23 +12,9 @@
 __all__ = ["version", "bootstrap"]
 
 
-_SETUPTOOLS_VERSION = "20.10.1"
+_SETUPTOOLS_VERSION = "28.8.0"
 
-_PIP_VERSION = "8.1.1"
-
-# pip currently requires ssl support, so we try to provide a nicer
-# error message when that is missing (http://bugs.python.org/issue19744)
-_MISSING_SSL_MESSAGE = ("pip {} requires SSL/TLS".format(_PIP_VERSION))
-try:
-    import ssl
-except ImportError:
-    ssl = None
-
-    def _require_ssl_for_pip():
-        raise RuntimeError(_MISSING_SSL_MESSAGE)
-else:
-    def _require_ssl_for_pip():
-        pass
+_PIP_VERSION = "9.0.1"
 
 _PROJECTS = [
     ("setuptools", _SETUPTOOLS_VERSION),
@@ -77,7 +63,6 @@
     if altinstall and default_pip:
         raise ValueError("Cannot use altinstall and default_pip together")
 
-    _require_ssl_for_pip()
     _disable_pip_configuration_settings()
 
     # By default, installing pip and setuptools installs all of the
@@ -143,7 +128,6 @@
         print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr)
         return
 
-    _require_ssl_for_pip()
     _disable_pip_configuration_settings()
 
     # Construct the arguments to be passed to the pip command
@@ -155,11 +139,6 @@
 
 
 def _main(argv=None):
-    if ssl is None:
-        print("Ignoring ensurepip failure: {}".format(_MISSING_SSL_MESSAGE),
-              file=sys.stderr)
-        return
-
     import argparse
     parser = argparse.ArgumentParser(prog="python -m ensurepip")
     parser.add_argument(
diff --git a/lib-python/2.7/ensurepip/_bundled/pip-8.1.1-py2.py3-none-any.whl b/lib-python/2.7/ensurepip/_bundled/pip-8.1.1-py2.py3-none-any.whl
deleted file mode 100644
index 8632eb7af04c6337f0442a878ecb99cd2b1a67e0..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch

[cut]

diff --git a/lib-python/2.7/ensurepip/_bundled/pip-9.0.1-py2.py3-none-any.whl b/lib-python/2.7/ensurepip/_bundled/pip-9.0.1-py2.py3-none-any.whl
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4b8ecc69db7e37fc6dd7b6dd8f690508f42866a1
GIT binary patch

[cut]

diff --git a/lib-python/2.7/ensurepip/_bundled/setuptools-20.10.1-py2.py3-none-any.whl b/lib-python/2.7/ensurepip/_bundled/setuptools-20.10.1-py2.py3-none-any.whl
deleted file mode 100644
index 9d1319a24aba103fe956ef6298e3649efacc0b93..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch

[cut]

diff --git a/lib-python/2.7/ensurepip/_bundled/setuptools-28.8.0-py2.py3-none-any.whl b/lib-python/2.7/ensurepip/_bundled/setuptools-28.8.0-py2.py3-none-any.whl
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..502e3cb418c154872ad6e677ef8b63557b38ec35
GIT binary patch

[cut]

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
@@ -264,7 +264,7 @@
         return self.voidcmd(cmd)
 
     def sendeprt(self, host, port):
-        '''Send a EPRT command with the current host and the given port number.'''
+        '''Send an EPRT command with the current host and the given port number.'''
         af = 0
         if self.af == socket.AF_INET:
             af = 1
@@ -842,7 +842,7 @@
 
 
 def parse229(resp, peer):
-    '''Parse the '229' response for a EPSV request.
+    '''Parse the '229' response for an EPSV request.
     Raises error_proto if it does not contain '(|||port|)'
     Return ('host.addr.as.numbers', port#) tuple.'''
 
diff --git a/lib-python/2.7/gettext.py b/lib-python/2.7/gettext.py
--- a/lib-python/2.7/gettext.py
+++ b/lib-python/2.7/gettext.py
@@ -59,74 +59,147 @@
 
 _default_localedir = os.path.join(sys.prefix, 'share', 'locale')
 
+# Expression parsing for plural form selection.
+#
+# The gettext library supports a small subset of C syntax.  The only
+# incompatible difference is that integer literals starting with zero are
+# decimal.
+#
+# https://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms
+# http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/plural.y
 
-def test(condition, true, false):
-    """
-    Implements the C expression:
+_token_pattern = re.compile(r"""
+        (?P<WHITESPACES>[ \t]+)                    | # spaces and horizontal tabs
+        (?P<NUMBER>[0-9]+\b)                       | # decimal integer
+        (?P<NAME>n\b)                              | # only n is allowed
+        (?P<PARENTHESIS>[()])                      |
+        (?P<OPERATOR>[-*/%+?:]|[><!]=?|==|&&|\|\|) | # !, *, /, %, +, -, <, >,
+                                                     # <=, >=, ==, !=, &&, ||,
+                                                     # ? :
+                                                     # unary and bitwise ops
+                                                     # not allowed
+        (?P<INVALID>\w+|.)                           # invalid token
+    """, re.VERBOSE|re.DOTALL)
 
-      condition ? true : false
+def _tokenize(plural):
+    for mo in re.finditer(_token_pattern, plural):
+        kind = mo.lastgroup
+        if kind == 'WHITESPACES':
+            continue
+        value = mo.group(kind)
+        if kind == 'INVALID':
+            raise ValueError('invalid token in plural form: %s' % value)
+        yield value
+    yield ''
 
-    Required to correctly interpret plural forms.
-    """
-    if condition:
-        return true
+def _error(value):
+    if value:
+        return ValueError('unexpected token in plural form: %s' % value)
     else:
-        return false
+        return ValueError('unexpected end of plural form')
 
+_binary_ops = (
+    ('||',),
+    ('&&',),
+    ('==', '!='),
+    ('<', '>', '<=', '>='),
+    ('+', '-'),
+    ('*', '/', '%'),
+)
+_binary_ops = {op: i for i, ops in enumerate(_binary_ops, 1) for op in ops}
+_c2py_ops = {'||': 'or', '&&': 'and', '/': '//'}
+
+def _parse(tokens, priority=-1):
+    result = ''
+    nexttok = next(tokens)
+    while nexttok == '!':
+        result += 'not '
+        nexttok = next(tokens)
+
+    if nexttok == '(':
+        sub, nexttok = _parse(tokens)
+        result = '%s(%s)' % (result, sub)
+        if nexttok != ')':
+            raise ValueError('unbalanced parenthesis in plural form')
+    elif nexttok == 'n':
+        result = '%s%s' % (result, nexttok)
+    else:
+        try:
+            value = int(nexttok, 10)
+        except ValueError:
+            raise _error(nexttok)
+        result = '%s%d' % (result, value)
+    nexttok = next(tokens)
+
+    j = 100
+    while nexttok in _binary_ops:
+        i = _binary_ops[nexttok]
+        if i < priority:
+            break
+        # Break chained comparisons
+        if i in (3, 4) and j in (3, 4):  # '==', '!=', '<', '>', '<=', '>='
+            result = '(%s)' % result
+        # Replace some C operators by their Python equivalents
+        op = _c2py_ops.get(nexttok, nexttok)
+        right, nexttok = _parse(tokens, i + 1)
+        result = '%s %s %s' % (result, op, right)
+        j = i
+    if j == priority == 4:  # '<', '>', '<=', '>='
+        result = '(%s)' % result
+
+    if nexttok == '?' and priority <= 0:
+        if_true, nexttok = _parse(tokens, 0)
+        if nexttok != ':':
+            raise _error(nexttok)
+        if_false, nexttok = _parse(tokens)
+        result = '%s if %s else %s' % (if_true, result, if_false)
+        if priority == 0:
+            result = '(%s)' % result
+
+    return result, nexttok
+
+def _as_int(n):
+    try:
+        i = round(n)
+    except TypeError:
+        raise TypeError('Plural value must be an integer, got %s' %
+                        (n.__class__.__name__,))
+    return n
 
 def c2py(plural):
     """Gets a C expression as used in PO files for plural forms and returns a
-    Python lambda function that implements an equivalent expression.
+    Python function that implements an equivalent expression.
     """
-    # Security check, allow only the "n" identifier
+
+    if len(plural) > 1000:
+        raise ValueError('plural form expression is too long')
     try:
-        from cStringIO import StringIO
-    except ImportError:
-        from StringIO import StringIO
-    import token, tokenize
-    tokens = tokenize.generate_tokens(StringIO(plural).readline)
-    try:
-        danger = [x for x in tokens if x[0] == token.NAME and x[1] != 'n']
-    except tokenize.TokenError:
-        raise ValueError, \
-              'plural forms expression error, maybe unbalanced parenthesis'
-    else:
-        if danger:
-            raise ValueError, 'plural forms expression could be dangerous'
+        result, nexttok = _parse(_tokenize(plural))
+        if nexttok:
+            raise _error(nexttok)
 
-    # Replace some C operators by their Python equivalents
-    plural = plural.replace('&&', ' and ')
-    plural = plural.replace('||', ' or ')
+        depth = 0
+        for c in result:
+            if c == '(':
+                depth += 1
+                if depth > 20:
+                    # Python compiler limit is about 90.
+                    # The most complex example has 2.
+                    raise ValueError('plural form expression is too complex')
+            elif c == ')':
+                depth -= 1
 
-    expr = re.compile(r'\!([^=])')
-    plural = expr.sub(' not \\1', plural)
-
-    # Regular expression and replacement function used to transform
-    # "a?b:c" to "test(a,b,c)".
-    expr = re.compile(r'(.*?)\?(.*?):(.*)')
-    def repl(x):
-        return "test(%s, %s, %s)" % (x.group(1), x.group(2),
-                                     expr.sub(repl, x.group(3)))
-
-    # Code to transform the plural expression, taking care of parentheses
-    stack = ['']
-    for c in plural:
-        if c == '(':
-            stack.append('')
-        elif c == ')':
-            if len(stack) == 1:
-                # Actually, we never reach this code, because unbalanced
-                # parentheses get caught in the security check at the
-                # beginning.
-                raise ValueError, 'unbalanced parenthesis in plural form'
-            s = expr.sub(repl, stack.pop())
-            stack[-1] += '(%s)' % s
-        else:
-            stack[-1] += c
-    plural = expr.sub(repl, stack.pop())
-
-    return eval('lambda n: int(%s)' % plural)
-
+        ns = {'_as_int': _as_int}
+        exec('''if 1:
+            def func(n):
+                if not isinstance(n, int):
+                    n = _as_int(n)
+                return int(%s)
+            ''' % result, ns)
+        return ns['func']
+    except RuntimeError:
+        # Recursion error can be raised in _parse() or exec().
+        raise ValueError('plural form expression is too complex')
 
 
 def _expand_lang(locale):
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
@@ -242,7 +242,7 @@
 #
 # VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1
 
-# the patterns for both name and value are more leniant than RFC
+# the patterns for both name and value are more lenient than RFC
 # definitions to allow for backwards compatibility
 _is_legal_header_name = re.compile(r'\A[^:\s][^:\r\n]*\Z').match
 _is_illegal_header_value = re.compile(r'\n(?![ \t])|\r(?![ \t\n])').search
@@ -273,9 +273,8 @@
 
         Read header lines up to the entirely blank line that terminates them.
         The (normally blank) line that ends the headers is skipped, but not
-        included in the returned list.  If a non-header line ends the headers,
-        (which is an error), an attempt is made to backspace over it; it is
-        never included in the returned list.
+        included in the returned list.  If an invalid line is found in the
+        header section, it is skipped, and further lines are processed.
 
         The variable self.status is set to the empty string if all went well,
         otherwise it is an error message.  The variable self.headers is a
@@ -302,19 +301,17 @@
         self.status = ''
         headerseen = ""
         firstline = 1
-        startofline = unread = tell = None
-        if hasattr(self.fp, 'unread'):
-            unread = self.fp.unread
-        elif self.seekable:
+        tell = None
+        if not hasattr(self.fp, 'unread') and self.seekable:
             tell = self.fp.tell
         while True:
             if len(hlist) > _MAXHEADERS:
                 raise HTTPException("got more than %d headers" % _MAXHEADERS)
             if tell:
                 try:
-                    startofline = tell()
+                    tell()
                 except IOError:
-                    startofline = tell = None
+                    tell = None
                     self.seekable = 0
             line = self.fp.readline(_MAXLINE + 1)
             if len(line) > _MAXLINE:
@@ -345,26 +342,14 @@
                 # It's a legal header line, save it.
                 hlist.append(line)
                 self.addheader(headerseen, line[len(headerseen)+1:].strip())
-                continue
             elif headerseen is not None:
                 # An empty header name. These aren't allowed in HTTP, but it's
                 # probably a benign mistake. Don't add the header, just keep
                 # going.
-                continue
+                pass
             else:
-                # It's not a header line; throw it back and stop here.
-                if not self.dict:
-                    self.status = 'No headers'
-                else:
-                    self.status = 'Non-header line where header expected'
-                # Try to undo the read.
-                if unread:
-                    unread(line)
-                elif tell:
-                    self.fp.seek(startofline)
-                else:
-                    self.status = self.status + '; bad seek'
-                break
+                # It's not a header line; skip it and try the next line.
+                self.status = 'Non-header line where header expected'
 
 class HTTPResponse:
 
diff --git a/lib-python/2.7/idlelib/Bindings.py b/lib-python/2.7/idlelib/Bindings.py
--- a/lib-python/2.7/idlelib/Bindings.py
+++ b/lib-python/2.7/idlelib/Bindings.py
@@ -67,6 +67,8 @@
  ('shell', [
    ('_View Last Restart', '<<view-restart>>'),
    ('_Restart Shell', '<<restart-shell>>'),
+   None,
+   ('_Interrupt Execution', '<<interrupt-execution>>'),
    ]),
  ('debug', [
    ('_Go to File/Line', '<<goto-file-line>>'),
diff --git a/lib-python/2.7/idlelib/CallTipWindow.py b/lib-python/2.7/idlelib/CallTipWindow.py
--- a/lib-python/2.7/idlelib/CallTipWindow.py
+++ b/lib-python/2.7/idlelib/CallTipWindow.py
@@ -9,7 +9,7 @@
 HIDE_SEQUENCES = ("<Key-Escape>", "<FocusOut>")
 CHECKHIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-checkhide>>"
 CHECKHIDE_SEQUENCES = ("<KeyRelease>", "<ButtonRelease>")
-CHECKHIDE_TIME = 100 # miliseconds
+CHECKHIDE_TIME = 100 # milliseconds
 
 MARK_RIGHT = "calltipwindowregion_right"
 
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
@@ -1384,7 +1384,7 @@
             text.see("insert")
             text.undo_block_stop()
 
-    # Our editwin provides a is_char_in_string function that works
+    # Our editwin provides an is_char_in_string function that works
     # with a Tk text index, but PyParse only knows about offsets into
     # a string. This builds a function for PyParse that accepts an
     # offset.
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
@@ -13,6 +13,7 @@
 import sys
 import tempfile
 
+from Tkinter import *
 import tkFileDialog
 import tkMessageBox
 from SimpleDialog import SimpleDialog
@@ -91,6 +92,7 @@
         # l2['state'] = DISABLED
         l2.pack(side=TOP, anchor = W, fill=X)
         l3 = Label(top, text="to your file\n"
+                   "See Language Reference, 2.1.4 Encoding declarations.\n"
                    "Choose OK to save this file as %s\n"
                    "Edit your general options to silence this warning" % enc)
         l3.pack(side=TOP, anchor = W)
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,6 +1,41 @@
+What's New in IDLE 2.7.13?
+==========================
+*Release date: 2017-01-01?*
+
+- Issue #27854: Make Help => IDLE Help work again on Windows.
+  Include idlelib/help.html in 2.7 Windows installer.
+
+- Issue #25507: Add back import needed for 2.x encoding warning box.
+  Add pointer to 'Encoding declaration' in Language Reference.
+
+- Issue #15308: Add 'interrupt execution' (^C) to Shell menu.
+  Patch by Roger Serwy, updated by Bayard Randel.
+
+- Issue #27922: Stop IDLE tests from 'flashing' gui widgets on the screen.
+
+- Issue #17642: add larger font sizes for classroom projection.
+
+- Add version to title of IDLE help window.
+
+- Issue #25564: In section on IDLE -- console differences, mention that
+  using exec means that __builtins__ is defined for each statement.
+
+- Issue #27714: text_textview and test_autocomplete now pass when re-run
+  in the same process.  This occurs when test_idle fails when run with the
+  -w option but without -jn.  Fix warning from test_config.
+
+- Issue #27452: add line counter and crc to IDLE configHandler test dump.
+
+- Issue #27365: Allow non-ascii chars in IDLE NEWS.txt, for contributor names.
+
+- Issue #27245: IDLE: Cleanly delete custom themes and key bindings.
+  Previously, when IDLE was started from a console or by import, a cascade
+  of warnings was emitted.  Patch by Serhiy Storchaka.
+
+
 What's New in IDLE 2.7.12?
 ==========================
-*Release date: 2015-06-30?*
+*Release date: 2015-06-25*
 
 - Issue #5124: Paste with text selected now replaces the selection on X11.
   This matches how paste works on Windows, Mac, most modern Linux apps,
@@ -174,7 +209,7 @@
   Changes are written to HOME/.idlerc/config-extensions.cfg.
   Original patch by Tal Einat.
 
-- Issue #16233: A module browser (File : Class Browser, Alt+C) requires a
+- Issue #16233: A module browser (File : Class Browser, Alt+C) requires an
   editor window with a filename.  When Class Browser is requested otherwise,
   from a shell, output window, or 'Untitled' editor, Idle no longer displays
   an error box.  It now pops up an  Open Module box (Alt+M). If a valid name
diff --git a/lib-python/2.7/idlelib/ParenMatch.py b/lib-python/2.7/idlelib/ParenMatch.py
--- a/lib-python/2.7/idlelib/ParenMatch.py
+++ b/lib-python/2.7/idlelib/ParenMatch.py
@@ -9,7 +9,7 @@
 from idlelib.configHandler import idleConf
 
 _openers = {')':'(',']':'[','}':'{'}
-CHECK_DELAY = 100 # miliseconds
+CHECK_DELAY = 100 # milliseconds
 
 class ParenMatch:
     """Highlight matching parentheses
diff --git a/lib-python/2.7/idlelib/README.txt b/lib-python/2.7/idlelib/README.txt
--- a/lib-python/2.7/idlelib/README.txt
+++ b/lib-python/2.7/idlelib/README.txt
@@ -161,14 +161,15 @@
   Show surrounding parens  # ParenMatch (& Hyperparser)
 
 Shell  # PyShell
-  View Last Restart  # PyShell.?
-  Restart Shell  # PyShell.?
+  View Last Restart    # PyShell.PyShell.view_restart_mark
+  Restart Shell        # PyShell.PyShell.restart_shell
+  Interrupt Execution  # pyshell.PyShell.cancel_callback
 
 Debug (Shell only)
   Go to File/Line
-  Debugger  # Debugger, RemoteDebugger
-  Stack Viewer  # StackViewer
-  Auto-open Stack Viewer  # StackViewer
+  Debugger               # Debugger, RemoteDebugger, PyShell.toggle_debuger
+  Stack Viewer           # StackViewer, PyShell.open_stack_viewer
+  Auto-open Stack Viewer # StackViewer
 
 Format (Editor only)
   Indent Region
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
@@ -59,7 +59,7 @@
     def default_command(self, event=None):
         if self.do_find(self.ok):
             if self.do_replace():   # Only find next match if replace succeeded.
-                                    # A bad re can cause a it to fail.
+                                    # A bad re can cause it to fail.
                 self.do_find(0)
 
     def _replace_expand(self, m, repl):
diff --git a/lib-python/2.7/idlelib/SearchEngine.py b/lib-python/2.7/idlelib/SearchEngine.py
--- a/lib-python/2.7/idlelib/SearchEngine.py
+++ b/lib-python/2.7/idlelib/SearchEngine.py
@@ -107,7 +107,7 @@
         It directly return the result of that call.
 
         Text is a text widget. Prog is a precompiled pattern.
-        The ok parameteris a bit complicated as it has two effects.
+        The ok parameter is a bit complicated as it has two effects.
 
         If there is a selection, the search begin at either end,
         depending on the direction setting and ok, with ok meaning that
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
@@ -767,6 +767,7 @@
         if not tkMessageBox.askyesno(
                 'Delete Key Set',  delmsg % keySetName, parent=self):
             return
+        self.DeactivateCurrentConfig()
         #remove key set from config
         idleConf.userCfg['keys'].remove_section(keySetName)
         if keySetName in self.changedItems['keys']:
@@ -785,7 +786,8 @@
         self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
         self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
         #user can't back out of these changes, they must be applied now
-        self.Apply()
+        self.SaveAllChangedConfigs()
+        self.ActivateConfigChanges()
         self.SetKeysType()
 
     def DeleteCustomTheme(self):
@@ -794,6 +796,7 @@
         if not tkMessageBox.askyesno(
                 'Delete Theme',  delmsg % themeName, parent=self):
             return
+        self.DeactivateCurrentConfig()
         #remove theme from config
         idleConf.userCfg['highlight'].remove_section(themeName)
         if themeName in self.changedItems['highlight']:
@@ -812,7 +815,8 @@
         self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme', 'default'))
         self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
         #user can't back out of these changes, they must be applied now
-        self.Apply()
+        self.SaveAllChangedConfigs()
+        self.ActivateConfigChanges()
         self.SetThemeType()
 
     def GetColour(self):
@@ -1008,7 +1012,8 @@
             pass
         ##font size dropdown
         self.optMenuFontSize.SetMenu(('7', '8', '9', '10', '11', '12', '13',
-                                      '14', '16', '18', '20', '22'), fontSize )
+                                      '14', '16', '18', '20', '22',
+                                      '25', '29', '34', '40'), fontSize )
         ##fontWeight
         self.fontBold.set(fontBold)
         ##font sample
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
@@ -741,21 +741,32 @@
 idleConf = IdleConf()
 
 # TODO Revise test output, write expanded unittest
-### module test
+#
 if __name__ == '__main__':
+    from zlib import crc32
+    line, crc = 0, 0
+
+    def sprint(obj):
+        global line, crc
+        txt = str(obj)
+        line += 1
+        crc = crc32(txt.encode(encoding='utf-8'), crc)
+        print(txt)
+        #print('***', line, crc, '***')  # uncomment for diagnosis
+
     def dumpCfg(cfg):
-        print('\n', cfg, '\n')
-        for key in cfg:
+        print('\n', cfg, '\n')  # has variable '0xnnnnnnnn' addresses
+        for key in sorted(cfg.keys()):
             sections = cfg[key].sections()
-            print(key)
-            print(sections)
+            sprint(key)
+            sprint(sections)
             for section in sections:
                 options = cfg[key].options(section)
-                print(section)
-                print(options)
+                sprint(section)
+                sprint(options)
                 for option in options:
-                    print(option, '=', cfg[key].Get(section, option))
+                    sprint(option + ' = ' + cfg[key].Get(section, option))
+
     dumpCfg(idleConf.defaultCfg)
     dumpCfg(idleConf.userCfg)
-    print(idleConf.userCfg['main'].Get('Theme', 'name'))
-    #print(idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal'))
+    print('\nlines = ', line, ', crc = ', crc, sep='')
diff --git a/lib-python/2.7/idlelib/help.html b/lib-python/2.7/idlelib/help.html
--- a/lib-python/2.7/idlelib/help.html
+++ b/lib-python/2.7/idlelib/help.html
@@ -6,7 +6,7 @@
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 
-    <title>24.6. IDLE — Python 2.7.11 documentation</title>
+    <title>24.6. IDLE — Python 2.7.12 documentation</title>
 
     <link rel="stylesheet" href="../_static/classic.css" type="text/css" />
     <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
@@ -14,7 +14,7 @@
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
         URL_ROOT:    '../',
-        VERSION:     '2.7.11',
+        VERSION:     '2.7.12',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
         HAS_SOURCE:  true
@@ -25,11 +25,11 @@
     <script type="text/javascript" src="../_static/doctools.js"></script>
     <script type="text/javascript" src="../_static/sidebar.js"></script>
     <link rel="search" type="application/opensearchdescription+xml"
-          title="Search within Python 2.7.11 documentation"
+          title="Search within Python 2.7.12 documentation"
           href="../_static/opensearch.xml"/>
     <link rel="author" title="About these documents" href="../about.html" />
     <link rel="copyright" title="Copyright" href="../copyright.html" />
-    <link rel="top" title="Python 2.7.11 documentation" href="../contents.html" />
+    <link rel="top" title="Python 2.7.12 documentation" href="../contents.html" />
     <link rel="up" title="24. Graphical User Interfaces with Tk" href="tk.html" />
     <link rel="next" title="24.7. Other Graphical User Interface Packages" href="othergui.html" />
     <link rel="prev" title="24.5. turtle — Turtle graphics for Tk" href="turtle.html" />
@@ -60,7 +60,7 @@
                  style="vertical-align: middle; margin-top: -1px"/></li>
         <li><a href="https://www.python.org/">Python</a> »</li>
         <li>
-          <a href="../index.html">Python 2.7.11 documentation</a> »
+          <a href="../index.html">Python 2.7.12 documentation</a> »
         </li>
 
           <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
@@ -238,6 +238,8 @@
 <dd>Scroll the shell window to the last Shell restart.</dd>
 <dt>Restart Shell</dt>
 <dd>Restart the shell to clean the environment.</dd>
+<dt>Interrupt Execution</dt>
+<dd>Stop a running program.</dd>
 </dl>
 </div>
 <div class="section" id="debug-menu-shell-window-only">
@@ -490,12 +492,12 @@
 functions to be used from IDLE’s Python shell.</p>
 <div class="section" id="command-line-usage">
 <h3>24.6.3.1. Command line usage<a class="headerlink" href="#command-line-usage" title="Permalink to this headline">¶</a></h3>
-<div class="highlight-python"><div class="highlight"><pre>idle.py [-c command] [-d] [-e] [-h] [-i] [-r file] [-s] [-t title] [-] [arg] ...
+<div class="highlight-none"><div class="highlight"><pre><span></span>idle.py [-c command] [-d] [-e] [-h] [-i] [-r file] [-s] [-t title] [-] [arg] ...
 
 -c command  run command in the shell window
 -d          enable debugger and open shell window
 -e          open editor window
--h          print help message with legal combinatios and exit
+-h          print help message with legal combinations and exit
 -i          open shell window
 -r file     run file in shell window
 -s          run $IDLESTARTUP or $PYTHONSTARTUP first, in shell window
@@ -527,7 +529,9 @@
 IDLE’s changes are lost and things like <code class="docutils literal"><span class="pre">input</span></code>, <code class="docutils literal"><span class="pre">raw_input</span></code>, and
 <code class="docutils literal"><span class="pre">print</span></code> will not work correctly.</p>
 <p>With IDLE’s Shell, one enters, edits, and recalls complete statements.
-Some consoles only work with a single physical line at a time.</p>
+Some consoles only work with a single physical line at a time.  IDLE uses
+<code class="docutils literal"><span class="pre">exec</span></code> to run each statement.  As a result, <code class="docutils literal"><span class="pre">'__builtins__'</span></code> is always
+defined for each statement.</p>
 </div>
 <div class="section" id="running-without-a-subprocess">
 <h3>24.6.3.3. Running without a subprocess<a class="headerlink" href="#running-without-a-subprocess" title="Permalink to this headline">¶</a></h3>
@@ -688,7 +692,7 @@
                  style="vertical-align: middle; margin-top: -1px"/></li>
         <li><a href="https://www.python.org/">Python</a> »</li>
         <li>
-          <a href="../index.html">Python 2.7.11 documentation</a> »
+          <a href="../index.html">Python 2.7.12 documentation</a> »
         </li>
 
           <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
@@ -701,10 +705,10 @@
     The Python Software Foundation is a non-profit corporation.
     <a href="https://www.python.org/psf/donations/">Please donate.</a>
     <br />
-    Last updated on May 02, 2016.
+    Last updated on Sep 12, 2016.
     <a href="../bugs.html">Found a bug</a>?
     <br />
-    Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.3.3.
+    Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.3.6.
     </div>
 
   </body>
diff --git a/lib-python/2.7/idlelib/help.py b/lib-python/2.7/idlelib/help.py
--- a/lib-python/2.7/idlelib/help.py
+++ b/lib-python/2.7/idlelib/help.py
@@ -26,6 +26,7 @@
 """
 from HTMLParser import HTMLParser
 from os.path import abspath, dirname, isdir, isfile, join
+from platform import python_version
 from Tkinter import Tk, Toplevel, Frame, Text, Scrollbar, Menu, Menubutton
 import tkFont as tkfont
 from idlelib.configHandler import idleConf
@@ -150,7 +151,8 @@
             self.text.insert('end', d, (self.tags, self.chartags))
 
     def handle_charref(self, name):
-        self.text.insert('end', unichr(int(name)))
+        if self.show:
+            self.text.insert('end', unichr(int(name)))
 
 
 class HelpText(Text):
@@ -268,7 +270,7 @@
     if not isfile(filename):
         # try copy_strip, present message
         return
-    HelpWindow(parent, filename, 'IDLE Help')
+    HelpWindow(parent, filename, 'IDLE Help (%s)' % python_version())
 
 if __name__ == '__main__':
     from idlelib.idle_test.htest import run
diff --git a/lib-python/2.7/idlelib/idle.py b/lib-python/2.7/idlelib/idle.py
--- a/lib-python/2.7/idlelib/idle.py
+++ b/lib-python/2.7/idlelib/idle.py
@@ -1,11 +1,13 @@
 import os.path
 import sys
 
-# If we are working on a development version of IDLE, we need to prepend the
-# parent of this idlelib dir to sys.path.  Otherwise, importing idlelib gets
-# the version installed with the Python used to call this module:
+# Enable running IDLE with idlelib in a non-standard location.
+# This was once used to run development versions of IDLE.
+# Because PEP 434 declared idle.py a public interface,
+# removal should require deprecation.
 idlelib_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-sys.path.insert(0, idlelib_dir)
+if idlelib_dir not in sys.path:
+    sys.path.insert(0, idlelib_dir)
 
-import idlelib.PyShell
-idlelib.PyShell.main()
+from idlelib.PyShell import main  # This is subject to change
+main()
diff --git a/lib-python/2.7/idlelib/idle_test/mock_tk.py b/lib-python/2.7/idlelib/idle_test/mock_tk.py
--- a/lib-python/2.7/idlelib/idle_test/mock_tk.py
+++ b/lib-python/2.7/idlelib/idle_test/mock_tk.py
@@ -1,6 +1,6 @@
 """Classes that replace tkinter gui objects used by an object being tested.
 
-A gui object is anything with a master or parent paramenter, which is
+A gui object is anything with a master or parent parameter, which is
 typically required in spite of what the doc strings say.
 """
 
diff --git a/lib-python/2.7/idlelib/idle_test/test_autocomplete.py b/lib-python/2.7/idlelib/idle_test/test_autocomplete.py
--- a/lib-python/2.7/idlelib/idle_test/test_autocomplete.py
+++ b/lib-python/2.7/idlelib/idle_test/test_autocomplete.py
@@ -4,7 +4,6 @@
 
 import idlelib.AutoComplete as ac
 import idlelib.AutoCompleteWindow as acw
-import idlelib.macosxSupport as mac
 from idlelib.idle_test.mock_idle import Func
 from idlelib.idle_test.mock_tk import Event
 
@@ -27,7 +26,6 @@
     def setUpClass(cls):
         requires('gui')
         cls.root = Tk()
-        mac.setupApp(cls.root, None)
         cls.text = Text(cls.root)
         cls.editor = DummyEditwin(cls.root, cls.text)
 
diff --git a/lib-python/2.7/idlelib/idle_test/test_configdialog.py b/lib-python/2.7/idlelib/idle_test/test_configdialog.py
--- a/lib-python/2.7/idlelib/idle_test/test_configdialog.py
+++ b/lib-python/2.7/idlelib/idle_test/test_configdialog.py
@@ -16,6 +16,7 @@
     def setUpClass(cls):
         requires('gui')
         cls.root = Tk()
+        cls.root.withdraw()
         _initializeTkVariantTests(cls.root)
 
     @classmethod
diff --git a/lib-python/2.7/idlelib/idle_test/test_editmenu.py b/lib-python/2.7/idlelib/idle_test/test_editmenu.py
--- a/lib-python/2.7/idlelib/idle_test/test_editmenu.py
+++ b/lib-python/2.7/idlelib/idle_test/test_editmenu.py
@@ -7,15 +7,18 @@
 import unittest
 from idlelib import PyShell
 
+
 class PasteTest(unittest.TestCase):
     '''Test pasting into widgets that allow pasting.
 
     On X11, replacing selections requires tk fix.
     '''
+
     @classmethod
     def setUpClass(cls):
         requires('gui')
         cls.root = root = tk.Tk()
+        root.withdraw()
         PyShell.fix_x11_paste(root)
         cls.text = tk.Text(root)
         cls.entry = tk.Entry(root)
diff --git a/lib-python/2.7/idlelib/idle_test/test_formatparagraph.py b/lib-python/2.7/idlelib/idle_test/test_formatparagraph.py
--- a/lib-python/2.7/idlelib/idle_test/test_formatparagraph.py
+++ b/lib-python/2.7/idlelib/idle_test/test_formatparagraph.py
@@ -159,7 +159,7 @@
 class ReformatFunctionTest(unittest.TestCase):
     """Test the reformat_paragraph function without the editor window."""
 
-    def test_reformat_paragrah(self):
+    def test_reformat_paragraph(self):
         Equal = self.assertEqual
         reform = fp.reformat_paragraph
         hw = "O hello world"
diff --git a/lib-python/2.7/idlelib/idle_test/test_hyperparser.py b/lib-python/2.7/idlelib/idle_test/test_hyperparser.py
--- a/lib-python/2.7/idlelib/idle_test/test_hyperparser.py
+++ b/lib-python/2.7/idlelib/idle_test/test_hyperparser.py
@@ -36,6 +36,7 @@
     def setUpClass(cls):
         requires('gui')
         cls.root = Tk()
+        cls.root.withdraw()
         cls.text = Text(cls.root)
         cls.editwin = DummyEditwin(cls.text)
 
diff --git a/lib-python/2.7/idlelib/idle_test/test_idlehistory.py b/lib-python/2.7/idlelib/idle_test/test_idlehistory.py
--- a/lib-python/2.7/idlelib/idle_test/test_idlehistory.py
+++ b/lib-python/2.7/idlelib/idle_test/test_idlehistory.py
@@ -68,6 +68,7 @@
     def setUpClass(cls):
         requires('gui')
         cls.root = tk.Tk()
+        cls.root.withdraw()
 
     def setUp(self):
         self.text = text = TextWrapper(self.root)
diff --git a/lib-python/2.7/idlelib/idle_test/test_textview.py b/lib-python/2.7/idlelib/idle_test/test_textview.py
--- a/lib-python/2.7/idlelib/idle_test/test_textview.py
+++ b/lib-python/2.7/idlelib/idle_test/test_textview.py
@@ -8,7 +8,11 @@
 from idlelib.idle_test.mock_idle import Func
 from idlelib.idle_test.mock_tk import Mbox
 
-orig_mbox = tv.tkMessageBox
+
+class TV(tv.TextViewer):  # Use in TextViewTest
+    transient = Func()
+    grab_set = Func()
+    wait_window = Func()
 
 class textviewClassTest(unittest.TestCase):
 
@@ -16,26 +20,19 @@
     def setUpClass(cls):
         requires('gui')
         cls.root = Tk()
-        cls.TV = TV = tv.TextViewer
-        TV.transient = Func()
-        TV.grab_set = Func()
-        TV.wait_window = Func()
+        cls.root.withdraw()
 
     @classmethod
     def tearDownClass(cls):
-        del cls.TV
         cls.root.destroy()
         del cls.root
 
     def setUp(self):
-        TV = self.TV
         TV.transient.__init__()
         TV.grab_set.__init__()
         TV.wait_window.__init__()
 
-
     def test_init_modal(self):
-        TV = self.TV
         view = TV(self.root, 'Title', 'test text')
         self.assertTrue(TV.transient.called)
         self.assertTrue(TV.grab_set.called)
@@ -43,7 +40,6 @@
         view.Ok()
 
     def test_init_nonmodal(self):
-        TV = self.TV
         view = TV(self.root, 'Title', 'test text', modal=False)
         self.assertFalse(TV.transient.called)
         self.assertFalse(TV.grab_set.called)
@@ -51,32 +47,36 @@
         view.Ok()
 
     def test_ok(self):
-        view = self.TV(self.root, 'Title', 'test text', modal=False)
+        view = TV(self.root, 'Title', 'test text', modal=False)
         view.destroy = Func()
         view.Ok()
         self.assertTrue(view.destroy.called)
-        del view.destroy  # unmask real function
-        view.destroy
+        del view.destroy  # Unmask the real function.
+        view.destroy()
 
 
-class textviewTest(unittest.TestCase):
+class ViewFunctionTest(unittest.TestCase):
 
     @classmethod
     def setUpClass(cls):
         requires('gui')
         cls.root = Tk()
+        cls.root.withdraw()
+        cls.orig_mbox = tv.tkMessageBox
         tv.tkMessageBox = Mbox
 
     @classmethod
     def tearDownClass(cls):
         cls.root.destroy()
         del cls.root
-        tv.tkMessageBox = orig_mbox
+        tv.tkMessageBox = cls.orig_mbox
+        del cls.orig_mbox
 
     def test_view_text(self):
-        # If modal True, tkinter will error with 'can't invoke "event" command'
+        # If modal True, get tkinter error 'can't invoke "event" command'.
         view = tv.view_text(self.root, 'Title', 'test text', modal=False)
         self.assertIsInstance(view, tv.TextViewer)
+        view.Ok()
 
     def test_view_file(self):
         test_dir = os.path.dirname(__file__)
@@ -86,10 +86,11 @@
         self.assertIn('Test', view.textView.get('1.0', '1.end'))
         view.Ok()
 
-        # Mock messagebox will be used and view_file will not return anything
+        # Mock messagebox will be used; view_file will return None.
         testfile = os.path.join(test_dir, '../notthere.py')
         view = tv.view_file(self.root, 'Title', testfile, modal=False)
         self.assertIsNone(view)
 
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/lib-python/2.7/idlelib/idle_test/test_widgetredir.py b/lib-python/2.7/idlelib/idle_test/test_widgetredir.py
--- a/lib-python/2.7/idlelib/idle_test/test_widgetredir.py
+++ b/lib-python/2.7/idlelib/idle_test/test_widgetredir.py
@@ -15,6 +15,7 @@
     def setUpClass(cls):
         requires('gui')
         cls.root = Tk()
+        cls.root.withdraw()
         cls.text = Text(cls.root)
 
     @classmethod
@@ -44,6 +45,7 @@
     def setUpClass(cls):
         requires('gui')
         cls.root = Tk()
+        cls.root.withdraw()
         cls.text = Text(cls.root)
 
     @classmethod
diff --git a/lib-python/2.7/inspect.py b/lib-python/2.7/inspect.py
--- a/lib-python/2.7/inspect.py
+++ b/lib-python/2.7/inspect.py
@@ -155,9 +155,8 @@
 def isgeneratorfunction(object):
     """Return true if the object is a user-defined generator function.
 
-    Generator function objects provides same attributes as functions.
-
-    See help(isfunction) for attributes listing."""
+    Generator function objects provide the same attributes as functions.
+    See help(isfunction) for a list of attributes."""
     return bool((isfunction(object) or ismethod(object)) and
                 object.func_code.co_flags & CO_GENERATOR)
 
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
@@ -19,7 +19,7 @@
 Another IOBase subclass, TextIOBase, deals with the encoding and decoding
 of streams into text. TextIOWrapper, which extends it, is a buffered text
 interface to a buffered raw stream (`BufferedIOBase`). Finally, StringIO
-is a in-memory stream for text.
+is an in-memory stream for text.
 
 Argument names are not part of the specification, and only the arguments
 of open() are intended to be used as keyword arguments.
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
@@ -138,7 +138,7 @@
     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.
+    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
@@ -169,7 +169,7 @@
     ``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
+    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
@@ -234,7 +234,7 @@
     ``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
+    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
@@ -330,7 +330,7 @@
     for JSON integers (e.g. float).
 
     ``parse_constant``, if specified, will be called with one of the
-    following strings: -Infinity, Infinity, NaN, null, true, false.
+    following strings: -Infinity, Infinity, NaN.
     This can be used to raise an exception if invalid JSON numbers
     are encountered.
 
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
@@ -35,7 +35,7 @@
     ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
 
 INFINITY = float('inf')
-FLOAT_REPR = repr
+FLOAT_REPR = float.__repr__
 
 def raw_encode_basestring(s):
     """Return a JSON representation of a Python string
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
@@ -43,7 +43,7 @@
         self.assertEqual(self.loads(s, object_pairs_hook=OrderedDict,
                                     object_hook=lambda x: None),
                          OrderedDict(p))
-        # check that empty objects literals work (see #17368)
+        # check that empty object literals work (see #17368)
         self.assertEqual(self.loads('{}', object_pairs_hook=OrderedDict),
                          OrderedDict())
         self.assertEqual(self.loads('{"empty": {}}',
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
@@ -32,6 +32,17 @@
                 self.assertNotEqual(res[0], res[0])
             self.assertRaises(ValueError, self.dumps, [val], allow_nan=False)
 
+    def test_float_subclasses_use_float_repr(self):
+        # Issue 27934.
+        class PeculiarFloat(float):
+            def __repr__(self):
+                return "I'm not valid JSON"
+            def __str__(self):
+                return "Neither am I"
+
+        val = PeculiarFloat(3.2)
+        self.assertEqual(self.loads(self.dumps(val)), val)
+
 
 class TestPyFloat(TestFloat, PyTest): pass
 class TestCFloat(TestFloat, CTest): pass
diff --git a/lib-python/2.7/lib-tk/Tix.py b/lib-python/2.7/lib-tk/Tix.py
--- a/lib-python/2.7/lib-tk/Tix.py
+++ b/lib-python/2.7/lib-tk/Tix.py
@@ -26,8 +26,10 @@
 # appreciate the advantages.
 #
 
+import os
+import Tkinter
 from Tkinter import *
-from Tkinter import _flatten, _cnfmerge, _default_root
+from Tkinter import _flatten, _cnfmerge
 
 # WARNING - TkVersion is a limited precision floating point number
 if TkVersion < 3.999:
@@ -72,7 +74,6 @@
 # BEWARE - this is implemented by copying some code from the Widget class
 #          in Tkinter (to override Widget initialization) and is therefore
 #          liable to break.
-import Tkinter, os
 
 # Could probably add this to Tkinter.Misc
 class tixCommand:
@@ -476,10 +477,14 @@
     (multiple) Display Items"""
 
     def __init__(self, itemtype, cnf={}, **kw):
-        master = _default_root              # global from Tkinter
-        if not master and 'refwindow' in cnf: master=cnf['refwindow']
-        elif not master and 'refwindow' in kw:  master= kw['refwindow']
-        elif not master: raise RuntimeError, "Too early to create display style: no root window"
+        if 'refwindow' in kw:
+            master = kw['refwindow']
+        elif 'refwindow' in cnf:
+            master = cnf['refwindow']
+        else:
+            master = Tkinter._default_root
+            if not master:
+                raise RuntimeError("Too early to create display style: no root window")
         self.tk = master.tk
         self.stylename = self.tk.call('tixDisplayStyle', itemtype,
                             *self._options(cnf,kw) )
@@ -923,7 +928,11 @@
         return self.tk.call(self._w, 'header', 'cget', col, opt)
 
     def header_exists(self,  col):
-        return self.tk.call(self._w, 'header', 'exists', col)
+        # A workaround to Tix library bug (issue #25464).
+        # The documented command is "exists", but only erroneous "exist" is
+        # accepted.
+        return self.tk.getboolean(self.tk.call(self._w, 'header', 'exist', col))
+    header_exist = header_exists
 
     def header_delete(self, col):
         self.tk.call(self._w, 'header', 'delete', col)
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


More information about the pypy-commit mailing list