merge 2.7.10 release branch
diff --git a/Doc/c-api/iter.rst b/Doc/c-api/iter.rst
index 8d1567c..fb2a71c 100644
--- a/Doc/c-api/iter.rst
+++ b/Doc/c-api/iter.rst
@@ -14,6 +14,10 @@
Return true if the object *o* supports the iterator protocol.
+ This function can return a false positive in the case of old-style
+ classes because those classes always define a :c:member:`tp_iternext`
+ slot with logic that either invokes a :meth:`next` method or raises
+ a :exc:`TypeError`.
.. c:function:: PyObject* PyIter_Next(PyObject *o)
diff --git a/Doc/faq/gui.rst b/Doc/faq/gui.rst
index 5e1d8be..44e5908 100644
--- a/Doc/faq/gui.rst
+++ b/Doc/faq/gui.rst
@@ -125,30 +125,11 @@
Can I have Tk events handled while waiting for I/O?
---------------------------------------------------
-Yes, and you don't even need threads! But you'll have to restructure your I/O
+On platforms other than Windows, yes, and you don't even
+need threads! But you'll have to restructure your I/O
code a bit. Tk has the equivalent of Xt's :c:func:`XtAddInput()` call, which allows you
to register a callback function which will be called from the Tk mainloop when
-I/O is possible on a file descriptor. Here's what you need::
-
- from Tkinter import tkinter
- tkinter.createfilehandler(file, mask, callback)
-
-The file may be a Python file or socket object (actually, anything with a
-fileno() method), or an integer file descriptor. The mask is one of the
-constants tkinter.READABLE or tkinter.WRITABLE. The callback is called as
-follows::
-
- callback(file, mask)
-
-You must unregister the callback when you're done, using ::
-
- tkinter.deletefilehandler(file)
-
-Note: since you don't know *how many bytes* are available for reading, you can't
-use the Python file object's read or readline methods, since these will insist
-on reading a predefined number of bytes. For sockets, the :meth:`recv` or
-:meth:`recvfrom` methods will work fine; for other files, use
-``os.read(file.fileno(), maxbytecount)``.
+I/O is possible on a file descriptor. See :ref:`tkinter-file-handlers`.
I can't get key bindings to work in Tkinter: why?
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index b947e27..e08eb51 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -104,9 +104,9 @@
.. method:: most_common([n])
Return a list of the *n* most common elements and their counts from the
- most common to the least. If *n* is not specified, :func:`most_common`
- returns *all* elements in the counter. Elements with equal counts are
- ordered arbitrarily:
+ most common to the least. If *n* is omitted or ``None``,
+ :func:`most_common` returns *all* elements in the counter.
+ Elements with equal counts are ordered arbitrarily:
>>> Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]
diff --git a/Doc/library/math.rst b/Doc/library/math.rst
index 562388e..22d2316 100644
--- a/Doc/library/math.rst
+++ b/Doc/library/math.rst
@@ -280,12 +280,12 @@
.. function:: degrees(x)
- Converts angle *x* from radians to degrees.
+ Convert angle *x* from radians to degrees.
.. function:: radians(x)
- Converts angle *x* from degrees to radians.
+ Convert angle *x* from degrees to radians.
Hyperbolic functions
diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst
index 846f96e..fa60c15 100644
--- a/Doc/library/tkinter.rst
+++ b/Doc/library/tkinter.rst
@@ -817,3 +817,53 @@
deleted, the image data is deleted as well, and Tk will display an empty box
wherever the image was used.
+
+.. _tkinter-file-handlers:
+
+File Handlers
+-------------
+
+Tk allows you to register and unregister a callback function which will be
+called from the Tk mainloop when I/O is possible on a file descriptor.
+Only one handler may be registered per file descriptor. Example code::
+
+ import Tkinter
+ widget = Tkinter.Tk()
+ mask = Tkinter.READABLE | Tkinter.WRITABLE
+ widget.tk.createfilehandler(file, mask, callback)
+ ...
+ widget.tk.deletefilehandler(file)
+
+This feature is not available on Windows.
+
+Since you don't know how many bytes are available for reading, you may not
+want to use the :class:`~io.BufferedIOBase` or :class:`~io.TextIOBase`
+:meth:`~io.BufferedIOBase.read` or :meth:`~io.IOBase.readline` methods,
+since these will insist on reading a predefined number of bytes.
+For sockets, the :meth:`~socket.socket.recv` or
+:meth:`~socket.socket.recvfrom` methods will work fine; for other files,
+use raw reads or ``os.read(file.fileno(), maxbytecount)``.
+
+
+.. method:: Widget.tk.createfilehandler(file, mask, func)
+
+ Registers the file handler callback function *func*. The *file* argument
+ may either be an object with a :meth:`~io.IOBase.fileno` method (such as
+ a file or socket object), or an integer file descriptor. The *mask*
+ argument is an ORed combination of any of the three constants below.
+ The callback is called as follows::
+
+ callback(file, mask)
+
+
+.. method:: Widget.tk.deletefilehandler(file)
+
+ Unregisters a file handler.
+
+
+.. data:: READABLE
+ WRITABLE
+ EXCEPTION
+
+ Constants used in the *mask* arguments.
+
diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py
index c11e84b..513b3e5 100644
--- a/Lib/email/test/test_email.py
+++ b/Lib/email/test/test_email.py
@@ -12,6 +12,10 @@
import textwrap
from cStringIO import StringIO
from random import choice
+try:
+ from threading import Thread
+except ImportError:
+ from dummy_threading import Thread
import email
@@ -33,7 +37,7 @@
from email import base64MIME
from email import quopriMIME
-from test.test_support import findfile, run_unittest
+from test.test_support import findfile, run_unittest, start_threads
from email.test import __file__ as landmark
@@ -2412,6 +2416,25 @@
addrs = Utils.getaddresses(['User ((nested comment)) <foo@bar.com>'])
eq(addrs[0][1], 'foo@bar.com')
+ def test_make_msgid_collisions(self):
+ # Test make_msgid uniqueness, even with multiple threads
+ class MsgidsThread(Thread):
+ def run(self):
+ # generate msgids for 3 seconds
+ self.msgids = []
+ append = self.msgids.append
+ make_msgid = Utils.make_msgid
+ clock = time.clock
+ tfin = clock() + 3.0
+ while clock() < tfin:
+ append(make_msgid())
+
+ threads = [MsgidsThread() for i in range(5)]
+ with start_threads(threads):
+ pass
+ all_ids = sum([t.msgids for t in threads], [])
+ self.assertEqual(len(set(all_ids)), len(all_ids))
+
def test_utils_quote_unquote(self):
eq = self.assertEqual
msg = Message()
diff --git a/Lib/email/utils.py b/Lib/email/utils.py
index c976021..ac13f49 100644
--- a/Lib/email/utils.py
+++ b/Lib/email/utils.py
@@ -177,21 +177,20 @@
def make_msgid(idstring=None):
"""Returns a string suitable for RFC 2822 compliant Message-ID, e.g:
- <20020201195627.33539.96671@nightshade.la.mastaler.com>
+ <142480216486.20800.16526388040877946887@nightshade.la.mastaler.com>
Optional idstring if given is a string used to strengthen the
uniqueness of the message id.
"""
- timeval = time.time()
- utcdate = time.strftime('%Y%m%d%H%M%S', time.gmtime(timeval))
+ timeval = int(time.time()*100)
pid = os.getpid()
- randint = random.randrange(100000)
+ randint = random.getrandbits(64)
if idstring is None:
idstring = ''
else:
idstring = '.' + idstring
idhost = socket.getfqdn()
- msgid = '<%s.%s.%s%s@%s>' % (utcdate, pid, randint, idstring, idhost)
+ msgid = '<%d.%d.%d%s@%s>' % (timeval, pid, randint, idstring, idhost)
return msgid
diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py
index e7df79a..4244299 100644
--- a/Lib/ensurepip/__init__.py
+++ b/Lib/ensurepip/__init__.py
@@ -12,9 +12,9 @@
__all__ = ["version", "bootstrap"]
-_SETUPTOOLS_VERSION = "15.2"
+_SETUPTOOLS_VERSION = "16.0"
-_PIP_VERSION = "6.1.1"
+_PIP_VERSION = "7.0.1"
# pip currently requires ssl support, so we try to provide a nicer
# error message when that is missing (http://bugs.python.org/issue19744)
diff --git a/Lib/ensurepip/_bundled/pip-6.1.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.0.1-py2.py3-none-any.whl
similarity index 75%
rename from Lib/ensurepip/_bundled/pip-6.1.1-py2.py3-none-any.whl
rename to Lib/ensurepip/_bundled/pip-7.0.1-py2.py3-none-any.whl
index e59694a..30a61f0 100644
--- a/Lib/ensurepip/_bundled/pip-6.1.1-py2.py3-none-any.whl
+++ b/Lib/ensurepip/_bundled/pip-7.0.1-py2.py3-none-any.whl
Binary files differ
diff --git a/Lib/ensurepip/_bundled/setuptools-15.2-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-16.0-py2.py3-none-any.whl
similarity index 84%
rename from Lib/ensurepip/_bundled/setuptools-15.2-py2.py3-none-any.whl
rename to Lib/ensurepip/_bundled/setuptools-16.0-py2.py3-none-any.whl
index f153ed3..fa4e994 100644
--- a/Lib/ensurepip/_bundled/setuptools-15.2-py2.py3-none-any.whl
+++ b/Lib/ensurepip/_bundled/setuptools-16.0-py2.py3-none-any.whl
Binary files differ
diff --git a/Lib/httplib.py b/Lib/httplib.py
index 9f1e088..30fc525 100644
--- a/Lib/httplib.py
+++ b/Lib/httplib.py
@@ -1063,7 +1063,7 @@
elif body is not None:
try:
thelen = str(len(body))
- except TypeError:
+ except (TypeError, AttributeError):
# If this is a file-like object, try to
# fstat its file descriptor
try:
diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py
index d34fc62..0a95293 100644
--- a/Lib/idlelib/EditorWindow.py
+++ b/Lib/idlelib/EditorWindow.py
@@ -9,7 +9,6 @@
import webbrowser
from idlelib.MultiCall import MultiCallCreator
-from idlelib import idlever
from idlelib import WindowList
from idlelib import SearchDialog
from idlelib import GrepDialog
@@ -154,7 +153,6 @@
EditorWindow.help_url = 'file://' + EditorWindow.help_url
else:
EditorWindow.help_url = "https://docs.python.org/%d.%d/" % sys.version_info[:2]
- currentTheme=idleConf.CurrentTheme()
self.flist = flist
root = root or flist.root
self.root = root
diff --git a/Lib/idlelib/GrepDialog.py b/Lib/idlelib/GrepDialog.py
index afb9a21..b038c9c 100644
--- a/Lib/idlelib/GrepDialog.py
+++ b/Lib/idlelib/GrepDialog.py
@@ -5,7 +5,6 @@
from Tkinter import StringVar, BooleanVar, Checkbutton # for GrepDialog
from Tkinter import Tk, Text, Button, SEL, END # for htest
from idlelib import SearchEngine
-import itertools
from idlelib.SearchDialogBase import SearchDialogBase
# Importing OutputWindow fails due to import loop
# EditorWindow -> GrepDialop -> OutputWindow -> EditorWindow
diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py
index e7d747c..db6773f 100644
--- a/Lib/idlelib/IOBinding.py
+++ b/Lib/idlelib/IOBinding.py
@@ -6,7 +6,6 @@
# which will only understand the local convention.
import os
-import types
import pipes
import sys
import codecs
@@ -391,7 +390,7 @@
return False
def encode(self, chars):
- if isinstance(chars, types.StringType):
+ if isinstance(chars, str):
# This is either plain ASCII, or Tk was returning mixed-encoding
# text to us. Don't try to guess further.
return chars
@@ -568,7 +567,7 @@
"Update recent file list on all editor windows"
self.editwin.update_recent_files_list(filename)
-def _io_binding(parent):
+def _io_binding(parent): # htest #
root = Tk()
root.title("Test IOBinding")
width, height, x, y = list(map(int, re.split('[x+]', parent.geometry())))
@@ -591,7 +590,7 @@
text.pack()
text.focus_set()
editwin = MyEditWin(text)
- io = IOBinding(editwin)
+ IOBinding(editwin)
if __name__ == "__main__":
from idlelib.idle_test.htest import run
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
index 79db883..eec5978 100755
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -10,8 +10,6 @@
import socket
import time
import threading
-import traceback
-import types
import io
import linecache
@@ -32,11 +30,11 @@
from idlelib.UndoDelegator import UndoDelegator
from idlelib.OutputWindow import OutputWindow
from idlelib.configHandler import idleConf
-from idlelib import idlever
from idlelib import rpc
from idlelib import Debugger
from idlelib import RemoteDebugger
from idlelib import macosxSupport
+from idlelib import IOBinding
IDENTCHARS = string.ascii_letters + string.digits + "_"
HOST = '127.0.0.1' # python execution server on localhost loopback
@@ -171,7 +169,7 @@
filename = self.io.filename
text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
try:
- i = self.breakpoints.index(lineno)
+ self.breakpoints.index(lineno)
except ValueError: # only add if missing, i.e. do once
self.breakpoints.append(lineno)
try: # update the subprocess debugger
@@ -439,7 +437,7 @@
try:
self.rpcclt = MyRPCClient(addr)
break
- except socket.error as err:
+ except socket.error:
pass
else:
self.display_port_binding_error()
@@ -460,7 +458,7 @@
self.rpcclt.listening_sock.settimeout(10)
try:
self.rpcclt.accept()
- except socket.timeout as err:
+ except socket.timeout:
self.display_no_subprocess_error()
return None
self.rpcclt.register("console", self.tkconsole)
@@ -495,7 +493,7 @@
self.spawn_subprocess()
try:
self.rpcclt.accept()
- except socket.timeout as err:
+ except socket.timeout:
self.display_no_subprocess_error()
return None
self.transfer_path(with_cwd=with_cwd)
@@ -513,7 +511,7 @@
# restart subprocess debugger
if debug:
# Restarted debugger connects to current instance of debug GUI
- gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
+ RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
# reload remote debugger breakpoints for all PyShellEditWindows
debug.load_breakpoints()
self.compile.compiler.flags = self.original_compiler_flags
@@ -654,7 +652,7 @@
if source is None:
source = open(filename, "r").read()
try:
- code = compile(source, filename, "exec")
+ code = compile(source, filename, "exec", dont_inherit=True)
except (OverflowError, SyntaxError):
self.tkconsole.resetoutput()
print('*** Error in script or command!\n'
@@ -671,10 +669,11 @@
self.more = 0
self.save_warnings_filters = warnings.filters[:]
warnings.filterwarnings(action="error", category=SyntaxWarning)
- if isinstance(source, types.UnicodeType):
- from idlelib import IOBinding
+ if isinstance(source, unicode) and IOBinding.encoding != 'utf-8':
try:
- source = source.encode(IOBinding.encoding)
+ source = '# -*- coding: %s -*-\n%s' % (
+ IOBinding.encoding,
+ source.encode(IOBinding.encoding))
except UnicodeError:
self.tkconsole.resetoutput()
self.write("Unsupported characters in input\n")
@@ -1246,7 +1245,7 @@
while i > 0 and line[i-1] in " \t":
i = i-1
line = line[:i]
- more = self.interp.runsource(line)
+ self.interp.runsource(line)
def open_stack_viewer(self, event=None):
if self.interp.rpcclt:
@@ -1260,7 +1259,7 @@
master=self.text)
return
from idlelib.StackViewer import StackBrowser
- sv = StackBrowser(self.root, self.flist)
+ StackBrowser(self.root, self.flist)
def view_restart_mark(self, event=None):
self.text.see("iomark")
diff --git a/Lib/idlelib/RemoteDebugger.py b/Lib/idlelib/RemoteDebugger.py
index 647285f..8c71a21 100644
--- a/Lib/idlelib/RemoteDebugger.py
+++ b/Lib/idlelib/RemoteDebugger.py
@@ -21,7 +21,6 @@
"""
import types
-from idlelib import rpc
from idlelib import Debugger
debugging = 0
@@ -101,7 +100,7 @@
tb = tracebacktable[tbid]
stack, i = self.idb.get_stack(frame, tb)
##print >>sys.__stderr__, "get_stack() ->", stack
- stack = [(wrap_frame(frame), k) for frame, k in stack]
+ stack = [(wrap_frame(frame2), k) for frame2, k in stack]
##print >>sys.__stderr__, "get_stack() ->", stack
return stack, i
diff --git a/Lib/idlelib/SearchDialog.py b/Lib/idlelib/SearchDialog.py
index 2aadb84..043168a 100644
--- a/Lib/idlelib/SearchDialog.py
+++ b/Lib/idlelib/SearchDialog.py
@@ -23,7 +23,7 @@
class SearchDialog(SearchDialogBase):
def create_widgets(self):
- f = SearchDialogBase.create_widgets(self)
+ SearchDialogBase.create_widgets(self)
self.make_button("Find Next", self.default_command, 1)
def default_command(self, event=None):
diff --git a/Lib/idlelib/TreeWidget.py b/Lib/idlelib/TreeWidget.py
index 1e56e86..88083f0 100644
--- a/Lib/idlelib/TreeWidget.py
+++ b/Lib/idlelib/TreeWidget.py
@@ -246,7 +246,7 @@
else:
self.edit_finish()
try:
- label = self.label
+ self.label
except AttributeError:
# padding carefully selected (on Windows) to match Entry widget:
self.label = Label(self.canvas, text=text, bd=0, padx=2, pady=2)
diff --git a/Lib/idlelib/aboutDialog.py b/Lib/idlelib/aboutDialog.py
index 1c3eba1..ef8e2de 100644
--- a/Lib/idlelib/aboutDialog.py
+++ b/Lib/idlelib/aboutDialog.py
@@ -1,12 +1,10 @@
"""About Dialog for IDLE
"""
-
-from Tkinter import *
import os
-
+from sys import version
+from Tkinter import *
from idlelib import textView
-from idlelib import idlever
class AboutDialog(Toplevel):
"""Modal about dialog for idle
@@ -37,6 +35,7 @@
self.wait_window()
def CreateWidgets(self):
+ release = version[:version.index(' ')]
frameMain = Frame(self, borderwidth=2, relief=SUNKEN)
frameButtons = Frame(self)
frameButtons.pack(side=BOTTOM, fill=X)
@@ -63,14 +62,14 @@
labelEmail.grid(row=6, column=0, columnspan=2,
sticky=W, padx=10, pady=0)
labelWWW = Label(frameBg, text='https://docs.python.org/' +
- sys.version[:3] + '/library/idle.html',
+ version[:3] + '/library/idle.html',
justify=LEFT, fg=self.fg, bg=self.bg)
labelWWW.grid(row=7, column=0, columnspan=2, sticky=W, padx=10, pady=0)
Frame(frameBg, borderwidth=1, relief=SUNKEN,
height=2, bg=self.bg).grid(row=8, column=0, sticky=EW,
columnspan=3, padx=5, pady=5)
- labelPythonVer = Label(frameBg, text='Python version: ' + \
- sys.version.split()[0], fg=self.fg, bg=self.bg)
+ labelPythonVer = Label(frameBg, text='Python version: ' +
+ release, fg=self.fg, bg=self.bg)
labelPythonVer.grid(row=9, column=0, sticky=W, padx=10, pady=0)
tkVer = self.tk.call('info', 'patchlevel')
labelTkVer = Label(frameBg, text='Tk version: '+
@@ -93,7 +92,7 @@
Frame(frameBg, borderwidth=1, relief=SUNKEN,
height=2, bg=self.bg).grid(row=11, column=0, sticky=EW,
columnspan=3, padx=5, pady=5)
- idle_v = Label(frameBg, text='IDLE version: ' + idlever.IDLE_VERSION,
+ idle_v = Label(frameBg, text='IDLE version: ' + release,
fg=self.fg, bg=self.bg)
idle_v.grid(row=12, column=0, sticky=W, padx=10, pady=0)
idle_button_f = Frame(frameBg, bg=self.bg)
diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py
index c416151..41b76e8 100644
--- a/Lib/idlelib/configDialog.py
+++ b/Lib/idlelib/configDialog.py
@@ -14,7 +14,6 @@
from idlelib.configHandler import idleConf
from idlelib.dynOptionMenuWidget import DynOptionMenu
-from idlelib.tabbedpages import TabbedPageSet
from idlelib.keybindingDialog import GetKeysDialog
from idlelib.configSectionNameDialog import GetCfgSectionNameDialog
from idlelib.configHelpSourceEdit import GetHelpSourceDialog
diff --git a/Lib/idlelib/idle.pyw b/Lib/idlelib/idle.pyw
index 537dd5a..9ce4c9f 100644
--- a/Lib/idlelib/idle.pyw
+++ b/Lib/idlelib/idle.pyw
@@ -2,20 +2,16 @@
import idlelib.PyShell
except ImportError:
# IDLE is not installed, but maybe PyShell is on sys.path:
- try:
- import PyShell
- except ImportError:
- raise
- else:
- import os
- idledir = os.path.dirname(os.path.abspath(PyShell.__file__))
- if idledir != os.getcwd():
- # We're not in the IDLE directory, help the subprocess find run.py
- pypath = os.environ.get('PYTHONPATH', '')
- if pypath:
- os.environ['PYTHONPATH'] = pypath + ':' + idledir
- else:
- os.environ['PYTHONPATH'] = idledir
- PyShell.main()
+ import PyShell
+ import os
+ idledir = os.path.dirname(os.path.abspath(PyShell.__file__))
+ if idledir != os.getcwd():
+ # We're not in the IDLE directory, help the subprocess find run.py
+ pypath = os.environ.get('PYTHONPATH', '')
+ if pypath:
+ os.environ['PYTHONPATH'] = pypath + ':' + idledir
+ else:
+ os.environ['PYTHONPATH'] = idledir
+ PyShell.main()
else:
idlelib.PyShell.main()
diff --git a/Lib/idlelib/idle_test/README.txt b/Lib/idlelib/idle_test/README.txt
index f6b6a21..2339926 100644
--- a/Lib/idlelib/idle_test/README.txt
+++ b/Lib/idlelib/idle_test/README.txt
@@ -1,14 +1,24 @@
README FOR IDLE TESTS IN IDLELIB.IDLE_TEST
+0. Quick Start
+
+Automated unit tests were added in 2.7 for Python 2.x and 3.3 for Python 3.x.
+To run the tests from a command line:
+
+python -m test.test_idle
+
+Human-mediated tests were added later in 2.7 and in 3.4.
+
+python -m idlelib.idle_test.htest
+
1. Test Files
The idle directory, idlelib, has over 60 xyz.py files. The idle_test
-subdirectory should contain a test_xyy.py for each. (For test modules, make
-'xyz' lower case, and possibly shorten it.) Each file should start with the
-something like the following template, with the blanks after after '.' and 'as',
-and before and after '_' filled in.
----
+subdirectory should contain a test_xyz.py for each, where 'xyz' is lowercased
+even if xyz.py is not. Here is a possible template, with the blanks after after
+'.' and 'as', and before and after '_' to be filled in.
+
import unittest
from test.support import requires
import idlelib. as
@@ -18,33 +28,33 @@
def test_(self):
if __name__ == '__main__':
- unittest.main(verbosity=2, exit=2)
----
-Idle tests are run with unittest; do not use regrtest's test_main.
+ unittest.main(verbosity=2)
-Once test_xyy is written, the following should go at the end of xyy.py,
-with xyz (lowercased) added after 'test_'.
----
+Add the following at the end of xyy.py, with the appropriate name added after
+'test_'. Some files already have something like this for htest. If so, insert
+the import and unittest.main lines before the htest lines.
+
if __name__ == "__main__":
import unittest
unittest.main('idlelib.idle_test.test_', verbosity=2, exit=False)
----
-2. Gui Tests
-Gui tests need 'requires' from test.support (test.test_support in 2.7). A
-test is a gui test if it creates a Tk root or master object either directly
-or indirectly by instantiating a tkinter or idle class. For the benefit of
-test processes that either have no graphical environment available or are not
-allowed to use it, gui tests must be 'guarded' by "requires('gui')" in a
-setUp function or method. This will typically be setUpClass.
+2. GUI Tests
-To avoid interfering with other gui tests, all gui objects must be destroyed
-and deleted by the end of the test. If a widget, such as a Tk root, is created
-in a setUpX function, destroy it in the corresponding tearDownX. For module
-and class attributes, also delete the widget.
----
+When run as part of the Python test suite, Idle gui tests need to run
+test.support.requires('gui') (test.test_support in 2.7). A test is a gui test
+if it creates a Tk root or master object either directly or indirectly by
+instantiating a tkinter or idle class. For the benefit of test processes that
+either have no graphical environment available or are not allowed to use it, gui
+tests must be 'guarded' by "requires('gui')" in a setUp function or method.
+This will typically be setUpClass.
+
+To avoid interfering with other gui tests, all gui objects must be destroyed and
+deleted by the end of the test. Widgets, such as a Tk root, created in a setUpX
+function, should be destroyed in the corresponding tearDownX. Module and class
+widget attributes should also be deleted..
+
@classmethod
def setUpClass(cls):
requires('gui')
@@ -54,49 +64,55 @@
def tearDownClass(cls):
cls.root.destroy()
del cls.root
----
-Support.requires('gui') causes the test(s) it guards to be skipped if any of
+
+Requires('gui') causes the test(s) it guards to be skipped if any of
a few conditions are met:
- - The tests are being run by regrtest.py, and it was started without
- enabling the "gui" resource with the "-u" command line option.
+
+ - The tests are being run by regrtest.py, and it was started without enabling
+ the "gui" resource with the "-u" command line option.
+
- The tests are being run on Windows by a service that is not allowed to
interact with the graphical environment.
+
- The tests are being run on Mac OSX in a process that cannot make a window
manager connection.
+
- tkinter.Tk cannot be successfully instantiated for some reason.
+
- test.support.use_resources has been set by something other than
regrtest.py and does not contain "gui".
-
-Since non-gui tests always run, but gui tests only sometimes, tests of non-gui
-operations should best avoid needing a gui. Methods that make incidental use of
-tkinter (tk) variables and messageboxes can do this by using the mock classes in
-idle_test/mock_tk.py. There is also a mock text that will handle some uses of the
-tk Text widget.
+
+Tests of non-gui operations should avoid creating tk widgets. Incidental uses of
+tk variables and messageboxes can be replaced by the mock classes in
+idle_test/mock_tk.py. The mock text handles some uses of the tk Text widget.
-3. Running Tests
+3. Running Unit Tests
-Assume that xyz.py and test_xyz.py end with the "if __name__" statements given
-above. In Idle, pressing F5 in an editor window with either loaded will run all
-tests in the test_xyz file with the version of Python running Idle. The test
-report and any tracebacks will appear in the Shell window. The options in these
-"if __name__" statements are appropriate for developers running (as opposed to
-importing) either of the files during development: verbosity=2 lists all test
-methods in the file; exit=False avoids a spurious sys.exit traceback that would
-otherwise occur when running in Idle. The following command lines also run
-all test methods, including gui tests, in test_xyz.py. (The exceptions are that
-idlelib and idlelib.idle start Idle and idlelib.PyShell should (issue 18330).)
+Assume that xyz.py and test_xyz.py both end with a unittest.main() call.
+Running either from an Idle editor runs all tests in the test_xyz file with the
+version of Python running Idle. Test output appears in the Shell window. The
+'verbosity=2' option lists all test methods in the file, which is appropriate
+when developing tests. The 'exit=False' option is needed in xyx.py files when an
+htest follows.
-python -m idlelib.xyz # With the capitalization of the xyz module
+The following command lines also run all test methods, including
+gui tests, in test_xyz.py. (Both '-m idlelib' and '-m idlelib.idle' start
+Idle and so cannot run tests.)
+
+python -m idlelib.xyz
python -m idlelib.idle_test.test_xyz
-To run all idle_test/test_*.py tests, either interactively
-('>>>', with unittest imported) or from a command line, use one of the
-following. (Notes: in 2.7, 'test ' (with the space) is 'test.regrtest ';
-where present, -v and -ugui can be omitted.)
+The following runs all idle_test/test_*.py tests interactively.
->>> unittest.main('idlelib.idle_test', verbosity=2, exit=False)
+>>> import unittest
+>>> unittest.main('idlelib.idle_test', verbosity=2)
+
+The following run all Idle tests at a command line. Option '-v' is the same as
+'verbosity=2'. (For 2.7, replace 'test' in the second line with
+'test.regrtest'.)
+
python -m unittest -v idlelib.idle_test
python -m test -v -ugui test_idle
python -m test.test_idle
@@ -113,3 +129,15 @@
unittest on the command line.
python -m unittest -v idlelib.idle_test.test_xyz.Test_case.test_meth
+
+
+4. Human-mediated Tests
+
+Human-mediated tests are widget tests that cannot be automated but need human
+verification. They are contained in idlelib/idle_test/htest.py, which has
+instructions. (Some modules need an auxiliary function, identified with # htest
+# on the header line.) The set is about complete, though some tests need
+improvement. To run all htests, run the htest file from an editor or from the
+command line with:
+
+python -m idlelib.idle_test.htest
diff --git a/Lib/idlelib/idle_test/test_autocomplete.py b/Lib/idlelib/idle_test/test_autocomplete.py
index ee9d0ed..c2a7266 100644
--- a/Lib/idlelib/idle_test/test_autocomplete.py
+++ b/Lib/idlelib/idle_test/test_autocomplete.py
@@ -1,6 +1,6 @@
import unittest
from test.test_support import requires
-from Tkinter import Tk, Text, TclError
+from Tkinter import Tk, Text
import idlelib.AutoComplete as ac
import idlelib.AutoCompleteWindow as acw
@@ -95,8 +95,8 @@
del ev.mc_state
# If autocomplete window is open, complete() method is called
- testwin = self.autocomplete._make_autocomplete_window()
self.text.insert('1.0', 're.')
+ # This must call autocomplete._make_autocomplete_window()
Equal(self.autocomplete.autocomplete_event(ev), 'break')
# If autocomplete window is not active or does not exist,
diff --git a/Lib/idlelib/idle_test/test_formatparagraph.py b/Lib/idlelib/idle_test/test_formatparagraph.py
index 07bbf16..9185a96 100644
--- a/Lib/idlelib/idle_test/test_formatparagraph.py
+++ b/Lib/idlelib/idle_test/test_formatparagraph.py
@@ -2,7 +2,7 @@
import unittest
from idlelib import FormatParagraph as fp
from idlelib.EditorWindow import EditorWindow
-from Tkinter import Tk, Text, TclError
+from Tkinter import Tk, Text
from test.test_support import requires
diff --git a/Lib/idlelib/idle_test/test_searchdialogbase.py b/Lib/idlelib/idle_test/test_searchdialogbase.py
index c1bee3e..32abfe6 100644
--- a/Lib/idlelib/idle_test/test_searchdialogbase.py
+++ b/Lib/idlelib/idle_test/test_searchdialogbase.py
@@ -6,14 +6,13 @@
'''
import unittest
from test.test_support import requires
-from Tkinter import Tk, Toplevel, Frame, Label, BooleanVar, StringVar
+from Tkinter import Tk, Toplevel, Frame ## BooleanVar, StringVar
from idlelib import SearchEngine as se
from idlelib import SearchDialogBase as sdb
from idlelib.idle_test.mock_idle import Func
-from idlelib.idle_test.mock_tk import Var, Mbox
+##from idlelib.idle_test.mock_tk import Var
-# The following could help make some tests gui-free.
-# However, they currently make radiobutton tests fail.
+# The ## imports above & following could help make some tests gui-free.# However, they currently make radiobutton tests fail.
##def setUpModule():
## # Replace tk objects used to initialize se.SearchEngine.
## se.BooleanVar = Var
diff --git a/Lib/idlelib/idle_test/test_searchengine.py b/Lib/idlelib/idle_test/test_searchengine.py
index 2525a13..8bf9d47 100644
--- a/Lib/idlelib/idle_test/test_searchengine.py
+++ b/Lib/idlelib/idle_test/test_searchengine.py
@@ -7,7 +7,7 @@
import re
import unittest
-from test.test_support import requires
+#from test.test_support import requires
from Tkinter import BooleanVar, StringVar, TclError # ,Tk, Text
import tkMessageBox
from idlelib import SearchEngine as se
diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py
index f0b9b76..50d3fac 100644
--- a/Lib/idlelib/idle_test/test_text.py
+++ b/Lib/idlelib/idle_test/test_text.py
@@ -3,7 +3,6 @@
from test.test_support import requires
from _tkinter import TclError
-import Tkinter as tk
class TextTest(object):
diff --git a/Lib/idlelib/macosxSupport.py b/Lib/idlelib/macosxSupport.py
index 10a06bb..60f5cc4 100644
--- a/Lib/idlelib/macosxSupport.py
+++ b/Lib/idlelib/macosxSupport.py
@@ -125,11 +125,9 @@
#
# Due to a (mis-)feature of TkAqua the user will also see an empty Help
# menu.
- from Tkinter import Menu, Text, Text
- from idlelib.EditorWindow import prepstr, get_accelerator
+ from Tkinter import Menu
from idlelib import Bindings
from idlelib import WindowList
- from idlelib.MultiCall import MultiCallCreator
closeItem = Bindings.menudefs[0][1][-2]
diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py
index 8f611a3..5c4aabd 100644
--- a/Lib/idlelib/rpc.py
+++ b/Lib/idlelib/rpc.py
@@ -332,10 +332,7 @@
n = self.sock.send(s[:BUFSIZE])
except (AttributeError, TypeError):
raise IOError, "socket no longer exists"
- except socket.error:
- raise
- else:
- s = s[n:]
+ s = s[n:]
buffer = ""
bufneed = 4
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index 604c5cd..d023e28 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -1,5 +1,4 @@
import sys
-import io
import linecache
import time
import socket
@@ -211,6 +210,8 @@
fn, ln, nm, line = tb[i]
if nm == '?':
nm = "-toplevel-"
+ if fn.startswith("<pyshell#") and IOBinding.encoding != 'utf-8':
+ ln -= 1 # correction for coding cookie
if not line and fn.startswith("<pyshell#"):
line = rpchandler.remotecall('linecache', 'getline',
(fn, ln), {})
diff --git a/Lib/lib2to3/refactor.py b/Lib/lib2to3/refactor.py
index a4c168d..bd23897 100644
--- a/Lib/lib2to3/refactor.py
+++ b/Lib/lib2to3/refactor.py
@@ -255,7 +255,7 @@
fixer = fix_class(self.options, self.fixer_log)
if fixer.explicit and self.explicit is not True and \
fix_mod_path not in self.explicit:
- self.log_message("Skipping implicit fixer: %s", fix_name)
+ self.log_message("Skipping optional fixer: %s", fix_name)
continue
self.log_debug("Adding transformation: %s", fix_name)
diff --git a/Lib/sqlite3/test/factory.py b/Lib/sqlite3/test/factory.py
index 0813a13..f4b8428 100644
--- a/Lib/sqlite3/test/factory.py
+++ b/Lib/sqlite3/test/factory.py
@@ -170,6 +170,14 @@
self.assertEqual(list(reversed(row)), list(reversed(as_tuple)))
self.assertIsInstance(row, Sequence)
+ def CheckFakeCursorClass(self):
+ # Issue #24257: Incorrect use of PyObject_IsInstance() caused
+ # segmentation fault.
+ class FakeCursor(str):
+ __class__ = sqlite.Cursor
+ cur = self.con.cursor(factory=FakeCursor)
+ self.assertRaises(TypeError, sqlite.Row, cur, ())
+
def tearDown(self):
self.con.close()
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index fbda8eb..184dfc1 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -205,9 +205,14 @@
_os.unlink(filename)
return dir
except (OSError, IOError) as e:
- if e.args[0] != _errno.EEXIST:
- break # no point trying more names in this directory
- pass
+ if e.args[0] == _errno.EEXIST:
+ continue
+ if (_os.name == 'nt' and e.args[0] == _errno.EACCES and
+ _os.path.isdir(dir) and _os.access(dir, _os.W_OK)):
+ # On windows, when a directory with the chosen name already
+ # exists, EACCES error code is returned instead of EEXIST.
+ continue
+ break # no point trying more names in this directory
raise IOError, (_errno.ENOENT,
("No usable temporary directory found in %s" % dirlist))
@@ -242,7 +247,8 @@
except OSError, e:
if e.errno == _errno.EEXIST:
continue # try again
- if _os.name == 'nt' and e.errno == _errno.EACCES:
+ if (_os.name == 'nt' and e.errno == _errno.EACCES and
+ _os.path.isdir(dir) and _os.access(dir, _os.W_OK)):
# On windows, when a directory with the chosen name already
# exists, EACCES error code is returned instead of EEXIST.
continue
@@ -335,6 +341,11 @@
except OSError, e:
if e.errno == _errno.EEXIST:
continue # try again
+ if (_os.name == 'nt' and e.errno == _errno.EACCES and
+ _os.path.isdir(dir) and _os.access(dir, _os.W_OK)):
+ # On windows, when a directory with the chosen name already
+ # exists, EACCES error code is returned instead of EEXIST.
+ continue
raise
raise IOError, (_errno.EEXIST, "No usable temporary directory name found")
diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py
index f5e4e0e..f4673d4 100644
--- a/Lib/test/seq_tests.py
+++ b/Lib/test/seq_tests.py
@@ -84,6 +84,14 @@
'Test multiple tiers of iterators'
return chain(imap(lambda x:x, iterfunc(IterGen(Sequence(seqn)))))
+class LyingTuple(tuple):
+ def __iter__(self):
+ yield 1
+
+class LyingList(list):
+ def __iter__(self):
+ yield 1
+
class CommonTest(unittest.TestCase):
# The type to be tested
type2test = None
@@ -130,6 +138,10 @@
self.assertRaises(TypeError, self.type2test, IterNoNext(s))
self.assertRaises(ZeroDivisionError, self.type2test, IterGenExc(s))
+ # Issue #23757
+ self.assertEqual(self.type2test(LyingTuple((2,))), self.type2test((1,)))
+ self.assertEqual(self.type2test(LyingList([2])), self.type2test([1]))
+
def test_truth(self):
self.assertFalse(self.type2test())
self.assertTrue(self.type2test([42]))
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index b933cbf..7256b94 100644
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -26,7 +26,17 @@
self.assertRaises(TypeError, array.array)
self.assertRaises(TypeError, array.array, spam=42)
self.assertRaises(TypeError, array.array, 'xx')
+ self.assertRaises(TypeError, array.array, '')
+ self.assertRaises(TypeError, array.array, 1)
self.assertRaises(ValueError, array.array, 'x')
+ self.assertRaises(ValueError, array.array, '\x80')
+
+ @test_support.requires_unicode
+ def test_unicode_constructor(self):
+ self.assertRaises(TypeError, array.array, u'xx')
+ self.assertRaises(TypeError, array.array, u'')
+ self.assertRaises(ValueError, array.array, u'x')
+ self.assertRaises(ValueError, array.array, u'\x80')
tests.append(BadConstructorTest)
@@ -1039,6 +1049,17 @@
minitemsize = 4
tests.append(UnsignedLongTest)
+
+@test_support.requires_unicode
+class UnicodeTypecodeTest(unittest.TestCase):
+ def test_unicode_typecode(self):
+ for typecode in typecodes:
+ a = array.array(unicode(typecode))
+ self.assertEqual(a.typecode, typecode)
+ self.assertIs(type(a.typecode), str)
+tests.append(UnicodeTypecodeTest)
+
+
class FPTest(NumberTest):
example = [-42.0, 0, 42, 1e5, -1e10]
smallerexample = [-42.0, 0, 42, 1e5, -2e10]
diff --git a/Lib/test/test_codeccallbacks.py b/Lib/test/test_codeccallbacks.py
index b9cd9c2..c11affd 100644
--- a/Lib/test/test_codeccallbacks.py
+++ b/Lib/test/test_codeccallbacks.py
@@ -836,6 +836,26 @@
text = u'abc<def>ghi'*n
text.translate(charmap)
+ def test_fake_error_class(self):
+ handlers = [
+ codecs.strict_errors,
+ codecs.ignore_errors,
+ codecs.replace_errors,
+ codecs.backslashreplace_errors,
+ codecs.xmlcharrefreplace_errors,
+ ]
+ for cls in UnicodeEncodeError, UnicodeDecodeError, UnicodeTranslateError:
+ class FakeUnicodeError(str):
+ __class__ = cls
+ for handler in handlers:
+ self.assertRaises(TypeError, handler, FakeUnicodeError())
+ class FakeUnicodeError(Exception):
+ __class__ = cls
+ for handler in handlers:
+ with self.assertRaises((TypeError, FakeUnicodeError)):
+ handler(FakeUnicodeError())
+
+
def test_main():
test.test_support.run_unittest(CodecCallbackTest)
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index fc7c571..dc986a9 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -5,6 +5,7 @@
import socket
import errno
import os
+import tempfile
import unittest
TestCase = unittest.TestCase
@@ -399,6 +400,22 @@
conn.sock = sock
conn.request('GET', '/foo', body)
self.assertTrue(sock.data.startswith(expected))
+ self.assertIn('def test_send_file', sock.data)
+
+ def test_send_tempfile(self):
+ expected = ('GET /foo HTTP/1.1\r\nHost: example.com\r\n'
+ 'Accept-Encoding: identity\r\nContent-Length: 9\r\n\r\n'
+ 'fake\ndata')
+
+ with tempfile.TemporaryFile() as body:
+ body.write('fake\ndata')
+ body.seek(0)
+
+ conn = httplib.HTTPConnection('example.com')
+ sock = FakeSocket(body)
+ conn.sock = sock
+ conn.request('GET', '/foo', body)
+ self.assertEqual(sock.data, expected)
def test_send(self):
expected = 'this is a test this is only a test'
diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py
index 50493f6..bed9a93 100644
--- a/Lib/test/test_pprint.py
+++ b/Lib/test/test_pprint.py
@@ -56,6 +56,7 @@
# Verify .isrecursive() and .isreadable() w/o recursion
pp = pprint.PrettyPrinter()
for safe in (2, 2.0, 2j, "abc", [3], (2,2), {3: 3}, uni("yaddayadda"),
+ bytearray(b"ghi"), True, False, None,
self.a, self.b):
# module-level convenience functions
self.assertFalse(pprint.isrecursive(safe),
@@ -125,21 +126,23 @@
# it sorted a dict display if and only if the display required
# multiple lines. For that reason, dicts with more than one element
# aren't tested here.
- for simple in (0, 0L, 0+0j, 0.0, "", uni(""),
+ for simple in (0, 0L, 0+0j, 0.0, "", uni(""), bytearray(),
(), tuple2(), tuple3(),
[], list2(), list3(),
set(), set2(), set3(),
frozenset(), frozenset2(), frozenset3(),
{}, dict2(), dict3(),
self.assertTrue, pprint,
- -6, -6L, -6-6j, -1.5, "x", uni("x"), (3,), [3], {3: 6},
+ -6, -6L, -6-6j, -1.5, "x", uni("x"), bytearray(b"x"),
+ (3,), [3], {3: 6},
(1,2), [3,4], {5: 6},
tuple2((1,2)), tuple3((1,2)), tuple3(range(100)),
[3,4], list2([3,4]), list3([3,4]), list3(range(100)),
set({7}), set2({7}), set3({7}),
frozenset({8}), frozenset2({8}), frozenset3({8}),
dict2({5: 6}), dict3({5: 6}),
- range(10, -11, -1)
+ range(10, -11, -1),
+ True, False, None,
):
native = repr(simple)
self.assertEqual(pprint.pformat(simple), native)
diff --git a/Lib/test/test_slice.py b/Lib/test/test_slice.py
index 3304d6b..68518d7 100644
--- a/Lib/test/test_slice.py
+++ b/Lib/test/test_slice.py
@@ -18,7 +18,8 @@
def test_hash(self):
# Verify clearing of SF bug #800796
self.assertRaises(TypeError, hash, slice(5))
- self.assertRaises(TypeError, slice(5).__hash__)
+ with self.assertRaises(TypeError):
+ slice(5).__hash__()
def test_cmp(self):
s1 = slice(1, 2, 3)
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 465bcda..3d0ac57 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -287,7 +287,42 @@
lambda: iter(names))
-class test__mkstemp_inner(TC):
+class TestBadTempdir:
+
+ def test_read_only_directory(self):
+ with _inside_empty_temp_dir():
+ oldmode = mode = os.stat(tempfile.tempdir).st_mode
+ mode &= ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)
+ os.chmod(tempfile.tempdir, mode)
+ try:
+ if os.access(tempfile.tempdir, os.W_OK):
+ self.skipTest("can't set the directory read-only")
+ with self.assertRaises(OSError) as cm:
+ self.make_temp()
+ self.assertIn(cm.exception.errno, (errno.EPERM, errno.EACCES))
+ self.assertEqual(os.listdir(tempfile.tempdir), [])
+ finally:
+ os.chmod(tempfile.tempdir, oldmode)
+
+ def test_nonexisting_directory(self):
+ with _inside_empty_temp_dir():
+ tempdir = os.path.join(tempfile.tempdir, 'nonexistent')
+ with support.swap_attr(tempfile, 'tempdir', tempdir):
+ with self.assertRaises(OSError) as cm:
+ self.make_temp()
+ self.assertEqual(cm.exception.errno, errno.ENOENT)
+
+ def test_non_directory(self):
+ with _inside_empty_temp_dir():
+ tempdir = os.path.join(tempfile.tempdir, 'file')
+ open(tempdir, 'wb').close()
+ with support.swap_attr(tempfile, 'tempdir', tempdir):
+ with self.assertRaises(OSError) as cm:
+ self.make_temp()
+ self.assertIn(cm.exception.errno, (errno.ENOTDIR, errno.ENOENT))
+
+
+class test__mkstemp_inner(TestBadTempdir, TC):
"""Test the internal function _mkstemp_inner."""
class mkstemped:
@@ -400,7 +435,7 @@
self.do_create(bin=0).write("blat\n")
# XXX should test that the file really is a text file
- def default_mkstemp_inner(self):
+ def make_temp(self):
return tempfile._mkstemp_inner(tempfile.gettempdir(),
tempfile.template,
'',
@@ -411,11 +446,11 @@
# the chosen name already exists
with _inside_empty_temp_dir(), \
_mock_candidate_names('aaa', 'aaa', 'bbb'):
- (fd1, name1) = self.default_mkstemp_inner()
+ (fd1, name1) = self.make_temp()
os.close(fd1)
self.assertTrue(name1.endswith('aaa'))
- (fd2, name2) = self.default_mkstemp_inner()
+ (fd2, name2) = self.make_temp()
os.close(fd2)
self.assertTrue(name2.endswith('bbb'))
@@ -427,7 +462,7 @@
dir = tempfile.mkdtemp()
self.assertTrue(dir.endswith('aaa'))
- (fd, name) = self.default_mkstemp_inner()
+ (fd, name) = self.make_temp()
os.close(fd)
self.assertTrue(name.endswith('bbb'))
@@ -542,9 +577,12 @@
test_classes.append(test_mkstemp)
-class test_mkdtemp(TC):
+class test_mkdtemp(TestBadTempdir, TC):
"""Test mkdtemp()."""
+ def make_temp(self):
+ return tempfile.mkdtemp()
+
def do_create(self, dir=None, pre="", suf=""):
if dir is None:
dir = tempfile.gettempdir()
diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py
index 7a9459a..11dc294 100644
--- a/Lib/test/test_warnings.py
+++ b/Lib/test/test_warnings.py
@@ -593,6 +593,63 @@
self.assertEqual(expect, self.module.formatwarning(message,
category, file_name, line_num, file_line))
+ @test_support.requires_unicode
+ def test_formatwarning_unicode_msg(self):
+ message = u"msg"
+ category = Warning
+ file_name = os.path.splitext(warning_tests.__file__)[0] + '.py'
+ line_num = 3
+ file_line = linecache.getline(file_name, line_num).strip()
+ format = "%s:%s: %s: %s\n %s\n"
+ expect = format % (file_name, line_num, category.__name__, message,
+ file_line)
+ self.assertEqual(expect, self.module.formatwarning(message,
+ category, file_name, line_num))
+ # Test the 'line' argument.
+ file_line += " for the win!"
+ expect = format % (file_name, line_num, category.__name__, message,
+ file_line)
+ self.assertEqual(expect, self.module.formatwarning(message,
+ category, file_name, line_num, file_line))
+
+ @test_support.requires_unicode
+ @unittest.skipUnless(test_support.FS_NONASCII, 'need test_support.FS_NONASCII')
+ def test_formatwarning_unicode_msg_nonascii_filename(self):
+ message = u"msg"
+ category = Warning
+ unicode_file_name = test_support.FS_NONASCII + u'.py'
+ file_name = unicode_file_name.encode(sys.getfilesystemencoding())
+ line_num = 3
+ file_line = 'spam'
+ format = "%s:%s: %s: %s\n %s\n"
+ expect = format % (file_name, line_num, category.__name__, str(message),
+ file_line)
+ self.assertEqual(expect, self.module.formatwarning(message,
+ category, file_name, line_num, file_line))
+ message = u"\xb5sg"
+ expect = format % (unicode_file_name, line_num, category.__name__, message,
+ file_line)
+ self.assertEqual(expect, self.module.formatwarning(message,
+ category, file_name, line_num, file_line))
+
+ @test_support.requires_unicode
+ def test_formatwarning_unicode_msg_nonascii_fileline(self):
+ message = u"msg"
+ category = Warning
+ file_name = 'file.py'
+ line_num = 3
+ file_line = 'sp\xe4m'
+ format = "%s:%s: %s: %s\n %s\n"
+ expect = format % (file_name, line_num, category.__name__, str(message),
+ file_line)
+ self.assertEqual(expect, self.module.formatwarning(message,
+ category, file_name, line_num, file_line))
+ message = u"\xb5sg"
+ expect = format % (file_name, line_num, category.__name__, message,
+ unicode(file_line, 'latin1'))
+ self.assertEqual(expect, self.module.formatwarning(message,
+ category, file_name, line_num, file_line))
+
def test_showwarning(self):
file_name = os.path.splitext(warning_tests.__file__)[0] + '.py'
line_num = 3
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index 6bbc55f..644fe5b 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -127,8 +127,6 @@
(expected_regexp.pattern, str(exc_value)))
return True
-def _sentinel(*args, **kwargs):
- raise AssertionError('Should never be called')
class TestCase(object):
"""A class whose instances are single test cases.
@@ -445,7 +443,7 @@
return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg))
- def assertRaises(self, excClass, callableObj=_sentinel, *args, **kwargs):
+ def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
"""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
@@ -453,7 +451,7 @@
deemed to have suffered an error, exactly as for an
unexpected exception.
- If called with callableObj omitted, will return a
+ If called with callableObj omitted or None, will return a
context object used like this::
with self.assertRaises(SomeException):
@@ -469,7 +467,7 @@
self.assertEqual(the_exception.error_code, 3)
"""
context = _AssertRaisesContext(excClass, self)
- if callableObj is _sentinel:
+ if callableObj is None:
return context
with context:
callableObj(*args, **kwargs)
@@ -975,7 +973,7 @@
self.fail(self._formatMessage(msg, standardMsg))
def assertRaisesRegexp(self, expected_exception, expected_regexp,
- callable_obj=_sentinel, *args, **kwargs):
+ callable_obj=None, *args, **kwargs):
"""Asserts that the message in a raised exception matches a regexp.
Args:
@@ -989,7 +987,7 @@
if expected_regexp is not None:
expected_regexp = re.compile(expected_regexp)
context = _AssertRaisesContext(expected_exception, self, expected_regexp)
- if callable_obj is _sentinel:
+ if callable_obj is None:
return context
with context:
callable_obj(*args, **kwargs)
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
index 4c2d1f9..7658189 100644
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -967,9 +967,6 @@
# Failure when no exception is raised
with self.assertRaises(self.failureException):
self.assertRaises(ExceptionMock, lambda: 0)
- # Failure when the function is None
- with self.assertRaises(TypeError):
- self.assertRaises(ExceptionMock, None)
# Failure when another exception is raised
with self.assertRaises(ExceptionMock):
self.assertRaises(ValueError, Stub)
@@ -1008,8 +1005,6 @@
self.assertRaisesRegexp(ExceptionMock, re.compile('expect$'), Stub)
self.assertRaisesRegexp(ExceptionMock, 'expect$', Stub)
self.assertRaisesRegexp(ExceptionMock, u'expect$', Stub)
- with self.assertRaises(TypeError):
- self.assertRaisesRegexp(ExceptionMock, 'expect$', None)
def testAssertNotRaisesRegexp(self):
self.assertRaisesRegexp(
diff --git a/Lib/warnings.py b/Lib/warnings.py
index fbec94b..b0d53aa 100644
--- a/Lib/warnings.py
+++ b/Lib/warnings.py
@@ -31,7 +31,7 @@
return
try:
file.write(formatwarning(message, category, filename, lineno, line))
- except IOError:
+ except (IOError, UnicodeError):
pass # the file (probably stderr) is invalid - this warning gets lost.
# Keep a working version around in case the deprecation of the old API is
# triggered.
@@ -39,11 +39,29 @@
def formatwarning(message, category, filename, lineno, line=None):
"""Function to format a warning the standard way."""
- s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
+ try:
+ unicodetype = unicode
+ except NameError:
+ unicodetype = ()
+ try:
+ message = str(message)
+ except UnicodeEncodeError:
+ pass
+ s = "%s: %s: %s\n" % (lineno, category.__name__, message)
line = linecache.getline(filename, lineno) if line is None else line
if line:
line = line.strip()
+ if isinstance(s, unicodetype) and isinstance(line, str):
+ line = unicode(line, 'latin1')
s += " %s\n" % line
+ if isinstance(s, unicodetype) and isinstance(filename, str):
+ enc = sys.getfilesystemencoding()
+ if enc:
+ try:
+ filename = unicode(filename, enc)
+ except UnicodeDecodeError:
+ pass
+ s = "%s:%s" % (filename, s)
return s
def filterwarnings(action, message="", category=Warning, module="", lineno=0,
diff --git a/Misc/ACKS b/Misc/ACKS
index 2262c79..8187174 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1159,6 +1159,7 @@
Just van Rossum
Hugo van Rossum
Saskia van Rossum
+Clement Rouault
Donald Wallace Rouse II
Liam Routt
Todd Rovito
diff --git a/Misc/NEWS b/Misc/NEWS
index c311f6b..a46a529 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -2,6 +2,60 @@
Python News
+++++++++++
+What's New in Python 2.7.11?
+============================
+
+*Release date: XXXX-XX-XX*
+
+Core and Builtins
+-----------------
+
+- Issue #22939: Fixed integer overflow in iterator object. Original patch by
+ Clement Rouault.
+
+- Issue #24102: Fixed exception type checking in standard error handlers.
+
+Library
+-------
+
+- Issue #24257: Fixed segmentation fault in sqlite3.Row constructor with faked
+ cursor type.
+
+- Issue #22107: tempfile.gettempdir() and tempfile.mkdtemp() now try again
+ when a directory with the chosen name already exists on Windows as well as
+ on Unix. tempfile.mkstemp() now fails early if parent directory is not
+ valid (not exists or is a file) on Windows.
+
+- Issue #6598: Increased time precision and random number range in
+ email.utils.make_msgid() to strengthen the uniqueness of the message ID.
+
+- Issue #24091: Fixed various crashes in corner cases in cElementTree.
+
+- Issue #15267: HTTPConnection.request() now is compatibile with old-style
+ classes (such as TemporaryFile). Original patch by Atsuo Ishimoto.
+
+- Issue #20014: array.array() now accepts unicode typecodes. Based on patch by
+ Vajrasky Kok.
+
+- Issue #23637: Showing a warning no longer fails with UnicodeErrror.
+ Formatting unicode warning in the file with the path containing non-ascii
+ characters no longer fails with UnicodeErrror.
+
+- Issue #24134: Reverted issue #24134 changes.
+
+IDLE
+----
+
+- Issue #15809: IDLE shell now uses locale encoding instead of Latin1 for
+ decoding unicode literals.
+
+Documentation
+-------------
+
+- Issue #22155: Add File Handlers subsection with createfilehandler to Tkinter
+ doc. Remove obsolete example from FAQ. Patch by Martin Panter.
+
+
What's New in Python 2.7.10?
============================
@@ -12,7 +66,6 @@
- Issue #22931: Allow '[' and ']' in cookie values.
-
What's New in Python 2.7.10 release candidate 1?
================================================
@@ -24,6 +77,11 @@
- Issue #20274: When calling a _sqlite.Connection, it now complains if passed
any keyword arguments. Previously it silently ignored them.
+- Issue #23971: Fix underestimated presizing in dict.fromkeys().
+
+- Issue #23757: PySequence_Tuple() incorrectly called the concrete list API
+ when the data was a list subclass.
+
- Issue #20274: Remove ignored and erroneous "kwargs" parameters from three
METH_VARARGS methods on _sqlite.Connection.
diff --git a/Misc/python.man b/Misc/python.man
index d87902f..054fbb5 100644
--- a/Misc/python.man
+++ b/Misc/python.man
@@ -289,9 +289,9 @@
from that file;
when called with
.B \-c
-.I command,
+.IR command ,
it executes the Python statement(s) given as
-.I command.
+.IR command .
Here
.I command
may contain multiple statements separated by newlines.
@@ -301,7 +301,7 @@
.PP
If available, the script name and additional arguments thereafter are
passed to the script in the Python variable
-.I sys.argv ,
+.IR sys.argv ,
which is a list of strings (you must first
.I import sys
to be able to access it).
@@ -315,14 +315,14 @@
.I '-c'.
Note that options interpreted by the Python interpreter itself
are not placed in
-.I sys.argv.
+.IR sys.argv .
.PP
In interactive mode, the primary prompt is `>>>'; the second prompt
(which appears when a command is not complete) is `...'.
The prompts can be changed by assignment to
.I sys.ps1
or
-.I sys.ps2.
+.IR sys.ps2 .
The interpreter quits when it reads an EOF at a prompt.
When an unhandled exception occurs, a stack trace is printed and
control returns to the primary prompt; in non-interactive mode, the
@@ -381,7 +381,7 @@
inserted in the path in front of $PYTHONPATH.
The search path can be manipulated from within a Python program as the
variable
-.I sys.path .
+.IR sys.path .
.IP PYTHONSTARTUP
If this is the name of a readable file, the Python commands in that
file are executed before the first prompt is displayed in interactive
@@ -452,7 +452,7 @@
the value 0 will lead to the same hash values as when hash randomization is
disabled.
.SH AUTHOR
-The Python Software Foundation: https://www.python.org/psf
+The Python Software Foundation: https://www.python.org/psf/
.SH INTERNET RESOURCES
Main website: https://www.python.org/
.br
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index 3e9f9df..837164c 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -756,7 +756,7 @@
element_extend(ElementObject* self, PyObject* args)
{
PyObject* seq;
- Py_ssize_t i, seqlen = 0;
+ Py_ssize_t i;
PyObject* seq_in;
if (!PyArg_ParseTuple(args, "O:extend", &seq_in))
@@ -771,8 +771,7 @@
return NULL;
}
- seqlen = PySequence_Size(seq);
- for (i = 0; i < seqlen; i++) {
+ for (i = 0; i < PySequence_Fast_GET_SIZE(seq); i++) {
PyObject* element = PySequence_Fast_GET_ITEM(seq, i);
if (element_add_subelement(self, element) < 0) {
Py_DECREF(seq);
@@ -805,11 +804,16 @@
for (i = 0; i < self->extra->length; i++) {
PyObject* item = self->extra->children[i];
- if (Element_CheckExact(item) &&
- PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) {
- Py_INCREF(item);
+ int rc;
+ if (!Element_CheckExact(item))
+ continue;
+ Py_INCREF(item);
+ rc = PyObject_Compare(((ElementObject*)item)->tag, tag);
+ if (rc == 0)
return item;
- }
+ Py_DECREF(item);
+ if (rc < 0 && PyErr_Occurred())
+ return NULL;
}
Py_RETURN_NONE;
@@ -838,13 +842,24 @@
for (i = 0; i < self->extra->length; i++) {
ElementObject* item = (ElementObject*) self->extra->children[i];
- if (Element_CheckExact(item) && !PyObject_Compare(item->tag, tag)) {
+ int rc;
+ if (!Element_CheckExact(item))
+ continue;
+ Py_INCREF(item);
+ rc = PyObject_Compare(item->tag, tag);
+ if (rc == 0) {
PyObject* text = element_get_text(item);
- if (text == Py_None)
+ if (text == Py_None) {
+ Py_DECREF(item);
return PyString_FromString("");
+ }
Py_XINCREF(text);
+ Py_DECREF(item);
return text;
}
+ Py_DECREF(item);
+ if (rc < 0 && PyErr_Occurred())
+ return NULL;
}
Py_INCREF(default_value);
@@ -876,12 +891,17 @@
for (i = 0; i < self->extra->length; i++) {
PyObject* item = self->extra->children[i];
- if (Element_CheckExact(item) &&
- PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) {
- if (PyList_Append(out, item) < 0) {
- Py_DECREF(out);
- return NULL;
- }
+ int rc;
+ if (!Element_CheckExact(item))
+ continue;
+ Py_INCREF(item);
+ rc = PyObject_Compare(((ElementObject*)item)->tag, tag);
+ if (rc == 0)
+ rc = PyList_Append(out, item);
+ Py_DECREF(item);
+ if (rc < 0 && PyErr_Occurred()) {
+ Py_DECREF(out);
+ return NULL;
}
}
@@ -1147,8 +1167,10 @@
element_remove(ElementObject* self, PyObject* args)
{
int i;
-
+ int rc;
PyObject* element;
+ PyObject* found;
+
if (!PyArg_ParseTuple(args, "O!:remove", &Element_Type, &element))
return NULL;
@@ -1164,11 +1186,14 @@
for (i = 0; i < self->extra->length; i++) {
if (self->extra->children[i] == element)
break;
- if (PyObject_Compare(self->extra->children[i], element) == 0)
+ rc = PyObject_Compare(self->extra->children[i], element);
+ if (rc == 0)
break;
+ if (rc < 0 && PyErr_Occurred())
+ return NULL;
}
- if (i == self->extra->length) {
+ if (i >= self->extra->length) {
/* element is not in children, so raise exception */
PyErr_SetString(
PyExc_ValueError,
@@ -1177,13 +1202,13 @@
return NULL;
}
- Py_DECREF(self->extra->children[i]);
+ found = self->extra->children[i];
self->extra->length--;
-
for (; i < self->extra->length; i++)
self->extra->children[i] = self->extra->children[i+1];
+ Py_DECREF(found);
Py_RETURN_NONE;
}
diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c
index d0ddb09..be301a6 100644
--- a/Modules/_heapqmodule.c
+++ b/Modules/_heapqmodule.c
@@ -244,6 +244,11 @@
return item;
}
+ if (PyList_GET_SIZE(heap) == 0) {
+ PyErr_SetString(PyExc_IndexError, "index out of range");
+ return NULL;
+ }
+
returnitem = PyList_GET_ITEM(heap, 0);
Py_INCREF(item);
PyList_SET_ITEM(heap, 0, item);
diff --git a/Modules/_sqlite/row.c b/Modules/_sqlite/row.c
index 02373f0..9ebe7b7 100644
--- a/Modules/_sqlite/row.c
+++ b/Modules/_sqlite/row.c
@@ -47,7 +47,7 @@
if (!PyArg_ParseTuple(args, "OO", &cursor, &data))
return NULL;
- if (!PyObject_IsInstance((PyObject*)cursor, (PyObject*)&pysqlite_CursorType)) {
+ if (!PyObject_TypeCheck((PyObject*)cursor, &pysqlite_CursorType)) {
PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument");
return NULL;
}
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 5a92862..c37644d 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -1928,16 +1928,28 @@
static PyObject *
array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
- char c;
- PyObject *initial = NULL, *it = NULL;
+ int c = -1;
+ PyObject *initial = NULL, *it = NULL, *typecode = NULL;
struct arraydescr *descr;
if (type == &Arraytype && !_PyArg_NoKeywords("array.array()", kwds))
return NULL;
- if (!PyArg_ParseTuple(args, "c|O:array", &c, &initial))
+ if (!PyArg_ParseTuple(args, "O|O:array", &typecode, &initial))
return NULL;
+ if (PyString_Check(typecode) && PyString_GET_SIZE(typecode) == 1)
+ c = (unsigned char)*PyString_AS_STRING(typecode);
+ else if (PyUnicode_Check(typecode) && PyUnicode_GET_SIZE(typecode) == 1)
+ c = *PyUnicode_AS_UNICODE(typecode);
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "array() argument 1 or typecode must be char (string or "
+ "ascii-unicode with length 1), not %s",
+ Py_TYPE(typecode)->tp_name);
+ return NULL;
+ }
+
if (!(initial == NULL || PyList_Check(initial)
|| PyString_Check(initial) || PyTuple_Check(initial)
|| (c == 'u' && PyUnicode_Check(initial)))) {
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 64a1a38..6e289ef 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2169,7 +2169,7 @@
Py_INCREF(v);
return v;
}
- if (PyList_Check(v))
+ if (PyList_CheckExact(v))
return PyList_AsTuple(v);
/* Get iterator. */
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 39e7035..50afa3f 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1361,7 +1361,7 @@
PyObject *key;
long hash;
- if (dictresize(mp, Py_SIZE(seq))) {
+ if (dictresize(mp, Py_SIZE(seq) / 2 * 3)) {
Py_DECREF(d);
return NULL;
}
@@ -1382,7 +1382,7 @@
PyObject *key;
long hash;
- if (dictresize(mp, PySet_GET_SIZE(seq))) {
+ if (dictresize(mp, PySet_GET_SIZE(seq) / 2 * 3)) {
Py_DECREF(d);
return NULL;
}
diff --git a/Objects/iterobject.c b/Objects/iterobject.c
index 5a9a2dd..9c90abe 100644
--- a/Objects/iterobject.c
+++ b/Objects/iterobject.c
@@ -54,6 +54,11 @@
seq = it->it_seq;
if (seq == NULL)
return NULL;
+ if (it->it_index == LONG_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "iter index too large");
+ return NULL;
+ }
result = PySequence_GetItem(seq, it->it_index);
if (result != NULL) {
diff --git a/Python/codecs.c b/Python/codecs.c
index a901d6d..184d147 100644
--- a/Python/codecs.c
+++ b/Python/codecs.c
@@ -472,15 +472,16 @@
PyObject *PyCodec_IgnoreErrors(PyObject *exc)
{
Py_ssize_t end;
- if (PyObject_IsInstance(exc, PyExc_UnicodeEncodeError)) {
+
+ if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
if (PyUnicodeEncodeError_GetEnd(exc, &end))
return NULL;
}
- else if (PyObject_IsInstance(exc, PyExc_UnicodeDecodeError)) {
+ else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) {
if (PyUnicodeDecodeError_GetEnd(exc, &end))
return NULL;
}
- else if (PyObject_IsInstance(exc, PyExc_UnicodeTranslateError)) {
+ else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) {
if (PyUnicodeTranslateError_GetEnd(exc, &end))
return NULL;
}
@@ -500,7 +501,7 @@
Py_ssize_t end;
Py_ssize_t i;
- if (PyObject_IsInstance(exc, PyExc_UnicodeEncodeError)) {
+ if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
PyObject *res;
Py_UNICODE *p;
if (PyUnicodeEncodeError_GetStart(exc, &start))
@@ -517,13 +518,13 @@
Py_DECREF(res);
return restuple;
}
- else if (PyObject_IsInstance(exc, PyExc_UnicodeDecodeError)) {
+ else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) {
Py_UNICODE res = Py_UNICODE_REPLACEMENT_CHARACTER;
if (PyUnicodeDecodeError_GetEnd(exc, &end))
return NULL;
return Py_BuildValue("(u#n)", &res, (Py_ssize_t)1, end);
}
- else if (PyObject_IsInstance(exc, PyExc_UnicodeTranslateError)) {
+ else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) {
PyObject *res;
Py_UNICODE *p;
if (PyUnicodeTranslateError_GetStart(exc, &start))
@@ -548,7 +549,7 @@
PyObject *PyCodec_XMLCharRefReplaceErrors(PyObject *exc)
{
- if (PyObject_IsInstance(exc, PyExc_UnicodeEncodeError)) {
+ if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
PyObject *restuple;
PyObject *object;
Py_ssize_t start;
@@ -673,7 +674,7 @@
PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc)
{
- if (PyObject_IsInstance(exc, PyExc_UnicodeEncodeError)) {
+ if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
PyObject *restuple;
PyObject *object;
Py_ssize_t start;
diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py
index d8c426a..07a4ef1 100644
--- a/Tools/msi/uuids.py
+++ b/Tools/msi/uuids.py
@@ -68,4 +68,6 @@
'2.7.8150':'{61121B12-88BD-4261-A6EE-AB32610A56DD}', # 2.7.8
'2.7.9121':'{AAB1E8FF-6D00-4409-8F13-BE365AB92FFE}', # 2.7.9rc1
'2.7.9150':'{79F081BF-7454-43DB-BD8F-9EE596813232}', # 2.7.9
+ '2.7.10121':'{872BE558-2E5F-4E9C-A42D-8561FA43811C}', # 2.7.10rc1
+ '2.7.10150':'{E2B51919-207A-43EB-AE78-733F9C6797C2}', # 2.7.10
}