diff options
42 files changed, 994 insertions, 248 deletions
diff --git a/Doc/lib/email.tex b/Doc/lib/email.tex index 47727a7..3de3df3 100644 --- a/Doc/lib/email.tex +++ b/Doc/lib/email.tex @@ -94,7 +94,7 @@ package, a section on differences and porting is provided. This table describes the release history of the email package, corresponding to the version of Python that the package was released with. For purposes of this document, when you see a note about change or added versions, these refer -to the Python version the change was made it, \emph{not} the email package +to the Python version the change was made in, \emph{not} the email package version. This table also describes the Python compatibility of each version of the package. diff --git a/Doc/lib/libitertools.tex b/Doc/lib/libitertools.tex index 19bc826..b4784a8 100644 --- a/Doc/lib/libitertools.tex +++ b/Doc/lib/libitertools.tex @@ -117,7 +117,7 @@ by functions or loops that truncate the stream. Make an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every element. Note, the iterator does not produce \emph{any} output until the predicate - is true, so it may have a lengthy start-up time. Equivalent to: + first becomes false, so it may have a lengthy start-up time. Equivalent to: \begin{verbatim} def dropwhile(predicate, iterable): @@ -509,8 +509,8 @@ def iteritems(mapping): return izip(mapping.iterkeys(), mapping.itervalues()) def nth(iterable, n): - "Returns the nth item or raise IndexError" - return list(islice(iterable, n, n+1))[0] + "Returns the nth item or raise StopIteration" + return islice(iterable, n, None).next() def all(seq, pred=None): "Returns True if pred(x) is true for every element in the iterable" diff --git a/Doc/lib/libnis.tex b/Doc/lib/libnis.tex index cc1482d..fe4acb5 100644 --- a/Doc/lib/libnis.tex +++ b/Doc/lib/libnis.tex @@ -2,7 +2,7 @@ Interface to Sun's NIS (Yellow Pages)} \declaremodule{extension}{nis} - \platform{UNIX} + \platform{Unix} \moduleauthor{Fred Gansevles}{Fred.Gansevles@cs.utwente.nl} \sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} \modulesynopsis{Interface to Sun's NIS (Yellow Pages) library.} diff --git a/Doc/lib/libsubprocess.tex b/Doc/lib/libsubprocess.tex index dc386bf..e2a9bb6 100644 --- a/Doc/lib/libsubprocess.tex +++ b/Doc/lib/libsubprocess.tex @@ -145,6 +145,8 @@ The arguments are the same as for the Popen constructor. Example: \begin{verbatim} check_call(["ls", "-l"]) \end{verbatim} + +\versionadded{2.5} \end{funcdesc} \subsubsection{Exceptions} diff --git a/Doc/lib/libtime.tex b/Doc/lib/libtime.tex index e276045..8a45bfcc 100644 --- a/Doc/lib/libtime.tex +++ b/Doc/lib/libtime.tex @@ -309,15 +309,23 @@ The field width is normally 2 except for \code{\%j} where it is 3. \begin{funcdesc}{strptime}{string\optional{, format}} Parse a string representing a time according to a format. The return value is a \class{struct_time} as returned by \function{gmtime()} or -\function{localtime()}. The \var{format} parameter uses the same -directives as those used by \function{strftime()}; it defaults to -\code{"\%a \%b \%d \%H:\%M:\%S \%Y"} which matches the formatting -returned by \function{ctime()}. If \var{string} cannot be parsed -according to \var{format}, \exception{ValueError} is raised. If the -string to be parsed has excess data after parsing, -\exception{ValueError} is raised. The default values used to fill in -any missing data when more accurate values cannot be inferred are -\code{(1900, 1, 1, 0, 0, 0, 0, 1, -1)} . +\function{localtime()}. + +The \var{format} parameter uses the same directives as those used by +\function{strftime()}; it defaults to \code{"\%a \%b \%d \%H:\%M:\%S + \%Y"} which matches the formatting returned by \function{ctime()}. +If \var{string} cannot be parsed according to \var{format}, or if it +has excess data after parsing, \exception{ValueError} is raised. The +default values used to fill in any missing data when more accurate +values cannot be inferred are \code{(1900, 1, 1, 0, 0, 0, 0, 1, -1)}. + +For example: + +\begin{verbatim} +>>> import time +>>> time.strptime("30 Nov 00", "%d %b %y") +(2000, 11, 30, 0, 0, 0, 3, 335, -1) +\end{verbatim} Support for the \code{\%Z} directive is based on the values contained in \code{tzname} and whether \code{daylight} is true. Because of this, diff --git a/Doc/lib/libwebbrowser.tex b/Doc/lib/libwebbrowser.tex index 50366ba..5d5f236 100644 --- a/Doc/lib/libwebbrowser.tex +++ b/Doc/lib/libwebbrowser.tex @@ -47,7 +47,7 @@ The following functions are defined: \begin{funcdesc}{open}{url\optional{, new=0\optional{, autoraise=1}}} Display \var{url} using the default browser. If \var{new} is 0, the - \var{url} is opened in the same browser window. If \var{new} is 1, + \var{url} is opened in the same browser window if possible. If \var{new} is 1, a new browser window is opened if possible. If \var{new} is 2, a new browser page ("tab") is opened if possible. If \var{autoraise} is true, the window is raised if possible (note that under many window diff --git a/Doc/lib/libzipfile.tex b/Doc/lib/libzipfile.tex index 6cdd1d3..366cee9 100644 --- a/Doc/lib/libzipfile.tex +++ b/Doc/lib/libzipfile.tex @@ -24,8 +24,8 @@ it cannot currently create an encrypted file. The available attributes of this module are: -\begin{excdesc}{error} - The error raised for bad ZIP files. +\begin{excdesc}{BadZipfile} + The error raised for bad ZIP files (old name: \code{zipfile.error}). \end{excdesc} \begin{excdesc}{LargeZipFile} @@ -90,7 +90,7 @@ The available attributes of this module are: (a string) or a file-like object. The \var{mode} parameter should be \code{'r'} to read an existing file, \code{'w'} to truncate and write a new file, or \code{'a'} to append to an - existing file. For \var{mode} is \code{'a'} and \var{file} + existing file. If \var{mode} is \code{'a'} and \var{file} refers to an existing ZIP file, then additional files are added to it. If \var{file} does not refer to a ZIP file, then a new ZIP archive is appended to the file. This is meant for adding a ZIP @@ -128,7 +128,8 @@ cat myzip.zip >> python.exe \begin{methoddesc}{getinfo}{name} Return a \class{ZipInfo} object with information about the archive - member \var{name}. + member \var{name}. Calling \method{getinfo()} for a name not currently + contained in the archive will raise a \exception{KeyError}. \end{methoddesc} \begin{methoddesc}{infolist}{} @@ -147,7 +148,9 @@ cat myzip.zip >> python.exe parameter, if included, must be one of the following: \code{'r'} (the default), \code{'U'}, or \code{'rU'}. Choosing \code{'U'} or \code{'rU'} will enable universal newline support in the read-only - object. \var{pwd} is the password used for encrypted files. + object. \var{pwd} is the password used for encrypted files. Calling + \method{open()} on a closed ZipFile will raise a + \exception{RuntimeError}. \begin{notice} The file-like object is read-only and provides the following methods: \method{read()}, \method{readline()}, \method{readlines()}, @@ -182,7 +185,8 @@ cat myzip.zip >> python.exe Return the bytes of the file in the archive. The archive must be open for read or append. \var{pwd} is the password used for encrypted files and, if specified, it will override the default password set with - \method{setpassword()}. + \method{setpassword()}. Calling \method{read()} on a closed ZipFile + will raise a \exception{RuntimeError}. \versionchanged[\var{pwd} was added]{2.6} \end{methoddesc} @@ -190,6 +194,8 @@ cat myzip.zip >> python.exe \begin{methoddesc}{testzip}{} Read all the files in the archive and check their CRC's and file headers. Return the name of the first bad file, or else return \code{None}. + Calling \method{testzip()} on a closed ZipFile will raise a + \exception{RuntimeError}. \end{methoddesc} \begin{methoddesc}{write}{filename\optional{, arcname\optional{, @@ -200,7 +206,10 @@ cat myzip.zip >> python.exe separators removed). If given, \var{compress_type} overrides the value given for the \var{compression} parameter to the constructor for the new entry. The archive must be open with mode \code{'w'} - or \code{'a'}. + or \code{'a'} -- calling \method{write()} on a ZipFile created with + mode \code{'r'} will raise a \exception{RuntimeError}. Calling + \method{write()} on a closed ZipFile will raise a + \exception{RuntimeError}. \note{There is no official file name encoding for ZIP files. If you have unicode file names, please convert them to byte strings @@ -210,6 +219,11 @@ cat myzip.zip >> python.exe \note{Archive names should be relative to the archive root, that is, they should not start with a path separator.} + + \note{If \code{arcname} (or \code{filename}, if \code{arcname} is + not given) contains a null byte, the name of the file in the archive will + be truncated at the null byte.} + \end{methoddesc} \begin{methoddesc}{writestr}{zinfo_or_arcname, bytes} @@ -218,7 +232,10 @@ cat myzip.zip >> python.exe \class{ZipInfo} instance. If it's an instance, at least the filename, date, and time must be given. If it's a name, the date and time is set to the current date and time. The archive must be - opened with mode \code{'w'} or \code{'a'}. + opened with mode \code{'w'} or \code{'a'} -- calling + \method{writestr()} on a ZipFile created with mode \code{'r'} + will raise a \exception{RuntimeError}. Calling \method{writestr()} + on a closed ZipFile will raise a \exception{RuntimeError}. \end{methoddesc} @@ -243,12 +260,13 @@ those of \class{ZipFile} objects. available, else a \file{*.pyc} file, compiling if necessary. If the pathname is a file, the filename must end with \file{.py}, and just the (corresponding \file{*.py[co]}) file is added at the top level - (no path information). If it is a directory, and the directory is - not a package directory, then all the files \file{*.py[co]} are - added at the top level. If the directory is a package directory, - then all \file{*.py[oc]} are added under the package name as a file - path, and if any subdirectories are package directories, all of - these are added recursively. \var{basename} is intended for + (no path information). If the pathname is a file that does not end with + \file{.py}, a \exception{RuntimeError} will be raised. If it is a + directory, and the directory is not a package directory, then all the + files \file{*.py[co]} are added at the top level. If the directory is + a package directory, then all \file{*.py[co]} are added under the package + name as a file path, and if any subdirectories are package directories, all + of these are added recursively. \var{basename} is intended for internal use only. The \method{writepy()} method makes archives with file names like this: diff --git a/Doc/tut/tut.tex b/Doc/tut/tut.tex index 53a84a9..a41487b 100644 --- a/Doc/tut/tut.tex +++ b/Doc/tut/tut.tex @@ -2498,6 +2498,44 @@ There is even a variant to import all names that a module defines: This imports all names except those beginning with an underscore (\code{_}). +\subsection{Executing modules as scripts \label{modulesAsScripts}} + +When you run a Python module with + +\begin{verbatim} +python fibo.py <arguments> +\end{verbatim} + +the code in the module will be executed, just as if you imported it, but +with the \code{__name__} set to \code{"__main__"}. That means that by +adding this code at the end of your module: + +\begin{verbatim} +if __name__ == "__main__": + import sys + fib(int(sys.argv[1])) +\end{verbatim} + +you can make the file usable as a script as well as an importable module, +because the code that parses the command line only runs if the module is +executed as the ``main'' file: + +\begin{verbatim} +$ python fibo.py 50 +1 1 2 3 5 8 13 21 34 +\end{verbatim} + +If the module is imported, the code is not run: + +\begin{verbatim} +>>> import fibo +>>> +\end{verbatim} + +This is often used either to provide a convenient user interface to a +module, or for testing purposes (running the module as a script executes +a test suite). + \subsection{The Module Search Path \label{searchPath}} diff --git a/Include/opcode.h b/Include/opcode.h index 6717977..1c6683d 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -112,7 +112,7 @@ extern "C" { #define LOAD_GLOBAL 116 /* Index in name list */ #define CONTINUE_LOOP 119 /* Start of loop (absolute) */ -#define SETUP_LOOP 120 /* Target address (absolute) */ +#define SETUP_LOOP 120 /* Target address (relative) */ #define SETUP_EXCEPT 121 /* "" */ #define SETUP_FINALLY 122 /* "" */ diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index f62c345..2cddb11 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -223,6 +223,14 @@ _check_size(c_char) class c_char_p(_SimpleCData): _type_ = "z" + if _os.name == "nt": + def __repr__(self): + if not windll.kernel32.IsBadStringPtrA(self, -1): + return "%s(%r)" % (self.__class__.__name__, self.value) + return "%s(%s)" % (self.__class__.__name__, cast(self, c_void_p).value) + else: + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, cast(self, c_void_p).value) _check_size(c_char_p, "P") class c_void_p(_SimpleCData): diff --git a/Lib/ctypes/test/test_find.py b/Lib/ctypes/test/test_find.py index 71cfe93..9f61cdb 100644 --- a/Lib/ctypes/test/test_find.py +++ b/Lib/ctypes/test/test_find.py @@ -7,25 +7,21 @@ from ctypes.test import is_resource_enabled if sys.platform == "win32": lib_gl = find_library("OpenGL32") lib_glu = find_library("Glu32") - lib_glut = find_library("glut32") lib_gle = None elif sys.platform == "darwin": lib_gl = lib_glu = find_library("OpenGL") - lib_glut = find_library("GLUT") lib_gle = None else: lib_gl = find_library("GL") lib_glu = find_library("GLU") - lib_glut = find_library("glut") lib_gle = find_library("gle") ## print, for debugging if is_resource_enabled("printing"): - if lib_gl or lib_glu or lib_glut or lib_gle: + if lib_gl or lib_glu or lib_gle: print("OpenGL libraries:") for item in (("GL", lib_gl), ("GLU", lib_glu), - ("glut", lib_glut), ("gle", lib_gle)): print("\t", item) @@ -33,24 +29,11 @@ if is_resource_enabled("printing"): # On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode. class Test_OpenGL_libs(unittest.TestCase): def setUp(self): - self.gl = self.glu = self.gle = self.glut = None + self.gl = self.glu = self.gle = None if lib_gl: self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) if lib_glu: self.glu = CDLL(lib_glu, RTLD_GLOBAL) - if lib_glut: - # On some systems, additional libraries seem to be - # required, loading glut fails with - # "OSError: /usr/lib/libglut.so.3: undefined symbol: XGetExtensionVersion" - # I cannot figure out how to repair the test on these - # systems (red hat), so we ignore it when the glut or gle - # libraries cannot be loaded. See also: - # https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1478253&group_id=5470 - # http://mail.python.org/pipermail/python-dev/2006-May/064789.html - try: - self.glut = CDLL(lib_glut) - except OSError: - pass if lib_gle: try: self.gle = CDLL(lib_gle) @@ -67,11 +50,6 @@ class Test_OpenGL_libs(unittest.TestCase): if self.glu: self.glu.gluBeginCurve - if lib_glut: - def test_glut(self): - if self.glut: - self.glut.glutWireTetrahedron - if lib_gle: def test_gle(self): if self.gle: diff --git a/Lib/ctypes/test/test_win32.py b/Lib/ctypes/test/test_win32.py index 057873c..5067b60 100644 --- a/Lib/ctypes/test/test_win32.py +++ b/Lib/ctypes/test/test_win32.py @@ -58,6 +58,15 @@ if sys.platform == "win32": self.failUnlessEqual(sizeof(wintypes.LPARAM), sizeof(c_void_p)) + def test_COMError(self): + from _ctypes import COMError + self.assertEqual(COMError.__doc__, "Raised when a COM method call failed.") + + ex = COMError(-1, "text", ("details",)) + self.assertEqual(ex.hresult, -1) + self.assertEqual(ex.text, "text") + self.assertEqual(ex.details, ("details",)) + class Structures(unittest.TestCase): def test_struct_by_value(self): diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py index e1d0eb7..c7c61ef 100644 --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -1491,6 +1491,18 @@ counter to RFC 2822, there's no separating newline here self.failUnless(isinstance(bad.defects[0], Errors.StartBoundaryNotFoundDefect)) + def test_first_line_is_continuation_header(self): + eq = self.assertEqual + m = ' Line 1\nLine 2\nLine 3' + msg = email.message_from_string(m) + eq(msg.keys(), []) + eq(msg.get_payload(), 'Line 2\nLine 3') + eq(len(msg.defects), 1) + self.failUnless(isinstance(msg.defects[0], + Errors.FirstHeaderLineIsContinuationDefect)) + eq(msg.defects[0].line, ' Line 1\n') + + # Test RFC 2047 header encoding and decoding diff --git a/Lib/email/test/test_email_renamed.py b/Lib/email/test/test_email_renamed.py index 4ce2184..4688a1b 100644 --- a/Lib/email/test/test_email_renamed.py +++ b/Lib/email/test/test_email_renamed.py @@ -1489,6 +1489,17 @@ counter to RFC 2822, there's no separating newline here self.failUnless(isinstance(bad.defects[0], errors.StartBoundaryNotFoundDefect)) + def test_first_line_is_continuation_header(self): + eq = self.assertEqual + m = ' Line 1\nLine 2\nLine 3' + msg = email.message_from_string(m) + eq(msg.keys(), []) + eq(msg.get_payload(), 'Line 2\nLine 3') + eq(len(msg.defects), 1) + self.failUnless(isinstance(msg.defects[0], + errors.FirstHeaderLineIsContinuationDefect)) + eq(msg.defects[0].line, ' Line 1\n') + # Test RFC 2047 header encoding and decoding diff --git a/Lib/idlelib/FileList.py b/Lib/idlelib/FileList.py index 9c6fafe..860dbae 100644 --- a/Lib/idlelib/FileList.py +++ b/Lib/idlelib/FileList.py @@ -44,7 +44,7 @@ class FileList: return self.EditorWindow(self, filename) def close_all_callback(self, event): - for edit in self.inversedict.keys(): + for edit in list(self.inversedict): reply = edit.close() if reply == "cancel": break diff --git a/Lib/idlelib/MultiCall.py b/Lib/idlelib/MultiCall.py index 4311999..f43f83e 100644 --- a/Lib/idlelib/MultiCall.py +++ b/Lib/idlelib/MultiCall.py @@ -105,18 +105,32 @@ class _SimpleBinder: # _state_subsets gives for each combination of modifiers, or *state*, # a list of the states which are a subset of it. This list is ordered by the # number of modifiers is the state - the most specific state comes first. -# XXX rewrite without overusing functional primitives :-) _states = range(1 << len(_modifiers)) _state_names = [''.join(m[0]+'-' for i, m in enumerate(_modifiers) if (1 << i) & s) for s in _states] -_state_subsets = map(lambda i: filter(lambda j: not (j & (~i)), _states), - _states) -for l in _state_subsets: - l.sort(lambda a, b, nummod = lambda x: len(filter(lambda i: (1<<i) & x, - range(len(_modifiers)))): - nummod(b) - nummod(a)) + +def expand_substates(states): + '''For each item of states return a list containing all combinations of + that item with individual bits reset, sorted by the number of set bits. + ''' + def nbits(n): + "number of bits set in n base 2" + nb = 0 + while n: + n, rem = divmod(n, 2) + nb += rem + return nb + statelist = [] + for state in states: + substates = list(set(state & x for x in states)) + substates.sort(lambda a,b: nbits(b) - nbits(a)) + statelist.append(substates) + return statelist + +_state_subsets = expand_substates(_states) + # _state_codes gives for each state, the portable code to be passed as mc_state _state_codes = [] for s in _states: diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py index 2d69157..f11e609 100644 --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -351,8 +351,6 @@ class ModifiedInterpreter(InteractiveInterpreter): def build_subprocess_arglist(self): w = ['-W' + s for s in sys.warnoptions] - if 1/2 > 0: # account for new division - w.append('-Qnew') # Maybe IDLE is installed and is being accessed via sys.path, # or maybe it's not installed and the idle.py script is being # run from the IDLE source directory. diff --git a/Lib/idlelib/WidgetRedirector.py b/Lib/idlelib/WidgetRedirector.py index 59005b8..459fea7 100644 --- a/Lib/idlelib/WidgetRedirector.py +++ b/Lib/idlelib/WidgetRedirector.py @@ -19,7 +19,7 @@ class WidgetRedirector: self.widget._w) def close(self): - for name in self.dict.keys(): + for name in list(self.dict.keys()): self.unregister(name) widget = self.widget; del self.widget orig = self.orig; del self.orig diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py index f56b4d4..636299d 100644 --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1 +1 @@ -IDLE_VERSION = "2.6a0" +IDLE_VERSION = "3.0x" diff --git a/Lib/idlelib/macosxSupport.py b/Lib/idlelib/macosxSupport.py index ad61fff..222abfc 100644 --- a/Lib/idlelib/macosxSupport.py +++ b/Lib/idlelib/macosxSupport.py @@ -3,6 +3,7 @@ A number of function that enhance IDLE on MacOSX when it used as a normal GUI application (as opposed to an X11 application). """ import sys +import Tkinter def runningAsOSXApp(): """ Returns True iff running from the IDLE.app bundle on OSX """ @@ -23,7 +24,11 @@ def addOpenEventSupport(root, flist): root.createcommand("::tk::mac::OpenDocument", doOpenFile) def hideTkConsole(root): - root.tk.call('console', 'hide') + try: + root.tk.call('console', 'hide') + except Tkinter.TclError: + # Some versions of the Tk framework don't have a console object + pass def overrideRootMenu(root, flist): """ @@ -75,32 +80,40 @@ def overrideRootMenu(root, flist): import configDialog configDialog.ConfigDialog(root, 'Settings') + root.bind('<<about-idle>>', about_dialog) root.bind('<<open-config-dialog>>', config_dialog) if flist: root.bind('<<close-all-windows>>', flist.close_all_callback) - for mname, entrylist in Bindings.menudefs: - menu = menudict.get(mname) - if not menu: - continue - for entry in entrylist: - if not entry: - menu.add_separator() + + ###check if Tk version >= 8.4.14; if so, use hard-coded showprefs binding + tkversion = root.tk.eval('info patchlevel') + if tkversion >= '8.4.14': + Bindings.menudefs[0] = ('application', [ + ('About IDLE', '<<about-idle>>'), + None, + ]) + root.createcommand('::tk::mac::ShowPreferences', config_dialog) + else: + for mname, entrylist in Bindings.menudefs: + menu = menudict.get(mname) + if not menu: + continue else: - label, eventname = entry - underline, label = prepstr(label) - accelerator = get_accelerator(Bindings.default_keydefs, + for entry in entrylist: + if not entry: + menu.add_separator() + else: + label, eventname = entry + underline, label = prepstr(label) + accelerator = get_accelerator(Bindings.default_keydefs, eventname) - def command(text=root, eventname=eventname): - text.event_generate(eventname) - menu.add_command(label=label, underline=underline, + def command(text=root, eventname=eventname): + text.event_generate(eventname) + menu.add_command(label=label, underline=underline, command=command, accelerator=accelerator) - - - - def setupApp(root, flist): """ Perform setup for the OSX application bundle. diff --git a/Lib/inspect.py b/Lib/inspect.py index b5e9ff2..45db8ee 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -690,7 +690,6 @@ def _getfullargs(co): if not iscode(co): raise TypeError('arg is not a code object') - code = co.co_code nargs = co.co_argcount names = co.co_varnames nkwargs = co.co_kwonlyargcount diff --git a/Lib/lib-tk/Tkinter.py b/Lib/lib-tk/Tkinter.py index 1e4d771..ef588e8 100644 --- a/Lib/lib-tk/Tkinter.py +++ b/Lib/lib-tk/Tkinter.py @@ -1680,7 +1680,7 @@ class Tk(Misc, Wm): def destroy(self): """Destroy this and all descendants widgets. This will end the application of this Tcl interpreter.""" - for c in self.children.values(): c.destroy() + for c in list(self.children.values()): c.destroy() self.tk.call('destroy', self._w) Misc.destroy(self) global _default_root diff --git a/Lib/mailbox.py b/Lib/mailbox.py index b9f4497..fdb118d 100755 --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -107,7 +107,7 @@ class Mailbox: yield value def __iter__(self): - return self.values() + return self.itervalues() def values(self): """Return a list of messages. Memory intensive.""" @@ -456,7 +456,11 @@ class Maildir(Mailbox): """Update table of contents mapping.""" self._toc = {} for subdir in ('new', 'cur'): - for entry in os.listdir(os.path.join(self._path, subdir)): + subdir_path = os.path.join(self._path, subdir) + for entry in os.listdir(subdir_path): + p = os.path.join(subdir_path, entry) + if os.path.isdir(p): + continue uniq = entry.split(self.colon)[0] self._toc[uniq] = os.path.join(subdir, entry) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 8c4b5e5..de7807c 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -335,12 +335,12 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, generate=False, tests = map(removepy, tests) stdtests = STDTESTS[:] - nottests = NOTTESTS[:] + nottests = NOTTESTS.copy() if exclude: for arg in args: if arg in stdtests: stdtests.remove(arg) - nottests[:0] = args + nottests.add(arg) args = [] tests = tests or args or findtests(testdir, stdtests, nottests) if single: @@ -478,14 +478,14 @@ STDTESTS = [ 'test_unittest', 'test_doctest', 'test_doctest2', - ] +] -NOTTESTS = [ +NOTTESTS = { 'test_support', 'test_future1', 'test_future2', 'test_future3', - ] +} def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS): """Return a list of all applicable test modules.""" @@ -818,12 +818,14 @@ def printlist(x, width=70, indent=4): # test_timeout # Controlled by test_timeout.skip_expected. Requires the network # resource and a socket module. +# +# Tests that are expected to be skipped everywhere except on one platform +# are also handled separately. _expectations = { 'win32': """ test__locale - test_applesingle test_bsddb3 test_commands test_crypt @@ -836,9 +838,7 @@ _expectations = { test_grp test_ioctl test_largefile - test_linuxaudiodev test_mhlib - test_nis test_openpty test_ossaudiodev test_poll @@ -847,24 +847,16 @@ _expectations = { test_pwd test_resource test_signal - test_sunaudiodev test_threadsignals test_wait3 test_wait4 """, 'linux2': """ - test_applesingle test_curses test_dl test_largefile - test_linuxaudiodev - test_nis - test_ntpath test_ossaudiodev - test_sqlite - test_startfile - test_sunaudiodev """, 'mac': """ @@ -882,11 +874,8 @@ _expectations = { test_grp test_ioctl test_largefile - test_linuxaudiodev test_locale test_mmap - test_nis - test_ntpath test_openpty test_ossaudiodev test_poll @@ -896,69 +885,45 @@ _expectations = { test_pwd test_resource test_signal - test_sqlite - test_startfile - test_sunaudiodev test_sundry test_tarfile """, 'unixware7': """ - test_applesingle test_bsddb test_dl test_largefile - test_linuxaudiodev test_minidom - test_nis - test_ntpath test_openpty test_pyexpat test_sax - test_startfile - test_sqlite - test_sunaudiodev test_sundry """, 'openunix8': """ - test_applesingle test_bsddb test_dl test_largefile - test_linuxaudiodev test_minidom - test_nis - test_ntpath test_openpty test_pyexpat test_sax - test_sqlite - test_startfile - test_sunaudiodev test_sundry """, 'sco_sv3': """ - test_applesingle test_asynchat test_bsddb test_dl test_fork1 test_gettext test_largefile - test_linuxaudiodev test_locale test_minidom - test_nis - test_ntpath test_openpty test_pyexpat test_queue test_sax - test_sqlite - test_startfile - test_sunaudiodev test_sundry test_thread test_threaded_import @@ -967,7 +932,6 @@ _expectations = { """, 'riscos': """ - test_applesingle test_asynchat test_atexit test_bsddb @@ -981,18 +945,12 @@ _expectations = { test_gdbm test_grp test_largefile - test_linuxaudiodev test_locale test_mmap - test_nis - test_ntpath test_openpty test_poll test_pty test_pwd - test_sqlite - test_startfile - test_sunaudiodev test_sundry test_thread test_threaded_import @@ -1001,209 +959,135 @@ _expectations = { """, 'darwin': """ + test__locale + test_bsddb + test_bsddb3 + test_curses test_gdbm test_largefile - test_linuxaudiodev test_locale - test_nis test_ossaudiodev - test_startfile - test_sunaudiodev + test_poll """, 'sunos5': """ - test_applesingle test_bsddb test_curses test_dbm test_gdbm test_gzip - test_linuxaudiodev test_openpty - test_sqlite - test_startfile test_zipfile test_zlib """, 'hp-ux11': """ - test_applesingle test_bsddb test_curses test_dl test_gdbm test_gzip test_largefile - test_linuxaudiodev test_locale test_minidom - test_nis - test_ntpath test_openpty test_pyexpat test_sax - test_sqlite - test_startfile - test_sunaudiodev test_zipfile test_zlib """, 'atheos': """ - test_applesingle test_curses test_dl test_gdbm test_largefile - test_linuxaudiodev test_locale test_mhlib test_mmap - test_nis test_poll test_resource - test_sqlite - test_startfile - test_sunaudiodev """, 'cygwin': """ - test_applesingle test_bsddb3 test_curses test_dbm test_ioctl test_largefile - test_linuxaudiodev test_locale - test_nis test_ossaudiodev test_socketserver - test_sqlite - test_sunaudiodev """, 'os2emx': """ - test_applesingle test_audioop test_bsddb3 test_commands test_curses test_dl test_largefile - test_linuxaudiodev test_mhlib test_mmap - test_nis test_openpty test_ossaudiodev test_pty test_resource test_signal - test_sqlite - test_startfile - test_sunaudiodev """, 'freebsd4': """ - test_aepack - test_applesingle test_bsddb test_bsddb3 test_gdbm - test_linuxaudiodev test_locale - test_macostools - test_nis test_ossaudiodev test_pep277 - test_plistlib test_pty - test_scriptpackages test_socket_ssl test_socketserver - test_sqlite - test_startfile - test_sunaudiodev test_tcl test_timeout - test_unicode_file test_urllibnet - test_winreg - test_winsound """, 'aix5': """ - test_aepack - test_applesingle test_bsddb test_bsddb3 test_bz2 test_dl test_gdbm test_gzip - test_linuxaudiodev - test_macostools - test_nis test_ossaudiodev - test_sqlite - test_startfile - test_sunaudiodev test_tcl - test_winreg - test_winsound test_zipimport test_zlib """, 'openbsd3': """ - test_aepack - test_applesingle test_bsddb test_bsddb3 test_ctypes test_dl test_gdbm - test_linuxaudiodev test_locale - test_macostools - test_nis test_normalization test_ossaudiodev test_pep277 - test_plistlib - test_scriptpackages test_tcl - test_sqlite - test_startfile - test_sunaudiodev - test_unicode_file - test_winreg - test_winsound """, 'netbsd3': """ - test_aepack - test_applesingle test_bsddb test_bsddb3 test_ctypes test_curses test_dl test_gdbm - test_linuxaudiodev test_locale - test_macostools - test_nis test_ossaudiodev test_pep277 - test_sqlite - test_startfile - test_sunaudiodev test_tcl - test_unicode_file - test_winreg - test_winsound """, } _expectations['freebsd5'] = _expectations['freebsd4'] @@ -1221,6 +1105,9 @@ class _ExpectedSkips: s = _expectations[sys.platform] self.expected = set(s.split()) + # expected to be skipped on every platform, even Linux + self.expected.add('test_linuxaudiodev') + if not os.path.supports_unicode_filenames: self.expected.add('test_pep277') @@ -1232,20 +1119,23 @@ class _ExpectedSkips: if not sys.platform in ("mac", "darwin"): MAC_ONLY = ["test_macostools", "test_aepack", - "test_plistlib", "test_scriptpackages"] + "test_plistlib", "test_scriptpackages", + "test_applesingle"] for skip in MAC_ONLY: self.expected.add(skip) if sys.platform != "win32": + # test_sqlite is only reliable on Windows where the library + # is distributed with Python WIN_ONLY = ["test_unicode_file", "test_winreg", - "test_winsound"] + "test_winsound", "test_startfile", + "test_sqlite"] for skip in WIN_ONLY: self.expected.add(skip) - if sys.platform != 'irix': - IRIX_ONLY =["test_imageop"] - for skip in IRIX_ONLY: - self.expected.add(skip) + if sys.platform != 'sunos5': + self.expected.add('test_sunaudiodev') + self.expected.add('test_nis') self.valid = True diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py new file mode 100644 index 0000000..7602b9f --- /dev/null +++ b/Lib/test/test_asyncore.py @@ -0,0 +1,406 @@ +import asyncore +import unittest +import select +import os +import socket +import threading +import sys +import time + +from test import test_support +from test.test_support import TESTFN, run_unittest, unlink +from StringIO import StringIO + +HOST = "127.0.0.1" +PORT = 54329 + +class dummysocket: + def __init__(self): + self.closed = False + + def close(self): + self.closed = True + + def fileno(self): + return 42 + +class dummychannel: + def __init__(self): + self.socket = dummysocket() + +class exitingdummy: + def __init__(self): + pass + + def handle_read_event(self): + raise asyncore.ExitNow() + + handle_write_event = handle_read_event + handle_expt_event = handle_read_event + +class crashingdummy: + def __init__(self): + self.error_handled = False + + def handle_read_event(self): + raise Exception() + + handle_write_event = handle_read_event + handle_expt_event = handle_read_event + + def handle_error(self): + self.error_handled = True + +# used when testing senders; just collects what it gets until newline is sent +def capture_server(evt, buf): + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.settimeout(3) + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serv.bind(("", PORT)) + serv.listen(5) + try: + conn, addr = serv.accept() + except socket.timeout: + pass + else: + n = 200 + while n > 0: + data = conn.recv(10) + # keep everything except for the newline terminator + buf.write(data.replace('\n', '')) + if '\n' in data: + break + n -= 1 + time.sleep(0.01) + + conn.close() + finally: + serv.close() + evt.set() + + +class HelperFunctionTests(unittest.TestCase): + def test_readwriteexc(self): + # Check exception handling behavior of read, write and _exception + + # check that ExitNow exceptions in the object handler method + # bubbles all the way up through asyncore read/write/_exception calls + tr1 = exitingdummy() + self.assertRaises(asyncore.ExitNow, asyncore.read, tr1) + self.assertRaises(asyncore.ExitNow, asyncore.write, tr1) + self.assertRaises(asyncore.ExitNow, asyncore._exception, tr1) + + # check that an exception other than ExitNow in the object handler + # method causes the handle_error method to get called + tr2 = crashingdummy() + asyncore.read(tr2) + self.assertEqual(tr2.error_handled, True) + + tr2 = crashingdummy() + asyncore.write(tr2) + self.assertEqual(tr2.error_handled, True) + + tr2 = crashingdummy() + asyncore._exception(tr2) + self.assertEqual(tr2.error_handled, True) + +## Commented out these tests because test a non-documented function +## (which is actually public, why it's not documented?). Anyway, the +## tests *and* the function uses constants in the select module that +## are not present in Windows systems (see this thread: +## http://mail.python.org/pipermail/python-list/2001-October/109973.html) +## Note even that these constants are mentioned in the select +## documentation, as a parameter of "poll" method "register", but are +## not explicit declared as constants of the module. +## . Facundo Batista +## +## def test_readwrite(self): +## # Check that correct methods are called by readwrite() +## +## class testobj: +## def __init__(self): +## self.read = False +## self.write = False +## self.expt = False +## +## def handle_read_event(self): +## self.read = True +## +## def handle_write_event(self): +## self.write = True +## +## def handle_expt_event(self): +## self.expt = True +## +## def handle_error(self): +## self.error_handled = True +## +## for flag in (select.POLLIN, select.POLLPRI): +## tobj = testobj() +## self.assertEqual(tobj.read, False) +## asyncore.readwrite(tobj, flag) +## self.assertEqual(tobj.read, True) +## +## # check that ExitNow exceptions in the object handler method +## # bubbles all the way up through asyncore readwrite call +## tr1 = exitingdummy() +## self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag) +## +## # check that an exception other than ExitNow in the object handler +## # method causes the handle_error method to get called +## tr2 = crashingdummy() +## asyncore.readwrite(tr2, flag) +## self.assertEqual(tr2.error_handled, True) +## +## tobj = testobj() +## self.assertEqual(tobj.write, False) +## asyncore.readwrite(tobj, select.POLLOUT) +## self.assertEqual(tobj.write, True) +## +## # check that ExitNow exceptions in the object handler method +## # bubbles all the way up through asyncore readwrite call +## tr1 = exitingdummy() +## self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, +## select.POLLOUT) +## +## # check that an exception other than ExitNow in the object handler +## # method causes the handle_error method to get called +## tr2 = crashingdummy() +## asyncore.readwrite(tr2, select.POLLOUT) +## self.assertEqual(tr2.error_handled, True) +## +## for flag in (select.POLLERR, select.POLLHUP, select.POLLNVAL): +## tobj = testobj() +## self.assertEqual(tobj.expt, False) +## asyncore.readwrite(tobj, flag) +## self.assertEqual(tobj.expt, True) +## +## # check that ExitNow exceptions in the object handler method +## # bubbles all the way up through asyncore readwrite calls +## tr1 = exitingdummy() +## self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag) +## +## # check that an exception other than ExitNow in the object handler +## # method causes the handle_error method to get called +## tr2 = crashingdummy() +## asyncore.readwrite(tr2, flag) +## self.assertEqual(tr2.error_handled, True) + + def test_closeall(self): + self.closeall_check(False) + + def test_closeall_default(self): + self.closeall_check(True) + + def closeall_check(self, usedefault): + # Check that close_all() closes everything in a given map + + l = [] + testmap = {} + for i in range(10): + c = dummychannel() + l.append(c) + self.assertEqual(c.socket.closed, False) + testmap[i] = c + + if usedefault: + socketmap = asyncore.socket_map + try: + asyncore.socket_map = testmap + asyncore.close_all() + finally: + testmap, asyncore.socket_map = asyncore.socket_map, socketmap + else: + asyncore.close_all(testmap) + + self.assertEqual(len(testmap), 0) + + for c in l: + self.assertEqual(c.socket.closed, True) + + def test_compact_traceback(self): + try: + raise Exception("I don't like spam!") + except: + real_t, real_v, real_tb = sys.exc_info() + r = asyncore.compact_traceback() + else: + self.fail("Expected exception") + + (f, function, line), t, v, info = r + self.assertEqual(os.path.split(f)[-1], 'test_asyncore.py') + self.assertEqual(function, 'test_compact_traceback') + self.assertEqual(t, real_t) + self.assertEqual(v, real_v) + self.assertEqual(info, '[%s|%s|%s]' % (f, function, line)) + + +class DispatcherTests(unittest.TestCase): + def setUp(self): + pass + + def tearDown(self): + asyncore.close_all() + + def test_basic(self): + d = asyncore.dispatcher() + self.assertEqual(d.readable(), True) + self.assertEqual(d.writable(), True) + + def test_repr(self): + d = asyncore.dispatcher() + self.assertEqual(repr(d), '<asyncore.dispatcher at %#x>' % id(d)) + + def test_log(self): + d = asyncore.dispatcher() + + # capture output of dispatcher.log() (to stderr) + fp = StringIO() + stderr = sys.stderr + l1 = "Lovely spam! Wonderful spam!" + l2 = "I don't like spam!" + try: + sys.stderr = fp + d.log(l1) + d.log(l2) + finally: + sys.stderr = stderr + + lines = fp.getvalue().splitlines() + self.assertEquals(lines, ['log: %s' % l1, 'log: %s' % l2]) + + def test_log_info(self): + d = asyncore.dispatcher() + + # capture output of dispatcher.log_info() (to stdout via print) + fp = StringIO() + stdout = sys.stdout + l1 = "Have you got anything without spam?" + l2 = "Why can't she have egg bacon spam and sausage?" + l3 = "THAT'S got spam in it!" + try: + sys.stdout = fp + d.log_info(l1, 'EGGS') + d.log_info(l2) + d.log_info(l3, 'SPAM') + finally: + sys.stdout = stdout + + lines = fp.getvalue().splitlines() + if __debug__: + expected = ['EGGS: %s' % l1, 'info: %s' % l2, 'SPAM: %s' % l3] + else: + expected = ['EGGS: %s' % l1, 'SPAM: %s' % l3] + + self.assertEquals(lines, expected) + + def test_unhandled(self): + d = asyncore.dispatcher() + + # capture output of dispatcher.log_info() (to stdout via print) + fp = StringIO() + stdout = sys.stdout + try: + sys.stdout = fp + d.handle_expt() + d.handle_read() + d.handle_write() + d.handle_connect() + d.handle_accept() + finally: + sys.stdout = stdout + + lines = fp.getvalue().splitlines() + expected = ['warning: unhandled exception', + 'warning: unhandled read event', + 'warning: unhandled write event', + 'warning: unhandled connect event', + 'warning: unhandled accept event'] + self.assertEquals(lines, expected) + + + +class dispatcherwithsend_noread(asyncore.dispatcher_with_send): + def readable(self): + return False + + def handle_connect(self): + pass + +class DispatcherWithSendTests(unittest.TestCase): + usepoll = False + + def setUp(self): + pass + + def tearDown(self): + asyncore.close_all() + + def test_send(self): + self.evt = threading.Event() + cap = StringIO() + threading.Thread(target=capture_server, args=(self.evt,cap)).start() + time.sleep(1) # Give server time to initialize + + data = "Suppose there isn't a 16-ton weight?"*5 + d = dispatcherwithsend_noread() + d.create_socket(socket.AF_INET, socket.SOCK_STREAM) + d.connect((HOST, PORT)) + d.send(data) + d.send('\n') + + n = 1000 + while d.out_buffer and n > 0: + asyncore.poll() + n -= 1 + + self.evt.wait() + + self.assertEqual(cap.getvalue(), data) + + +class DispatcherWithSendTests_UsePoll(DispatcherWithSendTests): + usepoll = True + +if hasattr(asyncore, 'file_wrapper'): + class FileWrapperTest(unittest.TestCase): + def setUp(self): + self.d = "It's not dead, it's sleeping!" + file(TESTFN, 'w').write(self.d) + + def tearDown(self): + unlink(TESTFN) + + def test_recv(self): + fd = os.open(TESTFN, os.O_RDONLY) + w = asyncore.file_wrapper(fd) + + self.assertEqual(w.fd, fd) + self.assertEqual(w.fileno(), fd) + self.assertEqual(w.recv(13), "It's not dead") + self.assertEqual(w.read(6), ", it's") + w.close() + self.assertRaises(OSError, w.read, 1) + + def test_send(self): + d1 = "Come again?" + d2 = "I want to buy some cheese." + fd = os.open(TESTFN, os.O_WRONLY | os.O_APPEND) + w = asyncore.file_wrapper(fd) + + w.write(d1) + w.send(d2) + w.close() + self.assertEqual(file(TESTFN).read(), self.d + d1 + d2) + + +def test_main(): + tests = [HelperFunctionTests, DispatcherTests, DispatcherWithSendTests, + DispatcherWithSendTests_UsePoll] + if hasattr(asyncore, 'file_wrapper'): + tests.append(FileWrapperTest) + + run_unittest(*tests) + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 085768d..ade3132 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -9,6 +9,7 @@ maxsize = MAX_Py_ssize_t # test on unicode strings as well overflowok = 1 +overflowrequired = 0 def testformat(formatstr, args, output=None): if verbose: @@ -25,7 +26,11 @@ def testformat(formatstr, args, output=None): if verbose: print('overflow (this is fine)') else: - if output and result != output: + if overflowrequired: + if verbose: + print('no') + print("overflow expected on %r %% %r" % (formatstr, args)) + elif output and result != output: if verbose: print('no') print("%r %% %r == %r != %r" %\ @@ -56,6 +61,14 @@ testboth("%#.*g", (110, -1.e+100/3.)) # test some ridiculously large precision, expect overflow testboth('%12.*f', (123456, 1.0)) +# check for internal overflow validation on length of precision +overflowrequired = 1 +testboth("%#.*g", (110, -1.e+100/3.)) +testboth("%#.*G", (110, -1.e+100/3.)) +testboth("%#.*f", (110, -1.e+100/3.)) +testboth("%#.*F", (110, -1.e+100/3.)) +overflowrequired = 0 + # Formatting of long integers. Overflow is not ok overflowok = 0 testboth("%x", 10, "a") diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 8f45382..bfc77fe 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -697,6 +697,20 @@ class GrammarTests(unittest.TestCase): def meth2(self, arg): pass def meth3(self, a1, a2): pass + # decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE + # decorators: decorator+ + # decorated: decorators (classdef | funcdef) + def class_decorator(x): return x + @class_decorator + class G: pass + + def testDictcomps(self): + # dictorsetmaker: ( (test ':' test (comp_for | + # (',' test ':' test)* [','])) | + # (test (comp_for | (',' test)* [','])) ) + nums = [1, 2, 3] + self.assertEqual({i:i+1 for i in nums}, {1: 2, 2: 3, 3: 4}) + def testListcomps(self): # list comprehension tests nums = [1, 2, 3, 4, 5] diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py index 9d50225..e5930d8 100644 --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -427,8 +427,8 @@ class TestMailboxSuperclass(TestBase): self.assertRaises(NotImplementedError, lambda: box.__setitem__('', '')) self.assertRaises(NotImplementedError, lambda: box.keys()) self.assertRaises(NotImplementedError, lambda: box.keys()) - self.assertRaises(NotImplementedError, lambda: box.values().next()) - self.assertRaises(NotImplementedError, lambda: box.__iter__().next()) + self.assertRaises(NotImplementedError, lambda: box.values().__next__()) + self.assertRaises(NotImplementedError, lambda: box.__iter__().__next__()) self.assertRaises(NotImplementedError, lambda: box.values()) self.assertRaises(NotImplementedError, lambda: box.items().next()) self.assertRaises(NotImplementedError, lambda: box.items()) @@ -679,7 +679,18 @@ class TestMaildir(TestMailbox): folder1_alias = box.get_folder('folder1') self.assert_(folder1_alias._factory is dummy_factory) + def test_directory_in_folder (self): + # Test that mailboxes still work if there's a stray extra directory + # in a folder. + for i in range(10): + self._box.add(mailbox.Message(_sample_message)) + + # Create a stray directory + os.mkdir(os.path.join(self._path, 'cur', 'stray-dir')) + # Check that looping still works with the directory present. + for msg in self._box: + pass class _TestMboxMMDF(TestMailbox): diff --git a/Lib/test/test_parser.py b/Lib/test/test_parser.py index ddb58b5..dbf6a92 100644 --- a/Lib/test/test_parser.py +++ b/Lib/test/test_parser.py @@ -443,6 +443,12 @@ class CompileTestCase(unittest.TestCase): st = parser.suite('1 = 3 + 4') self.assertRaises(SyntaxError, parser.compilest, st) + def test_compile_badunicode(self): + st = parser.suite('a = u"\U12345678"') + self.assertRaises(SyntaxError, parser.compilest, st) + st = parser.suite('a = u"\u1"') + self.assertRaises(SyntaxError, parser.compilest, st) + def test_main(): test_support.run_unittest( RoundtripLegalSyntaxTestCase, diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 99e3047..488e9e2 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -380,6 +380,12 @@ class MockPasswordManager: class OpenerDirectorTests(unittest.TestCase): + def test_add_non_handler(self): + class NonHandler(object): + pass + self.assertRaises(TypeError, + OpenerDirector().add_handler, NonHandler()) + def test_badly_named_methods(self): # test work-around for three methods that accidentally follow the # naming conventions for handler methods diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index 791cca7..0b8a963 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -1,5 +1,7 @@ +import base64 import datetime import sys +import time import unittest import xmlrpclib from test import test_support @@ -18,6 +20,10 @@ alist = [{'astring': 'foo@bar.baz.spam', (2005, 2, 10, 11, 41, 23, 0, 1, -1)), 'datetime3': xmlrpclib.DateTime( datetime.datetime(2005, 2, 10, 11, 41, 23)), + 'datetime4': xmlrpclib.DateTime( + datetime.date(2005, 2, 10)), + 'datetime5': xmlrpclib.DateTime( + datetime.time(11, 41, 23)), }] class XMLRPCTestCase(unittest.TestCase): @@ -94,11 +100,37 @@ class XMLRPCTestCase(unittest.TestCase): def test_dump_bad_dict(self): self.assertRaises(TypeError, xmlrpclib.dumps, ({(1,2,3): 1},)) + def test_dump_recursive_seq(self): + l = [1,2,3] + t = [3,4,5,l] + l.append(t) + self.assertRaises(TypeError, xmlrpclib.dumps, (l,)) + + def test_dump_recursive_dict(self): + d = {'1':1, '2':1} + t = {'3':3, 'd':d} + d['t'] = t + self.assertRaises(TypeError, xmlrpclib.dumps, (d,)) + def test_dump_big_int(self): if sys.maxint > 2**31-1: self.assertRaises(OverflowError, xmlrpclib.dumps, (int(2**34),)) + xmlrpclib.dumps((xmlrpclib.MAXINT, xmlrpclib.MININT)) + self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MAXINT+1,)) + self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MININT-1,)) + + def dummy_write(s): + pass + + m = xmlrpclib.Marshaller() + m.dump_int(xmlrpclib.MAXINT, dummy_write) + m.dump_int(xmlrpclib.MININT, dummy_write) + self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MAXINT+1, dummy_write) + self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MININT-1, dummy_write) + + def test_dump_none(self): value = alist + [None] arg1 = (alist + [None],) @@ -146,8 +178,109 @@ class XMLRPCTestCase(unittest.TestCase): self.assert_(isinstance(items[0][0], str)) self.assert_(isinstance(items[0][1], str)) + +class HelperTestCase(unittest.TestCase): + def test_escape(self): + self.assertEqual(xmlrpclib.escape("a&b"), "a&b") + self.assertEqual(xmlrpclib.escape("a<b"), "a<b") + self.assertEqual(xmlrpclib.escape("a>b"), "a>b") + +class FaultTestCase(unittest.TestCase): + def test_repr(self): + f = xmlrpclib.Fault(42, 'Test Fault') + self.assertEqual(repr(f), "<Fault 42: 'Test Fault'>") + self.assertEqual(repr(f), str(f)) + + def test_dump_fault(self): + f = xmlrpclib.Fault(42, 'Test Fault') + s = xmlrpclib.dumps((f,)) + (newf,), m = xmlrpclib.loads(s) + self.assertEquals(newf, {'faultCode': 42, 'faultString': 'Test Fault'}) + self.assertEquals(m, None) + + s = xmlrpclib.Marshaller().dumps(f) + self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, s) + + +class DateTimeTestCase(unittest.TestCase): + def test_default(self): + t = xmlrpclib.DateTime() + + def test_time(self): + d = 1181399930.036952 + t = xmlrpclib.DateTime(d) + self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", time.localtime(d))) + + def test_time_tuple(self): + d = (2007,6,9,10,38,50,5,160,0) + t = xmlrpclib.DateTime(d) + self.assertEqual(str(t), '20070609T10:38:50') + + def test_time_struct(self): + d = time.localtime(1181399930.036952) + t = xmlrpclib.DateTime(d) + self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", d)) + + def test_datetime_datetime(self): + d = datetime.datetime(2007,1,2,3,4,5) + t = xmlrpclib.DateTime(d) + self.assertEqual(str(t), '20070102T03:04:05') + + def test_datetime_date(self): + d = datetime.date(2007,9,8) + t = xmlrpclib.DateTime(d) + self.assertEqual(str(t), '20070908T00:00:00') + + def test_datetime_time(self): + d = datetime.time(13,17,19) + # allow for date rollover by checking today's or tomorrow's dates + dd1 = datetime.datetime.now().date() + dd2 = dd1 + datetime.timedelta(days=1) + vals = (dd1.strftime('%Y%m%dT13:17:19'), + dd2.strftime('%Y%m%dT13:17:19')) + t = xmlrpclib.DateTime(d) + self.assertEqual(str(t) in vals, True) + + def test_repr(self): + d = datetime.datetime(2007,1,2,3,4,5) + t = xmlrpclib.DateTime(d) + val ="<DateTime '20070102T03:04:05' at %x>" % id(t) + self.assertEqual(repr(t), val) + + def test_decode(self): + d = ' 20070908T07:11:13 ' + t1 = xmlrpclib.DateTime() + t1.decode(d) + tref = xmlrpclib.DateTime(datetime.datetime(2007,9,8,7,11,13)) + self.assertEqual(t1, tref) + + t2 = xmlrpclib._datetime(d) + self.assertEqual(t1, tref) + +class BinaryTestCase(unittest.TestCase): + def test_default(self): + t = xmlrpclib.Binary() + self.assertEqual(str(t), '') + + def test_string(self): + d = '\x01\x02\x03abc123\xff\xfe' + t = xmlrpclib.Binary(d) + self.assertEqual(str(t), d) + + def test_decode(self): + d = '\x01\x02\x03abc123\xff\xfe' + de = base64.encodestring(d) + t1 = xmlrpclib.Binary() + t1.decode(de) + self.assertEqual(str(t1), d) + + t2 = xmlrpclib._binary(de) + self.assertEqual(str(t2), d) + + def test_main(): - test_support.run_unittest(XMLRPCTestCase) + test_support.run_unittest(XMLRPCTestCase, HelperTestCase, + DateTimeTestCase, BinaryTestCase, FaultTestCase) if __name__ == "__main__": diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 197170a..eda6863 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -12,7 +12,7 @@ import test.test_support as support from test.test_support import TESTFN, run_unittest TESTFN2 = TESTFN + "2" -FIXEDTEST_SIZE = 10 +FIXEDTEST_SIZE = 1000 class TestsWithSourceFile(unittest.TestCase): def setUp(self): @@ -232,6 +232,63 @@ class TestsWithSourceFile(unittest.TestCase): self.assertEqual(zipfp.namelist(), ["absolute"]) zipfp.close() + def testAppendToZipFile(self): + # Test appending to an existing zipfile + zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) + zipfp.write(TESTFN, TESTFN) + zipfp.close() + zipfp = zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) + zipfp.writestr("strfile", self.data) + self.assertEqual(zipfp.namelist(), [TESTFN, "strfile"]) + zipfp.close() + + def testAppendToNonZipFile(self): + # Test appending to an existing file that is not a zipfile + # NOTE: this test fails if len(d) < 22 because of the first + # line "fpin.seek(-22, 2)" in _EndRecData + d = 'I am not a ZipFile!'*10 + f = file(TESTFN2, 'wb') + f.write(d) + f.close() + zipfp = zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) + zipfp.write(TESTFN, TESTFN) + zipfp.close() + + f = file(TESTFN2, 'rb') + f.seek(len(d)) + zipfp = zipfile.ZipFile(f, "r") + self.assertEqual(zipfp.namelist(), [TESTFN]) + zipfp.close() + f.close() + + def test_WriteDefaultName(self): + # Check that calling ZipFile.write without arcname specified produces the expected result + zipfp = zipfile.ZipFile(TESTFN2, "w") + zipfp.write(TESTFN) + self.assertEqual(zipfp.read(TESTFN), file(TESTFN).read()) + zipfp.close() + + def test_PerFileCompression(self): + # Check that files within a Zip archive can have different compression options + zipfp = zipfile.ZipFile(TESTFN2, "w") + zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED) + zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED) + sinfo = zipfp.getinfo('storeme') + dinfo = zipfp.getinfo('deflateme') + self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED) + self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED) + zipfp.close() + + def test_WriteToReadonly(self): + # Check that trying to call write() on a readonly ZipFile object + # raises a RuntimeError + zipf = zipfile.ZipFile(TESTFN2, mode="w") + zipf.writestr("somefile.txt", "bogus") + zipf.close() + zipf = zipfile.ZipFile(TESTFN2, mode="r") + self.assertRaises(RuntimeError, zipf.write, TESTFN) + zipf.close() + def tearDown(self): os.remove(TESTFN) os.remove(TESTFN2) @@ -349,7 +406,6 @@ class TestZip64InSmallFiles(unittest.TestCase): self.assertEqual(zipfp.namelist(), ["absolute"]) zipfp.close() - def tearDown(self): zipfile.ZIP64_LIMIT = self._limit os.remove(TESTFN) @@ -420,6 +476,11 @@ class PyZipFileTests(unittest.TestCase): finally: shutil.rmtree(TESTFN2) + def testWriteNonPyfile(self): + zipfp = zipfile.PyZipFile(TemporaryFile(), "w") + file(TESTFN, 'w').write('most definitely not a python file') + self.assertRaises(RuntimeError, zipfp.writepy, TESTFN) + os.remove(TESTFN) class OtherTests(unittest.TestCase): @@ -501,7 +562,56 @@ class OtherTests(unittest.TestCase): # a RuntimeError, and so should calling .testzip. An earlier # version of .testzip would swallow this exception (and any other) # and report that the first file in the archive was corrupt. + self.assertRaises(RuntimeError, zipf.read, "foo.txt") + self.assertRaises(RuntimeError, zipf.open, "foo.txt") self.assertRaises(RuntimeError, zipf.testzip) + self.assertRaises(RuntimeError, zipf.writestr, "bogus.txt", "bogus") + file(TESTFN, 'w').write('zipfile test data') + self.assertRaises(RuntimeError, zipf.write, TESTFN) + + def test_BadConstructorMode(self): + # Check that bad modes passed to ZipFile constructor are caught + self.assertRaises(RuntimeError, zipfile.ZipFile, TESTFN, "q") + + def test_BadOpenMode(self): + # Check that bad modes passed to ZipFile.open are caught + zipf = zipfile.ZipFile(TESTFN, mode="w") + zipf.writestr("foo.txt", "O, for a Muse of Fire!") + zipf.close() + zipf = zipfile.ZipFile(TESTFN, mode="r") + # read the data to make sure the file is there + zipf.read("foo.txt") + self.assertRaises(RuntimeError, zipf.open, "foo.txt", "q") + zipf.close() + + def test_Read0(self): + # Check that calling read(0) on a ZipExtFile object returns an empty + # string and doesn't advance file pointer + zipf = zipfile.ZipFile(TESTFN, mode="w") + zipf.writestr("foo.txt", "O, for a Muse of Fire!") + # read the data to make sure the file is there + f = zipf.open("foo.txt") + for i in range(FIXEDTEST_SIZE): + self.assertEqual(f.read(0), '') + + self.assertEqual(f.read(), "O, for a Muse of Fire!") + zipf.close() + + def test_OpenNonexistentItem(self): + # Check that attempting to call open() for an item that doesn't + # exist in the archive raises a RuntimeError + zipf = zipfile.ZipFile(TESTFN, mode="w") + self.assertRaises(KeyError, zipf.open, "foo.txt", "r") + + def test_BadCompressionMode(self): + # Check that bad compression methods passed to ZipFile.open are caught + self.assertRaises(RuntimeError, zipfile.ZipFile, TESTFN, "w", -1) + + def test_NullByteInFilename(self): + # Check that a filename containing a null byte is properly terminated + zipf = zipfile.ZipFile(TESTFN, mode="w") + zipf.writestr("foo.txt\x00qqq", "O, for a Muse of Fire!") + self.assertEqual(zipf.namelist(), ['foo.txt']) def tearDown(self): support.unlink(TESTFN) diff --git a/Lib/urllib2.py b/Lib/urllib2.py index 9e95fda..9c773fc 100644 --- a/Lib/urllib2.py +++ b/Lib/urllib2.py @@ -293,6 +293,10 @@ class OpenerDirector: self.process_request = {} def add_handler(self, handler): + if not hasattr(handler, "add_parent"): + raise TypeError("expected BaseHandler instance, got %r" % + type(handler)) + added = False for meth in dir(handler): if meth in ["redirect_request", "do_open", "proxy_open"]: diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 4791aea..63551a6 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -574,8 +574,9 @@ class ZipFile: def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False): """Open the ZIP file with mode read "r", write "w" or append "a".""" - self._allowZip64 = allowZip64 - self._didModify = False + if mode not in ("r", "w", "a"): + raise RuntimeError('ZipFile() requires mode "r", "w", or "a"') + if compression == ZIP_STORED: pass elif compression == ZIP_DEFLATED: @@ -584,6 +585,9 @@ class ZipFile: "Compression requires the (missing) zlib module" else: raise RuntimeError, "That compression method is not supported" + + self._allowZip64 = allowZip64 + self._didModify = False self.debug = 0 # Level of printing: 0 through 3 self.NameToInfo = {} # Find file info given name self.filelist = [] # List of ZipInfo instances for archive @@ -729,7 +733,12 @@ class ZipFile: def getinfo(self, name): """Return the instance of ZipInfo given 'name'.""" - return self.NameToInfo[name] + info = self.NameToInfo.get(name) + if info is None: + raise KeyError( + 'There is no item named %r in the archive' % name) + + return info def setpassword(self, pwd): """Set default password for encrypted files.""" @@ -834,6 +843,10 @@ class ZipFile: def write(self, filename, arcname=None, compress_type=None): """Put the bytes from filename into the archive under the name arcname.""" + if not self.fp: + raise RuntimeError( + "Attempt to write to ZIP archive that was already closed") + st = os.stat(filename) mtime = time.localtime(st.st_mtime) date_time = mtime[0:6] @@ -906,6 +919,11 @@ class ZipFile: zinfo.compress_type = self.compression else: zinfo = zinfo_or_arcname + + if not self.fp: + raise RuntimeError( + "Attempt to write to ZIP archive that was already closed") + zinfo.file_size = len(bytes) # Uncompressed size zinfo.header_offset = self.fp.tell() # Start of header bytes self._writecheck(zinfo) diff --git a/Makefile.pre.in b/Makefile.pre.in index 53fa3ce..4ab92ce 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -393,7 +393,7 @@ $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK): \ -compatibility_version $(VERSION) \ -current_version $(VERSION); \ else \ - libtool -o $(LDLIBRARY) -dynamic $(OTHER_LIBTOOL_OPT) $(LIBRARY) \ + /usr/bin/libtool -o $(LDLIBRARY) -dynamic $(OTHER_LIBTOOL_OPT) $(LIBRARY) \ @LIBTOOL_CRUFT@ ;\ fi $(INSTALL) -d -m $(DIRMODE) \ diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 35f087d..0350be3 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4466,11 +4466,6 @@ create_comerror(void) PyObject *s; int status; - ComError = PyErr_NewException("_ctypes.COMError", - NULL, - dict); - if (ComError == NULL) - return -1; while (methods->ml_name) { /* get a wrapper for the built-in function */ PyObject *func = PyCFunction_New(methods, NULL); @@ -4485,13 +4480,24 @@ create_comerror(void) Py_DECREF(meth); ++methods; } - Py_INCREF(ComError); + s = PyString_FromString(comerror_doc); if (s == NULL) return -1; status = PyDict_SetItemString(dict, "__doc__", s); Py_DECREF(s); - return status; + if (status == -1) { + Py_DECREF(dict); + return -1; + } + + ComError = PyErr_NewException("_ctypes.COMError", + NULL, + dict); + if (ComError == NULL) + return -1; + + return 0; } #endif diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index 82f6cc1..5915455 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -264,7 +264,7 @@ ffi_info *AllocFunctionCallback(PyObject *callable, ffi_abi cc; nArgs = PySequence_Size(converters); - p = (ffi_info *)PyMem_Malloc(sizeof(ffi_info) + sizeof(ffi_type) * (nArgs + 1)); + p = (ffi_info *)PyMem_Malloc(sizeof(ffi_info) + sizeof(ffi_type) * (nArgs)); if (p == NULL) { PyErr_NoMemory(); return NULL; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 5df9943..52f6065 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -58,7 +58,7 @@ typedef struct { PyObject *callable; SETFUNC setfunc; ffi_type *restype; - ffi_type *atypes[0]; + ffi_type *atypes[1]; } ffi_info; typedef struct { diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c index fd6f5e2..b4a6e87 100644 --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -457,13 +457,11 @@ StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) if (!prop) { Py_DECREF(pair); - Py_DECREF((PyObject *)stgdict); return -1; } if (-1 == PyDict_SetItem(realdict, name, prop)) { Py_DECREF(prop); Py_DECREF(pair); - Py_DECREF((PyObject *)stgdict); return -1; } Py_DECREF(pair); diff --git a/Objects/stringobject.c b/Objects/stringobject.c index b5abdb6..4e343b2 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -4156,7 +4156,8 @@ formatfloat(char *buf, size_t buflen, int flags, always given), therefore increase the length by one. */ - if ((type == 'g' && buflen <= (size_t)10 + (size_t)prec) || + if (((type == 'g' || type == 'G') && + buflen <= (size_t)10 + (size_t)prec) || (type == 'f' && buflen <= (size_t)53 + (size_t)prec)) { PyErr_SetString(PyExc_OverflowError, "formatted float is too long (precision too large?)"); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 860e38b..5dc3b41 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7935,7 +7935,8 @@ formatfloat(Py_UNICODE *buf, always given), therefore increase the length by one. */ - if ((type == 'g' && buflen <= (size_t)10 + (size_t)prec) || + if (((type == 'g' || type == 'G') && + buflen <= (size_t)10 + (size_t)prec) || (type == 'f' && buflen <= (size_t)53 + (size_t)prec)) { PyErr_SetString(PyExc_OverflowError, "formatted float is too long (precision too large?)"); diff --git a/Python/ast.c b/Python/ast.c index 23df29f..146cd05 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -1271,9 +1271,26 @@ ast_for_atom(struct compiling *c, const node *n) return Name(NEW_IDENTIFIER(ch), Load, LINENO(n), n->n_col_offset, c->c_arena); case STRING: { PyObject *str = parsestrplus(c, n, &bytesmode); - if (!str) + if (!str) { + if (PyErr_ExceptionMatches(PyExc_UnicodeError)){ + PyObject *type, *value, *tback, *errstr; + PyErr_Fetch(&type, &value, &tback); + errstr = ((PyUnicodeErrorObject *)value)->reason; + if (errstr) { + char *s = ""; + char buf[128]; + s = PyString_AsString(errstr); + PyOS_snprintf(buf, sizeof(buf), "(unicode error) %s", s); + ast_error(n, buf); + } else { + ast_error(n, "(unicode error) unknown error"); + } + Py_DECREF(type); + Py_DECREF(value); + Py_XDECREF(tback); + } return NULL; - + } PyArena_AddPyObject(c->c_arena, str); if (bytesmode) return Bytes(str, LINENO(n), n->n_col_offset, c->c_arena); |